我有一个使用Spark(带有Spark Job Server)的应用程序,该应用程序使用Cassandra存储。我当前的设置是在client
下运行的master=local[*]
模式。因此,只有一个Spark执行程序,它也是使用机器所有8个内核的驱动程序进程。我有一个在同一台计算机上运行的Cassandra实例。
Cassandra表的主键的格式为((datasource_id,date),clustering_col_1 ... clustering_col_n),其中date是单日,格式为“ 2019-02-07”,并且是复合分区键的一部分
在我的Spark应用程序中,我正在运行如下查询:
df.filter(col("date").isin(days: _*))
在Spark物理计划中,我注意到这些过滤器以及“ datasource_id”分区键的过滤器均被推送到Cassandra CQL查询中。
对于我们最大的数据源,我知道分区的大小约为30MB。因此,我在Spark Job Server配置中具有以下设置:
spark.cassandra.input.split.size_in_mb = 1
但是,我注意到在Cassandra加载步骤中没有并行化。尽管有多个大于1MB的Cassandra分区,但是没有创建其他的spark分区。只有一个任务可以在单个核心上执行所有查询,因此需要大约20秒钟的时间来加载对应于大约100万行的1个月日期范围内的数据。
我尝试了以下替代方法:
df union days.foldLeft(df)((df: DataFrame, day: String) => {
df.filter(col("date").equalTo(day))
})
这确实为cassandra中的每个“ day”分区创建了一个火花分区(或任务)。但是,对于cassandra分区的大小较小的较小数据源,就创建过多的任务以及由于它们的协调而造成的开销而言,该方法被证明是相当昂贵的。对于这些数据源,将许多Cassandra分区集中到一个spark分区中完全可以。因此,为什么我认为使用spark.cassandra.input.split.size_in_mb
配置对于处理小型和大型数据源都是有用的。
我的理解错误吗?为了使此配置生效,我还缺少其他东西吗?
P.S。我还阅读了有关使用joinWithCassandraTable的答案。但是,我们的代码依赖于使用DataFrame。同样,从CassandraRDD转换为DataFrame对我们来说也不可行,因为我们的架构是动态的,无法使用案例类进行指定。