如何从scala中的RDD中获取最早的时间戳日期

时间:2017-02-16 08:43:48

标签: scala apache-spark mapreduce

我有一个类似于((String, String), TimeStamp)的RDD。我有大量的记录,我想为每个键选择 具有最新TimeStamp值的记录。我已经尝试了以下代码,仍然在努力解决这个问题。有人可以帮我这么做吗?

我尝试下面的代码是错误的,并且不能正常工作

val context = sparkSession.read.format("jdbc")
  .option("driver", "com.mysql.jdbc.Driver")
  .option("url", url)
  .option("dbtable", "student_risk")
  .option("user", "user")
  .option("password", "password")
  .load()
context.cache();

val studentRDD = context.rdd.map(r => ((r.getString(r.fieldIndex("course_id")), r.getString(r.fieldIndex("student_id"))), r.getTimestamp(r.fieldIndex("risk_date_time"))))
val filteredRDD = studentRDD.collect().map(z => (z._1, z._2)).reduce((x, y) => (x._2.compareTo(y._2)))

2 个答案:

答案 0 :(得分:6)

直接在DataFrame上进行操作很简单(在这里奇怪地命名为context):

val result = context
  .groupBy("course_id", "student_id")
  .agg(min("risk_date_time") as "risk_date_time")

然后您可以像之前那样将其转换为RDD(如果需要) - 结果具有相同的架构。

如果您想通过RDD执行此操作,请使用reduceByKey

studentRDD.reduceByKey((t1, t2) => if (t1.before(t2)) t1 else t2)

答案 1 :(得分:2)

首先,您的代码提供的结果不正确,因为reduce不正确。 reduce函数返回一个int(来自compareTo)而不是x,y,但int没有._2成员。 要更正此尝试:

  studentRDD.collect().map(z => (z._1, z._2)).reduce((x ,y) => if (x._2.compareTo(y._2) < 0) x else y)._1

基本上这个新函数会以较小的时间返回记录,然后返回你取得密钥的整体结果(最小的)。

请注意,由于收集,您在驱动程序上执行了所有这些操作。没有理由收集,映射和减少RDD上的工作,因此您可以通过执行以下操作获得相同的结果(并且仍然可以扩展):       studentRDD.map(z =&gt;(z._1,z._2))。reduce((x,y)=&gt; if(x._2.compareTo(y._2)&lt; 0)x else y)。 _1

您可以直接从上下文数据框执行此操作:

val targetRow = context.agg(min(struct('risk_date_time, 'course_id, 'student_id)) as "rec").select($"rec.*").collect()(0)
val key = (targetRow.getString(1), targetRow.getString(2))