我有一个火花数据框存储为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函数的一个特性还是有其他错误?
答案 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';