如何在spark中检索具有最小值的记录?

时间:2016-02-23 04:48:53

标签: scala apache-spark

假设我有这样的RDD - > (String,Date,Int)

[("sam", 02-25-2016, 2), ("sam",02-14-2016, 4), ("pam",03-16-2016, 1), ("pam",02-16-2016, 5)]

我希望将其转换为这样的列表 - >

[("sam", 02-14-2016, 4), ("pam",02-16-2016, 5)]

其中value是记录,其中每个键的日期为分钟。 这样做的最佳方式是什么?

1 个答案:

答案 0 :(得分:4)

我认为,由于您将问题标记为与spark相关,因此您指的是RDD而不是列表。

将记录转换为2元组,使用键作为第一个元素将允许您使用reduceByKey方法,如下所示:

rdd
  .map(t => (t._1, (t._2, t._3))
  .reduceByKey((a, b) => if (a._1 < b._1) a else b)
  .map(t => (t._1, t._2._1, t._2._2))

或者,为清晰起见使用模式匹配: (我总是发现元组的_ *访问器有点让人难以理解)

rdd
  .map {case (name, date, value) => (name, (date, value))}
  .reduceByKey((a, b) => (a, b) match {
     case ((aDate, aVal), (bDate, bVal)) => 
       if (aDate < bDate) a else b
  })
  .map {case (name, (date, value)) => (name, date, value)}

a._1 < b._1替换为适合您正在使用的日期类型的任何比较。

请参阅http://spark.apache.org/docs/latest/programming-guide.html#working-with-key-value-pairs以获取有关reduceByKey的文档,以及您可以使用spark中的键/值对执行的其他操作

如果您实际上希望使用普通的旧scala List执行此操作,则以下操作可以:

list
  .groupBy(_._1)
  .mapValues(l => l.reduce((a, b) => if(a._2 < b._2) a else b))
  .values
  .toList

为清晰起见,模式再次匹配版本:

list
  .groupBy {case (name, date, value) => name}
  .mapValues(l => l.reduce((a, b) => (a,b) match {
    case ((aName, aDate, aValue), (bName, bDate, bValue)) => 
      if(aDate < bDate) a else b
  }))
  .values
  .toList