Scala 基于最大日期记录的火花过滤器
我正在使用Spark/Scala处理一个Scala 基于最大日期记录的火花过滤器,scala,apache-spark,Scala,Apache Spark,我正在使用Spark/Scala处理一个Hive表,其中包含每个成员的事务数据。我需要获得每个成员的最大记录。我使用下面的代码完成了这项任务,它成功地工作了,但没有获得性能 我需要问一下,是否有其他方法可以提高这段代码的性能?我找到了一些使用spark sql的方法,但我更喜欢sparkDataframe或Dataset 下面的示例将重现我的代码和数据 val mamberData = Seq( Row("1234", "CX", java.sql.Timestamp.valueOf
Hive
表,其中包含每个成员的事务数据。我需要获得每个成员的最大记录。我使用下面的代码完成了这项任务,它成功地工作了,但没有获得性能
我需要问一下,是否有其他方法可以提高这段代码的性能?我找到了一些使用spark sql的方法,但我更喜欢spark
Dataframe或Dataset
下面的示例将重现我的代码和数据
val mamberData = Seq(
Row("1234", "CX", java.sql.Timestamp.valueOf("2018-09-09 00:00:00")),
Row("1234", "CX", java.sql.Timestamp.valueOf("2018-03-02 00:00:00")),
Row("5678", "NY", java.sql.Timestamp.valueOf("2019-01-01 00:00:00")),
Row("5678", "NY", java.sql.Timestamp.valueOf("2018-01-01 00:00:00")),
Row("7088", "SF", java.sql.Timestamp.valueOf("2018-09-01 00:00:00"))
)
val MemberDataSchema = List(
StructField("member_id", StringType, nullable = true),
StructField("member_state", StringType, nullable = true),
StructField("activation_date", TimestampType, nullable = true)
)
import spark.implicits._
val memberDF =spark.createDataFrame(
spark.sparkContext.parallelize(mamberData),
StructType(MemberDataSchema)
)
val memberDfMaxDate = memberDF.groupBy('member_id).agg(max('activation_date).as("activation_date"))
val memberDFMaxOnly = memberDF.join(memberDfMaxDate,Seq("member_id","activation_date"))
输出如下
+---------+------------+-------------------+
|member_id|member_state|activation_date |
+---------+------------+-------------------+
|1234 |CX |2018-09-09 00:00:00|
|1234 |CX |2018-03-02 00:00:00|
|5678 |NY |2019-01-01 00:00:00|
|5678 |NY |2018-01-01 00:00:00|
|7088 |SF |2018-09-01 00:00:00|
+---------+------------+-------------------+
+---------+-------------------+------------+
|member_id| activation_date|member_state|
+---------+-------------------+------------+
| 7088|2018-09-01 00:00:00| SF|
| 1234|2018-09-09 00:00:00| CX|
| 5678|2019-01-01 00:00:00| NY|
+---------+-------------------+------------+
您可以使用许多技术,例如
排名
或数据集
。我更喜欢使用reducegroup
,因为这是一种函数风格的方式,而且易于解释
case class MemberDetails(member_id: String, member_state: String, activation_date: FileStreamSource.Timestamp)
val dataDS: Dataset[MemberDetails] = spark.createDataFrame(
spark.sparkContext.parallelize(mamberData),
StructType(MemberDataSchema)
).as[MemberDetails]
.groupByKey(_.member_id)
.reduceGroups((r1, r2) ⇒ if (r1.activation_date > r2.activation_date) r1 else r2)
.map { case (key, row) ⇒ row }
dataDS.show(truncate = false)
用于分配排名并筛选每个组中的第一个
import org.apache.spark.sql.expressions.Window
// Partition by member_id order by activation_date
val byMemberId = Window.partitionBy($"member_id").orderBy($"activation_date" desc)
// Get the new DF applying window function
val memberDFMaxOnly = memberDF.select('*, rank().over(byMemberId) as 'rank).where($"rank" === 1).drop("rank")
// View the results
memberDFMaxOnly.show()
+---------+------------+-------------------+
|member_id|member_state| activation_date|
+---------+------------+-------------------+
| 1234| CX|2018-09-09 00:00:00|
| 5678| NY|2019-01-01 00:00:00|
| 7088| SF|2018-09-01 00:00:00|
+---------+------------+-------------------+
数据帧的
groupBy
与它得到的效率一样高(由于部分聚合,比窗口函数效率更高)
但是您可以通过在聚合子句中使用struct
来避免连接:
val memberDfMaxOnly = memberDF.groupBy('member_id).agg(max(struct('activation_date, 'member_state)).as("row_selection"))
.select(
$"member_id",
$"row_selection.activation_date",
$"row_selection.member_state"
)
谢谢你的回答,我试着比较了窗口函数和reducegroup,但是reducegroup似乎更快。我不知道为什么?GroupByKey对于小数据集很快,但是对于大数据集,您应该避免使用它。我会使用窗口功能。谢谢你的回答,我试着将groupBy与window函数和reduceGroups进行比较,但是reduceGroups似乎更快。我不知道为什么?