spark posexplode函数运行速度很慢

时间:2018-02-21 08:06:09

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

我有一个火花数据框存储为orc,大约10000行,并遵循架构:

>>> df.printSchema()
root
 |-- contig: string (nullable = true)
 |-- start: integer (nullable = true)
 |-- ref: string (nullable = true)
 |-- alt: string (nullable = true)
 |-- gt: array (nullable = true)
 |    |-- element: integer (containsNull = true)

其中arrayField是200000个整数的列表。我想将其转换为具有扁平结构的数据框:

>>> from pyspark.sql.functions import posexplode
>>> flat = df.select('contig', 'start', 'ref', 'alt', posexplode(df.gt))
>>> flat.explain()
== Physical Plan ==
*Project [contig#0, start#1, ref#2, alt#3, pos#11, col#12]
+- Generate posexplode(gt#4), true, false, [pos#11, col#12]
   +- *FileScan orc [contig#0,start#1,ref#2,alt#3,gt#4] Batched: false, Format: ORC, Location: InMemoryFileIndex[file:/path/to/data], PartitionFilters: [], PushedFilters: [], ReadSchema: struct<contig:string,start:int,ref:string,alt:string,gt:array<int>>
>>> flat.write.orc('/path/to/output/file')

在具有24个CPU内核和超过100GB内存的计算机上将展平的数据帧写入文件需要五个多小时。这只是posexplode函数的一个特性还是有其他错误?

1 个答案:

答案 0 :(得分:1)

似乎火花在做这里的行疯了。使用RDD,我能够获得更好的性能(每个CPU核心每秒1/3行,而每个CPU核心数据帧每秒1/40行)。但这仍然不是很快。

df = sql_context.read.orc('/path/to/source/file')
rdd = df.rdd

def expand(row):
    contig, start, ref, alt, gt = row
    def getrow(index, genotype):
        return contig, start, ref, alt, index, genotype
    return [getrow(index, genotype) for index, genotype in enumerate(gt)]

rdd_flat = rdd.flatMap(expand)
schema = ('contig', 'start', 'ref', 'alt', 'index', 'genotype')
sqlc.createDataFrame(rdd_flat, schema=schema).write.orc('/path/to/output/file')

有趣的是,如果我将expand-function重新定义为

def expand(row):
    def getrow(index, genotype):
        return Row(
            contig=row.contig,
            start=row.start,
            ref=row.ref,
            alt=row.alt,
            index=index,
            genotype=genotype
        )
    return [getrow(index, genotype) for index, genotype in enumerate(row.gt)]

它运行速度慢约13倍(单个函数调用大约需要1.4秒)。

很明显,行对象的效率非常低。

但还有更多要解决的问题。单核应该能够每秒运行扩展功能9次,但实际性能是每3秒1行。

编辑:找到一个'解决方案':使用prestodb查询而不是spark。每个CPU核心运行速度超过每秒1行 - 比数据帧快20倍,比RDD快4倍:

create table flat (
  contig varchar,
  start int,
  ref varchar,
  alt varchar,
  index bigint,
  genotype tinyint
) 
WITH (format = 'ORC');

insert into flat
select contig, start, ref, alt, index, genotype, partition_name
from nested cross join unnest(gt) with ordinality as g (genotype, index)
where partition_name='10-70329347';