Scala 如何根据另一个数据帧的值(主键)计算spark数据帧中的行数?

Scala 如何根据另一个数据帧的值(主键)计算spark数据帧中的行数?,scala,apache-spark,spark-dataframe,Scala,Apache Spark,Spark Dataframe,我有两个数据帧df1和df2。两者都有一列“日期”,如下所示 df1的结构 +----------+ | date| +----------+ |02-01-2015| |02-02-2015| |02-03-2015| +----------+ df2的结构 +---+-------+-----+----------+ | ID|feature|value| date| +---+-------+-----+----------+ | 1|balance| 100|0

我有两个数据帧df1和df2。两者都有一列“日期”,如下所示

df1的结构

+----------+
|      date|
+----------+
|02-01-2015|
|02-02-2015|
|02-03-2015|
+----------+
df2的结构

+---+-------+-----+----------+
| ID|feature|value|      date|
+---+-------+-----+----------+
|  1|balance|  100|01-01-2015|
|  1|balance|  100|05-01-2015|
|  1|balance|  100|30-01-2015|
|  1|balance|  100|01-02-2015|
|  1|balance|  100|01-03-2015|
+---+-------+-----+----------+
我必须从df1中获取“日期”列中的每一行,与df2的“日期”进行比较,并从df2中获取所有小于df1中日期的行

假设从df1中获取第一行02-01-2015,并从df2中获取小于02-01-2015的所有行,这将产生如下输出

+---+-------+-----+----------+
| ID|feature|value|      date|
+---+-------+-----+----------+
|  1|balance|  100|01-01-2015|
+---+-------+-----+----------+ 

在spark scala中实现这一点的最佳方法是什么?我有数亿行。我曾想过在spark中使用window函数,但window仅限于一个数据帧。

如果您希望只比较
df1
df2
日期
中的一行,那么您应该首先
df1
中选择所需的行

val oneRowDF1 = df1.select($"date".as("date2")).where($"date" === "02-01-2015")
然后,您应该将
与您拥有的逻辑连接起来

df2.join(oneRowDF1, unix_timestamp(df2("date"), "dd-MM-yyyy") < unix_timestamp(oneRowDF1("date2"), "dd-MM-yyyy"))
    .drop("date2")
已更新

联接的代价很高,因为它需要在不同节点的执行者之间对数据进行洗牌

您可以简单地使用下面的过滤器函数

val oneRowDF1 = df1.select(unix_timestamp($"date", "dd-MM-yyyy").as("date2")).where($"date" === "02-01-2015")

df2.filter(unix_timestamp($"date", "dd-MM-yyyy") < oneRowDF1.take(1)(0)(0))
val oneRowDF1=df1。选择(unix时间戳($“日期”,“dd-MM-yyyy”).as(“日期2”)。其中($“日期”==“02-01-2015”)
df2.filter(unix_时间戳($“date”,“dd-MM-yyyy”)

我希望答案是有帮助的

这将在新的数据框架中获得所有结果:

val df1 = Seq(
  "02-01-2015",
  "02-02-2015",
  "02-03-2015"
).toDF("date")
  .withColumn("date", from_unixtime(unix_timestamp($"date", "dd-MM-yyyy")))

val df2 = Seq(
  (1, "balance", 100, "01-01-2015"),
  (1, "balance", 100, "05-01-2015"),
  (1, "balance", 100, "30-01-2015"),
  (1, "balance", 100, "01-02-2015"),
  (1, "balance", 100, "01-03-2015")
).toDF("ID", "feature", "value", "date")
  .withColumn("date", from_unixtime(unix_timestamp($"date", "dd-MM-yyyy")))

df1.join(
  df2, df2("date") < df1("date"), "left"
).show()


+-------------------+---+-------+-----+-------------------+
|               date| ID|feature|value|               date|
+-------------------+---+-------+-----+-------------------+
|2015-01-02 00:00:00|  1|balance|  100|2015-01-01 00:00:00|
|2015-02-02 00:00:00|  1|balance|  100|2015-01-01 00:00:00|
|2015-02-02 00:00:00|  1|balance|  100|2015-01-05 00:00:00|
|2015-02-02 00:00:00|  1|balance|  100|2015-01-30 00:00:00|
|2015-02-02 00:00:00|  1|balance|  100|2015-02-01 00:00:00|
|2015-03-02 00:00:00|  1|balance|  100|2015-01-01 00:00:00|
|2015-03-02 00:00:00|  1|balance|  100|2015-01-05 00:00:00|
|2015-03-02 00:00:00|  1|balance|  100|2015-01-30 00:00:00|
|2015-03-02 00:00:00|  1|balance|  100|2015-02-01 00:00:00|
|2015-03-02 00:00:00|  1|balance|  100|2015-03-01 00:00:00|
+-------------------+---+-------+-----+-------------------+
val df1=Seq(
"02-01-2015",
"02-02-2015",
"02-03-2015"
).toDF(“日期”)
.withColumn(“日期”,from_unixtime(unix_时间戳($“日期”,“dd-MM-yyyy”))
val df2=序列(
(1,“余额”,100,“01-01-2015”),
(1,“余额”,100,“05-01-2015”),
(1,“余额”,100,“2015年1月30日”),
(1,“余额”,100,“01-02-2015”),
(1,“余额”,100,“01-03-2015”)
).toDF(“ID”、“特征”、“值”、“日期”)
.withColumn(“日期”,from_unixtime(unix_时间戳($“日期”,“dd-MM-yyyy”))
df1.join(
df2,df2(“日期”)
编辑: 要从df2获取匹配签名记录的数量,请执行以下操作:

 df1.join(
    df2, df2("date") < df1("date"), "left"
 )
 .groupBy(df1("date"))
 .count
 .orderBy(df1("date"))
 .show

+-------------------+-----+
|               date|count|
+-------------------+-----+
|2015-01-02 00:00:00|    1|
|2015-02-02 00:00:00|    4|
|2015-03-02 00:00:00|    5|
+-------------------+-----+
df1.join(
df2,df2(“日期”)
您想一次只从df1中提取一行还是一次提取所有行?您好Ramesh。是,一次从df1中取一行,比较df2中的“日期”,并从df2中获取日期小于df1Thanks Ramesh中日期的所有行。谢谢你的帮助。实际上,我在df1中有数百万行,在df2中有十亿行,这意味着我必须执行数百万次联接操作,正如您可能知道的,联接是一个非常昂贵的操作。有没有像滑动窗这样的内置更好的火花方法?谢谢Ramesh。它起作用了。我将在完整数据集上运行有连接和无连接,并发布度量。谢谢你的帮助谢谢拉斐尔。你的回答很有效。在每次迭代之后,我们是否可以在value列上使用count或aggregate函数?假设从df1中获取第一行02-01-2015,并从df2中获取所有小于02-01-2015的行,计算行数并将其显示为结果,而不是显示行本身?
 df1.join(
    df2, df2("date") < df1("date"), "left"
 )
 .groupBy(df1("date"))
 .count
 .orderBy(df1("date"))
 .show

+-------------------+-----+
|               date|count|
+-------------------+-----+
|2015-01-02 00:00:00|    1|
|2015-02-02 00:00:00|    4|
|2015-03-02 00:00:00|    5|
+-------------------+-----+