spark中使用groupByKey进行分组排序

任务需求:已知RDD[(query:String, item_id:String, imp:Int, clk:Int)],要求找到每个query对应的点击最多的前2个item_id,即:按照query分组,并按照clk降序排序,每组取前两个。

例如:

(连衣裙,1234,  22,  13)

(牛仔裤,2768,  34,  7)

(连衣裙,1673,45,  9)

(衬衣,3468, 67,  12)

(牛仔裤,2754, 68, 20)

(连衣裙,1976,93,  29)

希望得到:

(连衣裙,1976,93,  29)

(连衣裙,1234,  22,  13)

(牛仔裤,2754, 68, 20)

(牛仔裤,2768,  34,  7)

(衬衣,3468, 67,  12)

先看一个错误的版本:

val topItem_set= data_set.map(ele => (ele._1, (ele._2, ele._3, ele._4))).groupByKey()
  .map(line => {
      val topItem = line._2.toArray.sortBy(_._3)(Ordering[Int].reverse).
        take(2)
      (line._1, topItem(0))
  })

我们把query作为key,其余放到一起,groupByKey后(map之前),类型为:RDD[(String, Iterable[(String, Int, Int)])],根据query分组再map,line._2.toArray把Iterable转为Array,sortBy(_._3)是按最后一个Int即clk排序,(Ordering[Int].reverse)表示从大到小(sortBy默认从小到大,注意这里的sortBy是Array的成员函数而不是rdd的sortBy,用法比较不同),take(2)是取前2个,然后返回(query,  item_id)。跑一下上面的过程。

你会发现,返回结果只有3项:

(连衣裙,1976,93,  29)

(牛仔裤,2754, 68, 20)

(衬衣,3468, 67,  12)

为什么呢?因为这里要用flatMap而不是Map:

val topItem_set= data_set.map(ele => (ele._1, (ele._2, ele._3, ele._4))).groupByKey()
  .flatMap(line => {
      val topItem = line._2.toArray.sortBy(_._3)(Ordering[Int].reverse).
        take(2)
      topItem.map(line._1,_.1)
  })

为什么呢?GroupByKey后,类型为RDD[(String, Iterable[(String, Int, Int)])],如果用map,那每一个key对应的一个Iterable变量,相当于一条数据,map后的结果自然还是一条。但flatMap,相当于map+flat操作,这才是我们真正的需要的形式。

你可能感兴趣的:(spark)