Как перебрать массив (строку) для проверки значения Null / Blank в Pyspark - PullRequest
1 голос
/ 27 марта 2020

Я новичок в Pyspark. С помощью приведенного ниже фрейма данных можно разделить его на два разных фрейма на основе поля «_Value». Если в _Value, являющемся массивом (строкой), содержатся нулевые или пустые элементы, он должен go к одному фрейму данных, а остальные к другому.

+----+-----+-----+-------------------------------+-------------+--------------+
|key |Size |Color|AdditionalAttributeMetric      |_Name        |_Value        |
+----+-----+-----+-------------------------------+-------------+--------------+
|123k|BLACK|black|[Size -> BLACK, Color -> black]|[Size, Color]|[BLACK, black]|
|123k|WHITE|null |[Size -> WHITE, Color ->]      |[Size, Color]|[WHITE,]      |
+----+-----+-----+-------------------------------+-------------+--------------+

Ниже приведен полный код, но выдает ошибку «Столбец не повторяется».

from pyspark.sql import functions as F
from pyspark.sql.functions import *
from pyspark.sql.types import *
from pyspark.sql.functions import lit, col, create_map
from itertools import chain

rdd = sc.parallelize([('123k', 'BLACK', 'black'),
                      ('123k', 'WHITE', None)
                          ])

schema = StructType([StructField('key', StringType(), True),
                     StructField('Size', StringType(), True),
                     StructField('Color', StringType(), True)])

df_struct = sqlContext.createDataFrame(rdd, schema)

df_struct_subattri = df_struct.select("Size", "Color")

AdditionalAttributeMetric = create_map(
            list(chain(*((lit(name), col(name)) for name in df_struct_subattri.columns)))).alias(
            "AdditionalAttributeMetric")

df_struct = df_struct.select("*", AdditionalAttributeMetric)

df_struct = df_struct.withColumn("_Name", map_keys(col("AdditionalAttributeMetric")))
df_struct = df_struct.withColumn("_Value", map_values(col("AdditionalAttributeMetric")))


df_struct1 = df_struct.select("*").where(array_contains (col("_Value"), '') | array_contains (col("_Value"), lit(None)))

df_struct1.show(truncate = False)

Любая помощь приветствуется.

1 Ответ

1 голос
/ 27 марта 2020

Пример данных имеет 1 чистую строку, 1 строку с None, 1 строку с ''.

from pyspark.sql import function as F
df_struct.show()

+----+--------------+
| key|        _value|
+----+--------------+
|123k|[BLACK, black]|
|123k|      [WHITE,]|
|124k|      [BLUE, ]|
+----+--------------+

Если у вас нет spark2.4, , вы можете используйте array_contains, чтобы проверить наличие пустой строки. Делая это, если в какой-либо строке есть ноль, вывод для array_contains будет null, или если в нем будет пустая строка "", вывод будет true. Затем вы можете filter в этом новом столбце boolean, как показано ниже.

df.withColumn("boolean", F.array_contains("_value", ""))\
  .filter(~((F.col("boolean")==True) | (F.col("boolean").isNull()))).drop("boolean").show()

+----+--------------+
| key|        _value|
+----+--------------+
|123k|[BLACK, black]|
+----+--------------+

Вы можете удалить ~, чтобы получить все остальные строки с None или пустыми строками .

df.withColumn("boolean", F.array_contains("_value", ""))\
  .filter(((F.col("boolean")==True) | (F.col("boolean").isNull()))).drop("boolean").show()

+----+--------+
| key|  _value|
+----+--------+
|123k|[WHITE,]|
|124k|[BLUE, ]|
+----+--------+

Spark2.4:

Вы можете использовать функцию более высокого порядка array filter, чтобы вынуть None или '' , а затем сравните size в фрейме данных filter.

df_struct.withColumn("_value2", F.expr("""filter(_value, x-> x is not null and x!='')"""))\
  .filter((F.size("_value2")==F.size("_value"))).drop("_value2").show()

+----+--------------+
| key|        _value|
+----+--------------+
|123k|[BLACK, black]|
+----+--------------+

, чтобы получить другие строки, которые имеют Nones или '' или оба . Вы можете поставить ~ перед выражением фильтра.

df_struct.withColumn("_value2", F.expr("""filter(_value, x-> x is not null and x!='')"""))\
  .filter(~(F.size("_value2")==F.size("_value"))).drop("_value2").show()

+----+--------+
| key|  _value|
+----+--------+
|123k|[WHITE,]|
|124k|[BLUE, ]|
+----+--------+

Вы можете также использовать функцию более высокого порядка exists.

df.withColumn("boolean", F.expr("""exists(_value, x-> x is null or x=='')"""))\
  .filter(~(F.col("boolean")==True)).drop("boolean").show()

+----+--------------+
| key|        _value|
+----+--------------+
|123k|[BLACK, black]|
+----+--------------+

Удалите ~, чтобы получить все строки с Nones или "":

df.withColumn("boolean", F.expr("""exists(_value, x-> x is null or x=='')"""))\
  .filter((F.col("boolean")==True)).drop("boolean").show()

+----+--------+
| key|  _value|
+----+--------+
|123k|[WHITE,]|
|124k|[BLUE, ]|
+----+--------+
...