df1包含字段id
和json
; df2包含字段id
和json
df1.count()
=> 1200; df2.count()
=> 20
df1包含所有行。 df2只有20行的增量更新。
我的目标是使用df2
中的值更新df1。 df2
的所有ID都在df1中。但df2已为这些相同的ID更新了值(在json
字段中)。
生成的df应包含df1
的所有值和df2
的更新值。
最好的方法是什么? - 使用最少数量的连接和过滤器。
谢谢!
答案 0 :(得分:0)
如果您需要来自两个数据帧的数据,您可以union
两个数据帧
import spark.implicits._
First Dataframe
val df1 = Seq(
(1, "a"),
(2, "b"),
(3, "c")
).toDF("id", "value")
第二个数据框
val df2 = Seq(
(1, "x"),
(2, "y")
).toDF("id", "value")
要将结果作为df1
和df2
的数据,请使用union
val resultDF = df1.union(df2)
resultDF.show()
输出:
+---+-----+
|id |value|
+---+-----+
|1 |a |
|2 |b |
|3 |c |
|1 |x |
|2 |y |
+---+-----+
答案 1 :(得分:0)
您可以使用一个左连接来实现此目的。
创建示例数据框
使用@Shankar Koirala在his answer中提供的样本数据。
data1 = [
(1, "a"),
(2, "b"),
(3, "c")
]
df1 = sqlCtx.createDataFrame(data1, ["id", "value"])
data2 = [
(1, "x"),
(2, "y")
]
df2 = sqlCtx.createDataFrame(data2, ["id", "value"])
执行左连接
使用id
列上的左连接加入两个DataFrame。这将保留左侧DataFrame中的所有行。对于右侧DataFrame中没有匹配id
的行,该值将为null
。
import pyspark.sql.functions as f
df1.alias('l').join(df2.alias('r'), on='id', how='left')\
.select(
'id',
f.col('l.value').alias('left_value'),
f.col('r.value').alias('right_value')
)\
.show()
#+---+----------+-----------+
#| id|left_value|right_value|
#+---+----------+-----------+
#| 1| a| x|
#| 3| c| null|
#| 2| b| y|
#+---+----------+-----------+
选择所需数据
我们将使用不匹配的id
具有null
来选择最终列的事实。如果它不为null,请使用pyspark.sql.functions.when()
使用正确的值,否则保留左值。
df1.alias('l').join(df2.alias('r'), on='id', how='left')\
.select(
'id',
f.when(
~f.isnull(f.col('r.value')),
f.col('r.value')
).otherwise(f.col('l.value')).alias('value')
)\
.show()
#+---+-----+
#| id|value|
#+---+-----+
#| 1| x|
#| 3| c|
#| 2| y|
#+---+-----+
如果您想按顺序id
,可以对此输出进行排序。
使用pyspark-sql
您可以使用pyspark-sql查询执行相同的操作:
df1.registerTempTable('df1')
df2.registerTempTable('df2')
query = """SELECT l.id,
CASE WHEN r.value IS NOT NULL THEN r.value ELSE l.value END AS value
FROM df1 l LEFT JOIN df2 r ON l.id = r.id"""
sqlCtx.sql(query.replace("\n", "")).show()
#+---+-----+
#| id|value|
#+---+-----+
#| 1| x|
#| 3| c|
#| 2| y|
#+---+-----+
答案 2 :(得分:0)
我想提供一个更通用的解决方案。如果输入数据有 100 列而不是 2 列会发生什么?我们将花费太多时间来合并这 100 列以保持左连接右侧的值。 解决此问题的另一种方法是从原始 df 中“删除”更新的行,最后与更新的行进行联合。
data_orginal = spark.createDataFrame([
(1, "a"),
(2, "b"),
(3, "c")
], ("id", "value"))
data_updated = spark.createDataFrame([
(1, "x"),
(2, "y")
], ("id", "value"))
data_orginal.show()
+---+-----+
| id|value|
+---+-----+
| 1| a|
| 2| b|
| 3| c|
+---+-----+
data_updated.show()
+---+-----+
| id|value|
+---+-----+
| 1| x|
| 2| y|
+---+-----+
data_orginal.createOrReplaceTempView("data_orginal")
data_updated.createOrReplaceTempView("data_updated")
src_data_except_updated = spark.sql(f"SELECT * FROM data_orginal WHERE id not in (1,2)")
result_data = src_data_except_updated.union(data_updated)
result_data.show()
+---+-----+
| id|value|
+---+-----+
| 3| c|
| 1| x|
| 2| y|
+---+-----+
注意查询
<块引用>SELECT * FROM data_orginal WHERE id 不在 (1,2) 中
可以自动生成:
ids_collect = spark.sql(f"SELECT id FROM data_updated").collect()
ids_list = [f"{x.id}" for x in ids_collect]
ids_str = ",".join(ids_list)
query_get_all_except = f"SELECT * FROM data_original WHERE id not in ({ids_str})"