使用sqlcontext进行spark并行查询

时间:2016-11-15 14:39:47

标签: apache-spark parallel-processing pyspark amazon-emr bigdata

我们正试图在EMR上运行ETL。在S3中有大约2000万个事件作为gzipped json线。它们总共约有30个文件。我正在使用pyspark。

这是代码,

def value_to_list(columns):
    def value_map(values):
        data = []
        for val in values:
            d = val.asDict()
            data.append([d[column] for column in columns])
        return data

    return value_map


def main():
    sc = SparkContext()
    sql_context = SQLContenxt(sc)

    all_events = SQLContenxt(sc).read.json("s3n://...", schema=StructType(fields), timestampFormat="yyyy-MM-dd HH:mm:ss")
    all_events.registerTempTable('allevents')

    for event_type in event_types:
        process_event(sc, event_type, "allevents")


def process_event(sparkcontext, etype, tablename):
    query = "select app_id, source, type, {time_cols}, count(*) as total " \
            "from {table} where  type = '{event_type}' " \
            "group by app_id, source, type, {time_cols}"
    time_cols_spec = [('hour', 'day', 'month', 'year'),
                      ('day', 'month', 'year'),
                      ('month', 'year'),
                      ('year')]

    for time_cols in time_cols_spec:
        final_query = query.format(time_cols=", ".join(time_cols),
                                   table=tablename,
                                   event_type=etype)
        dataframe = sql_context.sql(final_query)

        dataframe.rdd.groupBy(lambda r: r['app_id'])\
            .mapValues(value_to_list(['source'] + time_cols))\
            .saveAsTextFile("s3n://...")

因此,我们有大约30种类型的活动,每次活动我都会按小时,日,月和年的4种组合进行汇总。所以4查询每个。我们总共有大约2000M的活动。

我正在运行

  • AWS EMR(5.0.3)
  • Apache Spark 2.0.1
  • 1名主人,2名工人
  • 每台机器都是m3.2xlarge
  • 总内存为90GB

问题是,最后的保存需要很长时间。上次我查询它花了14个小时进行2次组合和一次活动​​:(

我知道我不是平行时尚。循环是顺序的。并且有2个循环。但我希望rdd,groupBymapValues能够并行运行。当我看到事件时间表时,我看到saveAsTextFile占据了99%的时间。可能是因为火花懒散地执行了。

我需要使这个过程平行且快速。我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:2)

您可以应用4种主要优化:

  1. 您正在对普通json文件执行聚合,这些文件未针对进行查询进行优化。将它们重写为镶木地板,按事件类型重新分区并在S3上存储 - 它们将占用更少的空间,您的应用程序将获得良好的速度提升。

  2. 提高并行度。没有必要在这样强大的虚拟机上安装驱动程序(主服务器),而是生成一个较小的实例(例如m3.medium),并为工作人员使用所有3个大实例。

  3. 将RDD API调用替换为Dataframe:.rdd.groupBy().mapValues()可以替换为.groupBy(dataframe.app_id).agg(collect_list()),然后替换为某些映射。

  4. 您可以对(小时,日,月,年)数据集的原始数据执行查询,然后使用此聚合来调用给定事件的所有剩余查询。