2

给定具有以下行的 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,col3col4(即第 3 行)删除带有空数组的行。

例如,我可能希望这段代码能够工作:

df.where(~df.col2.isEmpty(), ~df.col3.isEmpty(), ~df.col4.isEmpty()).collect()

我有两个问题

  1. 如何将 where 子句与and但更重要的是...
  2. 如何判断数组是否为空。

那么,是否有一个内置函数来查询空数组?有没有一种优雅的方式将一个空数组强制为一个nanull值?

我试图避免使用 python 来解决它,无论是使用 UDF 还是.map().

4

1 回答 1

3

如何将where子句与and结合起来

要在列上构造布尔表达式,您应该使用&,|~运算符,因此在您的情况下它应该是这样的

~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解决方案是转换为字符串

cols = [
    col(c).cast(StringType()) != lit("ArrayBuffer()")
    for c in  ["col2", "col3", "col4"]
]
cond = reduce(lambda x, y: x & y, cols)
df.where(cond)

但它从一英里外散发出来。

也可以使用explode数组 , groupBy,并且在任何现实生活场景中都可能非常昂贵。aggcountjoin

可能避免 UDF 和脏黑客的最佳方法是将空数组替换为NULL.

于 2015-09-08T07:43:38.190 回答