Выбор пустых значений массива из Spark DataFrame

Учитывая 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 (т.е. 3-й строки).

Например, я мог бы ожидать, что этот код будет работать:

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

у меня две проблемы

  1. как комбинировать предложения where с and, но что более важно...
  2. как определить, что массив пуст.

Итак, есть ли встроенная функция для запроса пустых массивов? Есть ли элегантный способ привести пустой массив к значению na или null?

Я пытаюсь избежать использования python для его решения либо с UDF, либо с .map().


person Rob Cowie    schedule 07.09.2015    source источник


Ответы (1)


как сочетать предложения where с и

Чтобы построить логические выражения для столбцов, вы должны использовать операторы &, | и ~, поэтому в вашем случае это должно быть примерно так

~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, agg с использованием count и join, но, скорее всего, это слишком дорого, чтобы быть полезным в любом сценарии реальной жизни.

Вероятно, лучший способ избежать UDF и грязных хаков — заменить пустые массивы на NULL.

person zero323    schedule 08.09.2015
comment
Полезная информация спасибо. Мне было бы интересно увидеть пример замены пустых массивов на null. Есть ли способ добиться этого без udf? - person Rob Cowie; 08.09.2015
comment
Лично я бы использовал Hive SIZE UDF или чистил данные при загрузке. - person zero323; 09.09.2015