Spark dense_rank窗口函数 - 没有partitionBy子句

时间:2017-01-02 16:49:01

标签: sql-server scala apache-spark yarn hadoop2

我正在使用Spark 1.6.2,Scala 2.10.5和Java 1.7。

我们的用例需要我们在超过2亿行的数据集上执行dense_rank()而不使用partitionBy子句,只使用orderBy子句。这当前在MSSQL中运行,大约需要30分钟才能完成。

我在Spark中实现了等效逻辑,如下所示:

val df1 = hqlContext.read.format("jdbc").options(
  Map("url" -> url, "driver" -> driver,
  "dbtable" -> "(select * from OwnershipStandardization_PositionSequence_tbl) as ps")).load()

df1.cache()

val df1_drnk = df1.withColumn("standardizationId",denseRank().over(Window.orderBy("ownerObjectId","securityId","periodId")))

我以Yarn-cluster模式提交作业,如下所示。我有一个2节点Hadoop 2.6集群,每个集群有4个vCore和32 GB内存。

spark-submit --class com.spgmi.csd.OshpStdCarryOver --master  yarn --deploy-mode cluster --conf spark.yarn.executor.memoryOverhead=3072 --num-executors 2 --executor-cores 3 --driver-memory 7g --executor-memory 16g --jars $SPARK_HOME/lib/datanucleus-api-jdo-3.2.6.jar,$SPARK_HOME/lib/datanucleus-core-3.2.10.jar,$SPARK_HOME/lib/datanucleus-rdbms-3.2.9.jar,/usr/share/java/sqljdbc_4.1/enu/sqljdbc41.jar --files $SPARK_HOME/conf/hive-site.xml $SPARK_HOME/lib/spark-poc2-14.0.0.jar

在日志中,我可以看到来自MSSQL的大约200密耳行的表格正在导入&在15分钟内在Spark中缓存。我看到大约5 GB的内存在这个阶段被使用,其中一个执行程序仍有大约6.2 GB的内存,而另一个执行器上有11 GB的内存空闲。

但是,在dense_rank()的步骤总是失败,并且#34;超出了GC开销限制"几分钟后出错。我甚至将驱动程序内存设置为高达7g,您可以在上面的spark-submit命令中注意到。但是,无济于事! 当然,据我所知,缺少partitionBy子句实际上是在Spark中造成了麻烦。但不幸的是,这是我们需要处理的用例。

请你在这里说明一些事情吗?我错过了什么吗?有没有在Spark中使用dense_rank窗口函数的替代方法?例如,使用" zipWithIndex"本论坛其他地方的专家之一建议的功能?它会产生与dense_rank相同的结果,因为我理解" zipWithIndex"复制row_number()函数而不是dense_rank?

任何有用的建议表示赞赏! 非常感谢!

1 个答案:

答案 0 :(得分:3)

这里有两个不同的问题:

  • 您可以通过JDBC连接加载数据,而无需提供分区列或分区谓词。这使用单个执行程序线程加载所有数据。

    通过使用现有列之一或提供人工密钥,这个问题通常很容易解决。

  • 您使用没有partitionBy的窗口函数。因此,所有数据都会重新整理到单个分区,在本地排序,并使用单个线程进行处理。

    一般情况下,没有通用解决方案只能使用Dataset API来解决这个问题,但您可以使用一些技巧:

    • 创建反映所需记录顺序的人工分区。我在回答Avoid performance impact of a single partition mode in Spark window functions

      时描述了这种方法

      在您的情况下可以使用类似的方法,但它需要多步骤过程,相当于下面描述的过程。

    • 使用关联方法,您可以对已排序的RDD进行两次单独扫描(应该可以执行类似的操作而不转换为Dataset)和其他操作:

      • 计算每个分区的部分结果(在您的情况下,给定分区的等级)。
      • 收集所需的摘要(在您的情况下,分区边界和每个分区的累积排名值)。
      • 执行第二次扫描以更正前面分区的部分聚合。

    这种方法的一个例子,可以轻松调整以适合您的情况,可以在How to compute cumulative sum using Spark

  • 找到