基于行值的条件联接过滤

时间:2018-11-08 01:48:36

标签: scala apache-spark join

我有2个数据框需要结合在一起。我们将通过2列进行联接,但是,这2列不是id,并且在其他数据框中不会产生唯一的行值。例如,两个数据框将如下所示:

Dataframe 1 
    product_no   dist   code
    040          wmn    aj
    040          wmn    lm
    040          wmn    mn

Dataframe 2
    p_no   vendor    code   product
    040    wmn       **     y
    040    wmn       *j     y
    040    wmn       mn     n

对2列的查询如下:

df1.join(df2, $"product_no" === $"p_no" && $"dist" === $"vendor")

这将使所有行彼此连接并重复。但是,我们也想通过code进行连接,例如,其中代码等于第二个数据帧中的实际代码。如果找不到实际值,则检查代码是否以j结尾,如果没有,则我们以*j加入,如果没有匹配的内容,则以{ {1}}结果应如下所示:

**

有没有办法做到这一点?

2 个答案:

答案 0 :(得分:0)

我也经历了一些类似的情况,即基于条件标志进行联接。

val decision: Boolean = false
val exprs = (if (decision != true) 
                   dataFrame1.col("id").equalTo(dataFrame2.col("id"))
             else dataFrame1.col("id").equalTo(dataFrame2.col("id")) 
                   and dataFrame1.col("code").equalTo(dataFrame2.col("code")))
            )
dataFrame1.join(dataFrame2, exprs).show

您可以看到示例示例here 您可以在此处利用相同的逻辑。

尝试使用行值代替条件标志。

答案 1 :(得分:0)

检查一下:

scala> val df3 = df1.alias("t1").join(df2.alias("t2"),$"product_no" === $"p_no" && $"dist" === $"vendor").withColumn("match", when($"t1.code"===$"t2.code",lit(1)).when(regexp_extract($"t1.code",".*j",0)=!=lit("") && regexp_extract($"t2.code",".*j",0)=!=lit(""), 2).when(regexp_extract($"t1.code",".*[^j]$",0)=!=lit("") &&  regexp_extract($"t2.code","[*][*]",0)=!=lit(""), 3).otherwise(lit(0))).filter('match > 0).toDF("product_no","dist","code1","p_no","vendor","code2","product","match")
df3: org.apache.spark.sql.DataFrame = [product_no: string, dist: string ... 6 more fields]

scala> val df4= df3.withColumn("match2", collect_set('code2) over(Window.partitionBy('product_no,'dist).orderBy('match)))
df4: org.apache.spark.sql.DataFrame = [product_no: string, dist: string ... 7 more fields]

scala> df4.show
+----------+----+-----+----+------+-----+-------+-----+------------+
|product_no|dist|code1|p_no|vendor|code2|product|match|      match2|
+----------+----+-----+----+------+-----+-------+-----+------------+
|       040| wmn|   mn| 040|   wmn|   mn|      n|    1|        [mn]|
|       040| wmn|   aj| 040|   wmn|   *j|      y|    2|    [*j, mn]|
|       040| wmn|   mn| 040|   wmn|   **|      y|    3|[*j, mn, **]|
|       040| wmn|   lm| 040|   wmn|   **|      y|    3|[*j, mn, **]|
+----------+----+-----+----+------+-----+-------+-----+------------+

scala> df4.selectExpr("*"," match in (1,2) or ( not array_contains(match2,code1) ) as match3 ").where('match3).show
+----------+----+-----+----+------+-----+-------+-----+------------+------+
|product_no|dist|code1|p_no|vendor|code2|product|match|      match2|match3|
+----------+----+-----+----+------+-----+-------+-----+------------+------+
|       040| wmn|   mn| 040|   wmn|   mn|      n|    1|        [mn]|  true|
|       040| wmn|   aj| 040|   wmn|   *j|      y|    2|    [*j, mn]|  true|
|       040| wmn|   lm| 040|   wmn|   **|      y|    3|[*j, mn, **]|  true|
+----------+----+-----+----+------+-----+-------+-----+------------+------+


scala>