在子串匹配(或包含)上加入PySpark数据帧

时间:2017-08-07 16:14:15

标签: pyspark

我想在两个数据帧之间执行左连接,但列不相同。第一个数据帧中的连接列具有相对于第二个数据帧的额外后缀。

from pyspark import SparkContext
import pyspark.sql.functions as f

sc = SparkContext()

df1 = sc.parallelize([
    ['AB-101-1', 'el1', 1.5],
    ['ABC-1020-1', 'el2', 1.3],
    ['AC-1030-1', 'el3', 8.5]
]).toDF(('id1', 'el', 'v1'))

df2 = sc.parallelize([
    ['AB-101', 3],
    ['ABC-1020', 4]
]).toDF(('id2', 'v2'))

我想通过左连接获得的数据帧是:

df_join = sc.parallelize([
    ['AB-101-1', 'el1', 1.5, 'AB-101', 3],
    ['ABC-1020-1', 'el2', 1.3, 'ABC-1020', 4],
    ['AC-103-1', 'el3', 8.5, None, None]
]).toDF(('id1', 'el', 'v1', 'id2', 'v2'))

我很乐意使用pyspark.sql.substring来获取"除最后2个字符以外的所有字符",或使用类似pyspark.sql.like的内容,但我无法弄清楚如何使这些中的任何一个在连接中正常工作。

3 个答案:

答案 0 :(得分:1)

如果id1& id2有一些类似于你在问题中说明的模式,然后我建议采用以下方法。

from pyspark.sql.functions import regexp_extract

df1 = sc.parallelize([
    ['AB-101-1', 'el1', 1.5],
    ['ABC-1020-1', 'el2', 1.3],
    ['AC-1030-1', 'el3', 8.5]
]).toDF(('id1', 'el', 'v1'))

df2 = sc.parallelize([
    ['AB-101', 3],
    ['ABC-1020', 4]
]).toDF(('id2', 'v2'))

df1 = df1.withColumn("id1_transformed", regexp_extract('id1', '(.*-.*)(-.*)', 1))

df_join = df1.join(df2, df1.id1_transformed==df2.id2, 'left').drop("id1_transformed")
df_join.show()

输出是:

+----------+---+---+--------+----+
|       id1| el| v1|     id2|  v2|
+----------+---+---+--------+----+
|ABC-1020-1|el2|1.3|ABC-1020|   4|
|  AB-101-1|el1|1.5|  AB-101|   3|
| AC-1030-1|el3|8.5|    null|null|
+----------+---+---+--------+----+

希望这有帮助!

答案 1 :(得分:0)

此解决方案使用3 5415.00 6.00 -1998.3 -781.28 21.98 9.99 3.41 21.63 0.94 1.29 0 -98.04 98.04 4 6443.00 6.00 -1998.3-1216.10 21.71 0.35 0.38 22.78 8.00 3.00 2 -98.04 98.04 5 5806.00 7.00 -1997.8 -946.67 21.04 0.19 0.19 23.26 6.27 0.97 0 2.23 -2.23 6 7882.00 8.00 -1997.4-1824.80 22.18 0.58 0.49 22.62 0.85 0.85 0 0.44 -0.44 7 3278.00 9.00 -1997.0 122.67 20.94 0.24 0.20 23.53 8.00 0.24 2 -98.04 98.04 解构原始split,然后id1重建较短的concat

id2

但我宁愿使用df1 = ( df1 .withColumn('id1_els', f.split('id1','-')) .withColumn('id2', f.concat(f.col('id1_els').getItem(0) , f.lit('-') , f.col('id1_els').getItem(1))) ) df_join = df1.join(df2, 'id2', 'left').show() substring的解决方案,因为这在很大程度上取决于我的ID字段的具体形式。

答案 2 :(得分:0)

在您的特定情况下,regexp_extract可能是您的最佳选择,但在一般情况下,您可以使用:

df_join = df1.join(df2, df2.id2.contains(df1.id1), how='left')