Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark 在Spark Streaming中加入Kafka和Cassandra数据帧会忽略C*谓词下推_Apache Spark_Cassandra_Apache Kafka_Spark Streaming_Spark Cassandra Connector - Fatal编程技术网

Apache spark 在Spark Streaming中加入Kafka和Cassandra数据帧会忽略C*谓词下推

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

意图

我正在通过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.终止协议() } 环境

  • 火花1.6
  • 卡桑德拉2.1.12
  • 卡桑德拉火花连接器1.5-RC1
  • 卡夫卡0.8.2.2
解决方案

来自Apache Cassandra ML的DataStax Spark连接器讨论

我学到了以下几点:

引用Russell Spitzer的话

  • 这不是谓词下推的情况。这是分区键列上的联接。目前只有joinWithCassandraTable支持这种直接连接,尽管我们正在研究一些方法,试图在Spark中自动完成这种连接

  • 可以从任何可以应用模式的RDD创建数据帧。最简单的方法可能是将joinedRDD[x,y]映射到Rdd[JoinedCaseClass],然后调用toDF(这将需要导入sqlContext隐式)。有关更多信息,请参见此处

  • 因此,现在的实际实现类似于

    //将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]再次转换为有效的数据帧。对此有何想法,或者我应该发布一个新问题?