簡體   English   中英

Scala RDD按范圍計算

[英]Scala RDD count by range

我需要“提取”Iterable [MyObject]中包含的一些數據(它是groupBy之前的RDD [MyObject])。

我的初始RDD [MyObject]:

|-----------|---------|----------|
| startCity | endCity | Customer |
|-----------|---------|----------|
| Paris     | London  | ID | Age |
|           |         |----|-----|
|           |         |  1 | 1   |
|           |         |----|-----|
|           |         |  2 | 1   |
|           |         |----|-----|
|           |         |  3 | 50  |
|-----------|---------|----------|
| Paris     | London  | ID | Age |
|           |         |----|-----|
|           |         |  5 | 40  |
|           |         |----|-----|
|           |         |  6 | 41  |
|           |         |----|-----|
|           |         |  7 | 2   |
|-----------|---------|----|-----|
| New-York  | Paris   | ID | Age |
|           |         |----|-----|
|           |         |  9 | 15  |
|           |         |----|-----|
|           |         |  10| 16  |
|           |         |----|-----|
|           |         |  11| 46  |
|-----------|---------|----|-----|
| New-York  | Paris   | ID | Age |
|           |         |----|-----|
|           |         |  13| 7   |
|           |         |----|-----|
|           |         |  14| 9   |
|           |         |----|-----|
|           |         |  15| 60  |
|-----------|---------|----|-----|
| Barcelona | London  | ID | Age |
|           |         |----|-----|
|           |         |  17| 66  |
|           |         |----|-----|
|           |         |  18| 53  |
|           |         |----|-----|
|           |         |  19| 11  |
|-----------|---------|----|-----|

我需要按年齡范圍和groupBy startCity - endCity來計算它們

最終結果應該是:

|-----------|---------|-------------|
| startCity | endCity | Customer    |
|-----------|---------|-------------|
| Paris     | London  | Range| Count|
|           |         |------|------|
|           |         |0-2   | 3    |
|           |         |------|------|
|           |         |3-18  | 0    |
|           |         |------|------|
|           |         |19-99 | 3    |
|-----------|---------|-------------|
| New-York  | Paris   | Range| Count|
|           |         |------|------|
|           |         |0-2   | 0    |
|           |         |------|------|
|           |         |3-18  | 3    |
|           |         |------|------|
|           |         |19-99 | 2    |
|-----------|---------|-------------|
| Barcelona | London  | Range| Count|
|           |         |------|------|
|           |         |0-2   | 0    |
|           |         |------|------|
|           |         |3-18  | 1    |
|           |         |------|------|
|           |         |19-99 | 2    |
|-----------|---------|-------------|

目前我正在通過計數3次相同的數據(第一次0-2范圍,然后10-20,然后21-99)。

喜歡 :

Iterable[MyObject] ite

ite.count(x => x.age match {
    case Some(age) => { age >= 0 && age < 2 }
}

它的工作原理是給我一個Integer,但根本沒有效率我覺得因為我需要多次計算,請問最好的方法是什么?

謝謝

編輯 :Customer對象是一個案例類

def computeRange(age : Int) = 
    if(age<=2)
        "0-2"
    else if(age<=10)
        "2-10"
    // etc, you get the idea

然后,使用case class MyObject(id : String, age : Int)的RDD case class MyObject(id : String, age : Int)

rdd
   .map(x=> computeRange(x.age) -> 1)
   .reduceByKey(_+_)

編輯:如果你需要按某些列分組,你可以這樣做,前提是你有一個RDD [(SomeColumns,Iterable [MyObject])]。 以下幾行將為您提供一個地圖,將每個“范圍”與其出現次數相關聯。

def computeMapOfOccurances(list : Iterable[MyObject]) : Map[String, Int] =
    list
        .map(_.age)
        .map(computeRange)
        .groupBy(x=>x)
        .mapValues(_.size)

val result1 = rdd
    .mapValues( computeMapOfOccurances(_))

如果您需要展平數據,可以寫:

val result2 = result1
    .flatMapValues(_.toSeq)    

假設您將Customer[Object]作為case class ,如下所示

case class Customer(ID: Int, Age: Int)

你的RDD[MyObject]是一個case classrdd ,如下所示

case class MyObject(startCity: String, endCity: String, customer: List[Customer])

因此,使用上面的case class你應該有輸入(你有表格格式),如下所示

MyObject(Paris,London,List(Customer(1,1), Customer(2,1), Customer(3,50)))
MyObject(Paris,London,List(Customer(5,40), Customer(6,41), Customer(7,2)))
MyObject(New-York,Paris,List(Customer(9,15), Customer(10,16), Customer(11,46)))
MyObject(New-York,Paris,List(Customer(13,7), Customer(14,9), Customer(15,60)))
MyObject(Barcelona,London,List(Customer(17,66), Customer(18,53), Customer(19,11)))

並且你還提到在分組后你有Iterable[MyObject] ,相當於下面的步驟

val groupedRDD = rdd.groupBy(myobject => (myobject.startCity, myobject.endCity))   //groupedRDD: org.apache.spark.rdd.RDD[((String, String), Iterable[MyObject])] = ShuffledRDD[2] at groupBy at worksheetTest.sc:23

因此,您要做的下一步是使用mapValues迭代Iterable[MyObject] ,然后計算屬於每個范圍的age ,最后轉換為您需要的輸出,如下所示

val finalResult = groupedRDD.mapValues(x => {
  val rangeAge = Map("0-2" -> 0, "3-18" -> 0, "19-99" -> 0)
  val list = x.flatMap(y => y.customer.map(z => z.Age)).toList
  updateCounts(list, rangeAge).map(x => CustomerOut(x._1, x._2)).toList
})

其中updateCounts遞歸函數

def updateCounts(ageList: List[Int], map: Map[String, Int]) : Map[String, Int] = ageList match{
  case head :: tail => if(head >= 0 && head < 3) {
    updateCounts(tail, map ++ Map("0-2" -> (map("0-2")+1)))
  } else if(head >= 3 && head < 19) {
    updateCounts(tail, map ++ Map("3-18" -> (map("3-18")+1)))
  } else updateCounts(tail, map ++ Map("19-99" -> (map("19-99")+1)))
  case Nil => map
}

CustomerOut是另一個case class

case class CustomerOut(Range: String, Count: Int)

所以finalResult如下

((Barcelona,London),List(CustomerOut(0-2,0), CustomerOut(3-18,1), CustomerOut(19-99,2)))
((New-York,Paris),List(CustomerOut(0-2,0), CustomerOut(3-18,4), CustomerOut(19-99,2)))
((Paris,London),List(CustomerOut(0-2,3), CustomerOut(3-18,0), CustomerOut(19-99,3)))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM