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计算累积总和中找到
-