关于sql server:Spark density_rank窗口函数-不带有partitionBy子句

Spark dense_rank window function - without a partitionBy clause

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

我们的用例需要我们在不使用partitionBy子句的情况下,对超过2亿行的数据集执行density_rank(),仅使用orderBy子句。目前,该程序在MSSQL中运行,大约需要30分钟才能完成。

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

1
2
3
4
5
6
7
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内存。

1
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的大约2千万行的表


这里有两个不同的问题:

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

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

  • 您使用不带partitionBy的窗口功能。结果,所有数据都重新组合到单个分区,在本地进行排序,并使用单个线程进行处理。

    通常,没有通用解决方案可以仅使用Dataset API来解决该问题,但是您可以使用一些技巧:

    • 创建反映所需记录顺序的人工分区。我在回答"避免在Spark窗口函数中避免单个分区模式的性能影响"的答案中描述了此方法。

      在您的情况下,可以使用类似的方法,但它需要多步处理,等效于以下所述。

    • 使用关联方法,您可以对已排序的RDD使用两次单独的扫描(也可以在不从Dataset转换的情况下执行类似的操作)和其他操作:

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

    此方法的一个示例,可以轻松调整以适合您的情况,可在如何使用Spark计算累积总和中找到