从pyspark中的Dataframe方法中访问广播字典

时间:2018-01-21 05:42:49

标签: python apache-spark dataframe pyspark broadcast

我有一个广告,我希望用它来映射<v-select ... :item-value="value.language" :item-text="text"></v-select> 中的列值。让我们说我为此调用DataFrame方法。

我只能使用UDF,但不能直接使用它:

withColumn()

使用文字或使用UDF进行引用可以正常工作:

sc = SparkContext()
ss = SparkSession(sc)
df = ss.createDataFrame( [ "a", "b" ], StringType() ).toDF("key")
# +---+                                                                           
# |key|
# +---+
# |  a|
# |  b|
# +---+
thedict={"a":"A","b":"B","c":"C"}
thedict_bc=sc.broadcast(thedict)

但是,直接从命令访问字典并不是:

df.withColumn('upper',lit(thedict_bc.value.get('c',"--"))).show()
# +---+-----+
# |key|upper|
# +---+-----+
# |  a|    C|
# |  b|    C|
# +---+-----+
df.withColumn('upper',udf(lambda x : thedict_bc.value.get(x,"--"), StringType())('key')).show()
# +---+-----+
# |key|upper|
# +---+-----+
# |  a|    A|
# |  b|    B|
# +---+-----+

我错过了一些明显的东西吗?

1 个答案:

答案 0 :(得分:3)

TL; DR 您正在混淆属于完全不同的背景的事物。符号SQL表达式(litcol等)和纯Python代码。

你正在混淆上下文。以下行:

thedict_bc.value.get(col('key'),"--")))

在驱动程序上用Python执行,实际上是一个本地字典查找。 thedict不包含col('key')(字面意义,不涉及扩展)您始终获得默认值。

我个人会使用一个简单的join

lookup = sc.parallelize(thedict.items()).toDF(["key", "upper"])
df.join(lookup, ["key"], "left").na.fill("upper", "--").show()
+---+-----+                                                                     
|key|upper|
+---+-----+
|  b|    B|
|  a|    A|
+---+-----+

但是udf(正如您已经建立的那样)或文字map也会起作用:

from pyspark.sql.functions import coalesce, create_map
from itertools import chain

thedict_col = create_map(*chain.from_iterable(
    (lit(k), lit(v)) for k, v in thedict.items()
))

df.withColumn('upper', coalesce(thedict_col[col("key")], lit("--"))).show()
+---+-----+
|key|upper|
+---+-----+
|  a|    A|
|  b|    B|
+---+-----+

备注

  • 当然,如果您想转换为大写字母,请使用pyspark.sql.functions.upper
  • 使用some_broadcast.value作为函数的参数将完全不起作用。变量替换将在本地应用,并且不会使用广播。 value应该在函数体中调用,因此它在执行程序上下文中执行。