我有一个按计划执行的Spark作业。
当我将结果DataFrame写入数据目标(S3,HDFS,DB ...)时,我希望Spark写入的内容不会与特定列重复。
示例:
假设MY_ID
是唯一列。
第一次执行:
--------------
|MY_ID|MY_VAL|
--------------
| 1 | 5 |
| 2 | 9 |
| 3 | 6 |
--------------
第二次执行:
--------------
|MY_ID|MY_VAL|
--------------
| 2 | 9 |
| 3 | 2 |
| 4 | 4 |
--------------
在两次执行之后,我希望在数据目标中找到的内容是这样的:
--------------
|MY_ID|MY_VAL|
--------------
| 1 | 5 |
| 2 | 9 |
| 3 | 6 |
| 4 | 4 |
--------------
预期输出是第一次执行的结果,并附加了第二次执行的结果。如果MY_ID
的值已经存在,则保留旧值,丢弃新执行的结果(在这种情况下,第二个执行要为MY_ID
3写入MY_VAL
9。由于该记录从第一次执行起就已经存在,因此将删除新记录。)
因此,distinct()
函数不足以保证这种情况。列MY_ID
的唯一性即使在转储的输出中也应保持不变。
是否有任何解决方案可以合理的计算成本保证此属性? (与关系数据库中的UNIQUE
基本相同。)
答案 0 :(得分:0)
您可以在第一次和第二次迭代中执行fullOuterJoin
。
val joined = firstIteration.join(secondIteration, Seq("MY_ID"), "fullouter")
scala> joined.show
+-----+------+------+
|MY_ID|MY_VAL|MY_VAL|
+-----+------+------+
| 1| 5| null|
| 3| 6| 2|
| 4| null| 4|
| 2| 9| 9|
+-----+------+------+
从结果表中,如果firstIteration的MY_VAL
有值,则可以按原样使用它。否则,如果它的null
(表示密钥仅在第二次迭代中出现)。使用secondIteration的MY_VAL
中的值。
scala> joined.withColumn("result", when(firstIteration.col("MY_VAL").isNull, secondIteration.col("MY_VAL"))
.otherwise(firstIteration.col("MY_VAL")))
.drop("MY_VAL")
.show
+-----+------+
|MY_ID|result|
+-----+------+
| 1| 5|
| 3| 6|
| 4| 4|
| 2| 9|
+-----+------+
答案 1 :(得分:-1)
不确定使用的是Scala还是Python,但请看一下dropDuplicates
函数,该函数允许您指定一个或多个列:
https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.sql.Dataset