PySpark 比较空地图文字
PySpark Compare Empty Map Literal
我想在 PySpark DataFrame 中删除行,其中特定列包含一个空映射。我该怎么做呢?我似乎无法声明一个类型化的空 MapType 来与我的专栏进行比较。我已经看到在 Scala 中,您可以使用 typedLit
,但在 PySpark 中似乎没有这样的等价物。我也尝试过使用 lit(...)
并转换为 struct<string,int>
但我发现 lit()
没有可接受的参数(尝试使用 None
which returns null and {}
这是一个错误)。
我确定这是微不足道的,但我还没有看到这方面的任何文档!
这是一个使用 pyspark size
内置函数的解决方案:
from pyspark.sql.functions import col, size
df = spark.createDataFrame(
[(1, {1:'A'} ),
(2, {2:'B'} ),
(3, {3:'C'} ),
(4, {}),
(5, None)]
).toDF("id", "map")
df.printSchema()
# root
# |-- id: long (nullable = true)
# |-- map: map (nullable = true)
# | |-- key: long
# | |-- value: string (valueContainsNull = true)
df.withColumn("is_empty", size(col("map")) <= 0).show()
# +---+--------+--------+
# | id| map|is_empty|
# +---+--------+--------+
# | 1|[1 -> A]| false|
# | 2|[2 -> B]| false|
# | 3|[3 -> C]| false|
# | 4| []| true|
# | 5| null| true|
# +---+--------+--------+
注意条件是 size <= 0
因为在 null 的情况下函数 returns -1(如果 spark.sql.legacy.sizeOfNull
设置为真,否则它将 return无效的)。 Here您可以找到更多详细信息。
通用解决方案:比较 Map 列和文字 Map
对于更通用的解决方案,我们可以将内置函数 size
与 UDF 结合使用,将每个项目的字符串 key + value
附加到排序列表中(感谢@jxc指出以前版本的问题)。这里的假设是两个地图在以下情况下相等:
- 它们的大小相同
- key + value 的字符串表示在映射项之间是相同的
文字映射是通过 map_from_arrays
:
结合键和值的任意 python 字典创建的
from pyspark.sql.functions import udf, lit, size, when, map_from_arrays, array
df = spark.createDataFrame([
[1, {}],
[2, {1:'A', 2:'B', 3:'C'}],
[3, {1:'A', 2:'B'}]
]).toDF("key", "map")
dict = { 1:'A' , 2:'B' }
map_keys_ = array([lit(k) for k in dict.keys()])
map_values_ = array([lit(v) for v in dict.values()])
tmp_map = map_from_arrays(map_keys_, map_values_)
to_strlist_udf = udf(lambda d: sorted([str(k) + str(d[k]) for k in d.keys()]))
def map_equals(m1, m2):
return when(
(size(m1) == size(m2)) &
(to_strlist_udf(m1) == to_strlist_udf(m2)), True
).otherwise(False)
df = df.withColumn("equals", map_equals(df["map"], tmp_map))
df.show(10, False)
# +---+------------------------+------+
# |key|map |equals|
# +---+------------------------+------+
# |1 |[] |false |
# |2 |[1 -> A, 2 -> B, 3 -> C]|false |
# |3 |[1 -> A, 2 -> B] |true |
# +---+------------------------+------+
注意:如您所见,pyspark ==
运算符也非常适合数组比较。
我想在 PySpark DataFrame 中删除行,其中特定列包含一个空映射。我该怎么做呢?我似乎无法声明一个类型化的空 MapType 来与我的专栏进行比较。我已经看到在 Scala 中,您可以使用 typedLit
,但在 PySpark 中似乎没有这样的等价物。我也尝试过使用 lit(...)
并转换为 struct<string,int>
但我发现 lit()
没有可接受的参数(尝试使用 None
which returns null and {}
这是一个错误)。
我确定这是微不足道的,但我还没有看到这方面的任何文档!
这是一个使用 pyspark size
内置函数的解决方案:
from pyspark.sql.functions import col, size
df = spark.createDataFrame(
[(1, {1:'A'} ),
(2, {2:'B'} ),
(3, {3:'C'} ),
(4, {}),
(5, None)]
).toDF("id", "map")
df.printSchema()
# root
# |-- id: long (nullable = true)
# |-- map: map (nullable = true)
# | |-- key: long
# | |-- value: string (valueContainsNull = true)
df.withColumn("is_empty", size(col("map")) <= 0).show()
# +---+--------+--------+
# | id| map|is_empty|
# +---+--------+--------+
# | 1|[1 -> A]| false|
# | 2|[2 -> B]| false|
# | 3|[3 -> C]| false|
# | 4| []| true|
# | 5| null| true|
# +---+--------+--------+
注意条件是 size <= 0
因为在 null 的情况下函数 returns -1(如果 spark.sql.legacy.sizeOfNull
设置为真,否则它将 return无效的)。 Here您可以找到更多详细信息。
通用解决方案:比较 Map 列和文字 Map
对于更通用的解决方案,我们可以将内置函数 size
与 UDF 结合使用,将每个项目的字符串 key + value
附加到排序列表中(感谢@jxc指出以前版本的问题)。这里的假设是两个地图在以下情况下相等:
- 它们的大小相同
- key + value 的字符串表示在映射项之间是相同的
文字映射是通过 map_from_arrays
:
from pyspark.sql.functions import udf, lit, size, when, map_from_arrays, array
df = spark.createDataFrame([
[1, {}],
[2, {1:'A', 2:'B', 3:'C'}],
[3, {1:'A', 2:'B'}]
]).toDF("key", "map")
dict = { 1:'A' , 2:'B' }
map_keys_ = array([lit(k) for k in dict.keys()])
map_values_ = array([lit(v) for v in dict.values()])
tmp_map = map_from_arrays(map_keys_, map_values_)
to_strlist_udf = udf(lambda d: sorted([str(k) + str(d[k]) for k in d.keys()]))
def map_equals(m1, m2):
return when(
(size(m1) == size(m2)) &
(to_strlist_udf(m1) == to_strlist_udf(m2)), True
).otherwise(False)
df = df.withColumn("equals", map_equals(df["map"], tmp_map))
df.show(10, False)
# +---+------------------------+------+
# |key|map |equals|
# +---+------------------------+------+
# |1 |[] |false |
# |2 |[1 -> A, 2 -> B, 3 -> C]|false |
# |3 |[1 -> A, 2 -> B] |true |
# +---+------------------------+------+
注意:如您所见,pyspark ==
运算符也非常适合数组比较。