给定一个包含以下行的DataFrame:
rows = [
Row(col1='abc', col2=[8], col3=[18], col4=[16]),
Row(col2='def', col2=[18], col3=[18], col4=[]),
Row(col3='ghi', col2=[], col3=[], col4=[])]
我想为每个col2
, col3
和col4
(即第三行)删除空数组的行。
例如,我可能希望这段代码工作:
df.where(~df.col2.isEmpty(), ~df.col3.isEmpty(), ~df.col4.isEmpty()).collect()
我有两个问题
- where clause如何与
and
结合,但更重要的是… - 如何判断数组是否为空
那么,是否有一个内置函数来查询空数组?是否有一种优雅的方式将空数组强制为na
或null
值?
我试图避免使用python来解决它,无论是使用UDF还是.map()
。
where子句with和
要在列上构造布尔表达式,你应该使用&
, |
和~
运算符,所以在你的情况下,它应该是这样的
~lit(True) & ~lit(False)
由于这些操作符比复杂表达式的比较操作符具有更高的优先级,因此必须使用括号:
(lit(1) > lit(2)) & (lit(3) > lit(4))
如何判断数组是否为空。
我很确定没有UDF就没有优雅的方法来处理这个问题。我猜你已经知道你可以像这样使用Python UDF
isEmpty = udf(lambda x: len(x) == 0, BooleanType())
也可以使用Hive UDF:
df.registerTempTable("df")
query = "SELECT * FROM df WHERE {0}".format(
" AND ".join("SIZE({0}) > 0".format(c) for c in ["col2", "col3", "col4"]))
sqlContext.sql(query)
想到的唯一可行的非udf解决方案是转换为string
cols = [
col(c).cast(StringType()) != lit("ArrayBuffer()")
for c in ["col2", "col3", "col4"]
]
cond = reduce(lambda x, y: x & y, cols)
df.where(cond)
但一英里外就有味道。
也可以使用count
和join
来explode
数组,groupBy
, agg
,但很可能在任何现实生活场景中都非常昂贵。
可能避免udf和恶意攻击的最佳方法是将空数组替换为NULL
。