在不重新分区的情况下将火花数据帧保存在多个部分中

时间:2016-07-05 14:57:22

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

我想查询我的数据库,并且只存储按一些列排序的前100万条记录,例如column1。 我尝试了两种方法

  1. 我将镶木地板文件从HDFS加载到数据框中并对其应用SQL查询,然后将完整的数据框(1000万条记录)保存为HDFS上的文本文件。

    df = sqlContext.sql("SELECT * FROM table order by column1")
    df.rdd.saveAsTextFile("<path>")
    

    然后我读取文本文件并从文本文件中获取100万条记录。

  2. 我将SQL查询限制为100万条记录。

    df = sqlContext.sql("SELECT * FROM table order by column1 LIMIT 1000000")
    df.rdd.saveAsTextFile("<path>")
    

    但第二种方法要慢得多。我发现在第二种情况下,SQL查询(df)返回的数据帧只包含1个分区,因此它写在一个任务中。对数据帧进行重新分区改进了第二种情况下的性能,但它仍然比第一种情况慢。

  3. 请允许任何人建议在案例2或任何其他方法中更快地保存数据帧以实现相同任务的方法

1 个答案:

答案 0 :(得分:0)

假设column1是数字,一种可能的解决方案是估算分布和filter而不是排序和limit。假设您的数据如下所示:

from pyspark.mllib.random import RandomRDDs

df = RandomRDDs.normalRDD(sc, 1000000, 10, 323).map(lambda x: (x, )).toDF(["x"])

并且您希望获得100条最佳记录:

n = 1000 # Number of records to take, lets say 1000

您可以估算出必须采取的记录比例:

q = 100 * (1 - n / float(df.count()))

估计各自的分位数:

import numpy as np
from pyspark.sql.functions import col


threshold = np.percentile(
    df.sample(False, 0.05).select("x").rdd.flatMap(lambda x: x).collect(),
    [q]
)[0]

result = df.where(col("x") > threshold)
result.write.format(...).save(...)

这根本不会随机播放并保持初始记录分发,但不保证确切的记录数量,并且需要对相关网络IO执行其他操作。