在Spark数据框架中将特定函数应用于结构化列的有效方法?

时间:2016-11-13 11:28:06

标签: python apache-spark dataframe spark-dataframe pyspark-sql

我在Spark数据框中有数据,其中col列包含以下格式的结构化数据

------ col -------   # Column whose elements are structures
field0  field1 …     # StructType with StructFields (variable names and count)
[1,2,3] [4,5]  [6]   # Each field is of type ArrayType
[1,2]   [3]    []
…

其中字段的编号和名称未修复

计算每一行中元素总数的最有效方法是什么?在上面的示例中,预期的结果数据框将是:

num_elements
6
3
…

始终存在用户定义函数的解决方案:

from pyspark.sql.types import IntegerType

def num_elements(all_arrays_in_row):
    return sum(map(len, all_arrays_in_row))
num_elements = pyspark.sql.functions.udf(num_elements, IntegerType())

data_frame.select(num_elements(data_frame.col)).show()  # Number of elements in each row

现在,我不确定这是否通常有效,因为:

  1. 函数num_elements()在Python中。
  2. 如果由于某种原因字段碰巧没有存储在一起,map()强制在计算每个数组之前获取每个数组。
  3. 更一般地说,"纯粹" Spark方法会更有效率,但它正在躲避我。到目前为止我尝试的是以下内容,但这比上面的方法更麻烦,而且还不完整:

    1. 使用field0(繁琐)获取字段名称[field.name for field in data_frame.select("col").schema.fields[0].dataType.fields]等。
    2. 对于每个字段名称,有效地计算其数组的大小:

      sizes_one_field = data_frame.select(pyspark.sql.functions.size(
                                          data_frame.col.getField(field_name))
      
    3. 现在,我陷入困境,因为我不确定如何将1列数据帧sizes_one_field加在一起(每个字段名称都有一个)。另外,也许有一种方法可以直接将size()函数应用于Spark中的col列的每个字段(通过某种映射?)?或者采用一些完全不同的方法来获取每一行中的元素总数?

1 个答案:

答案 0 :(得分:1)

您可以尝试以下内容:

from pyspark.sql import functions as f

result = df.select(sum((f.size(df[col_name]) for col_name in df.columns), f.lit(0)))

此解决方案使用pyspark.sql内置函数,并将以优化的方式执行。有关这些功能的更多信息,您可以查看其pyspark documentation