Apache spark 在Spark Streaming中加入Kafka和Cassandra数据帧会忽略C*谓词下推
意图 我正在通过direct stream接收来自卡夫卡的数据,并希望用来自卡桑德拉的数据丰富这些信息。卡夫卡消息(Protobufs)被解码成数据帧,然后与来自卡桑德拉(Cassandra)的一个(假定是预过滤的)DF连接。(Kafka)流式处理批量大小与原始C*数据的关系是[数条流式处理消息与数百万个C*行],但连接始终只为每条消息生成一个结果[1:1]。在连接之后,生成的DF最终存储到另一个C*表中 问题 即使我在完整的Cassandra主键上连接两个DFs并将相应的筛选器按到C*,Spark似乎在实际连接之前将整个C*数据集加载到内存中(我希望通过使用筛选器/谓词下推来防止这种情况)。这导致了大量的洗牌和任务的产生,因此“简单”的加入需要永远 def main(参数:数组[字符串]){ val conf=new SparkConf() .setAppName(“测试”) .set(“spark.cassandra.connection.host”,“xxx”) .set(“spark.cassandra.connection.keep_live_ms”,“30000”) .setMaster(“本地[*]”) val ssc=新的StreamingContext(形态,秒(10)) ssc.sparkContext.setLogLevel(“信息”) //初始化卡夫卡 val kafkaTopics=设置[字符串](“xxx”) val kafkaParams=Map[String,String]( “metadata.broker.list”->“xxx:32000,xxx:32000,xxx:32000,xxx:32000”, “自动偏移重置”->“最小值”) //卡夫卡河 val messages=KafkaUtils.createDirectStream[String,MyMsg,StringDecoder,MyMsgDecoder](ssc,kafkaParams,kafkaTopics) //对司机执行 messages.foreachRDD{rdd=> //创建SQLContext的实例 val sqlContext=SQLContextSingleton.getInstance(rdd.sparkContext) 导入sqlContext.implicits_ //映射MyMsg-RDD val MyMsgRdd=rdd.map{case(key,MyMsg)=>(MyMsg)} //将RDD[MyMsg]转换为数据帧 val MyMsgDf=MyMsgRdd.toDF() .选择( $“prim1Id”作为“prim1\u id”, $“prim2Id”作为“prim2\u id”, $... ) //从C*数据源加载数据帧 val base_data=base_data_df.getInstance(sqlContext) //prim1Id和prim2Id上的左联接 val joinedf=MyMsgDf.join(基本数据, MyMsgDf(“prim1\U id”)==基本数据(“prim1\U id”)&& MyMsgDf(“prim2\U id”)==基本数据(“prim2\U id”),“左”) .filter(基本数据(“prim1\u id”).isin(MyMsgDf(“prim1\u id”)) &&基本数据(“prim2\U id”).isin(MyMsgDf(“prim2\U id”)) joinedDf.show() joinedDf.printSchema() //选择相关字段 //坚持 } //开始计算 ssc.start() ssc.终止协议() } 环境Apache spark 在Spark Streaming中加入Kafka和Cassandra数据帧会忽略C*谓词下推,apache-spark,cassandra,apache-kafka,spark-streaming,spark-cassandra-connector,Apache Spark,Cassandra,Apache Kafka,Spark Streaming,Spark Cassandra Connector,意图 我正在通过direct stream接收来自卡夫卡的数据,并希望用来自卡桑德拉的数据丰富这些信息。卡夫卡消息(Protobufs)被解码成数据帧,然后与来自卡桑德拉(Cassandra)的一个(假定是预过滤的)DF连接。(Kafka)流式处理批量大小与原始C*数据的关系是[数条流式处理消息与数百万个C*行],但连接始终只为每条消息生成一个结果[1:1]。在连接之后,生成的DF最终存储到另一个C*表中 问题 即使我在完整的Cassandra主键上连接两个DFs并将相应的筛选器按到C*,Spa
- 火花1.6
- 卡桑德拉2.1.12
- 卡桑德拉火花连接器1.5-RC1
- 卡夫卡0.8.2.2
//将myMsg RDD与myCassandraTable连接起来
val joinedsgrdd=myMsgRdd.joinewithcassandratable(
“键空间”,
“我的可处置”,
所有栏目,
一些专栏(
“prim1_id”,
“prim2_id”
)
).map{case(myMsg,cassandraRow)=>
JoinedMsg(
foo=myMsg.foo
bar=cassandraRow.bar
)
}
//将RDD[JoinedMsg]转换为数据帧
val myjoinedf=joinedsgrdd.toDF()
您是否尝试加入Cassandratable?它应该下推到C*您正在寻找的所有键…长话短说,它不是可以有效下推的东西。您使用的谓词是动态的,如果不逐个记录执行查询,则无法将其表示为简单条件。另一个问题是由isin
生成的逻辑析取,通常很难推送,如果Spark下推不支持任何更改。如果要避免混乱,最好是分区并缓存base_数据
和分区MyMsgDF
好的,谢谢!是的,这正是我所怀疑的。我还考虑过收集prim1_id和prim2_id,并在连接之前使用它来缩小base_数据的范围,但是如果无法使用isin有效地向下推送谓词列表,这也不会有任何帮助。缓存base_数据实际上是不可行的,高更改率和非常大的大小。您认为有更好的方法来达到最初的目的吗?您可以尝试直接查询数据库isin
可以有效地重写为扁平结构上的等式,后跟distinct。关于<代码> ISIN <代码>请务必仔细检查一下,我可能错了。实际上,我没有直接去DF方法,也没有考虑加入Casaband Realabl。不过看起来很有希望!好的,prima vista这看起来相当不错,但我似乎不知道如何将结果CassandraJoinRDD[MyMsg,CassandraRow]再次转换为有效的数据帧。对此有何想法,或者我应该发布一个新问题?