Spark Structured Streaming - 比较两个流

时间:2017-06-09 05:01:56

标签: apache-spark spark-streaming

我正在使用Kafka和Spark 2.1 Structured Streaming。我有两个主题与json格式的数据,例如:

topic 1:

{"id":"1","name":"tom"}
{"id":"2","name":"mark"}

topic 2:

{"name":"tom","age":"25"}
{"name":"mark","age:"35"}

我需要在标签上比较Spark中的这两个流:name和当值相等时执行一些额外的定义/函数。

如何使用Spark Structured Streaming执行此操作?

由于

4 个答案:

答案 0 :(得分:0)

遵循当前文档(Spark 2.1.1)

  

两个流式数据集之间的任何类型的连接还没有   支撑。

参考:https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html#unsupported-operations

此时此刻,我认为你需要依赖@ igodfried的回答提出的Spark Streaming。

答案 1 :(得分:0)

我希望你得到你的解决方案。如果没有,那么您可以尝试从两个主题创建两个KStream,然后加入这些KStream并将连接的数据放回一个主题。现在,您可以使用Spark Structured Streaming将连接的数据作为一个DataFrame读取。现在,您将能够对连接的数据应用所需的任何转换。由于结构化流式传输不支持两个流式数据框架的连接,因此您可以按照此方法完成任务。

答案 2 :(得分:0)

前段时间我遇到了类似的要求:我有2个流必须根据某些标准“加入”在一起。我使用的是一个名为 mapGroupsWithState 的函数。

这个函数的作用(简言之,下面参考的更多细节)是以(K,V)的形式获取流,并根据每对的密钥将其元素累积在一个公共状态上。然后你可以在状态为完成(根据你的应用程序)时告诉Spark,或者甚至对不完整的状态超时。

基于您的问题的示例:

  1. 将Kafka主题读入Spark Stream:

    val rawDataStream: DataFrame = spark.readStream
    .format("kafka")
    .option("kafka.bootstrap.servers", bootstrapServers)
    .option("subscribe", "topic1,topic2") // Both topics on same stream!
    .option("startingOffsets", "latest")
    .option("failOnDataLoss", "true")
    .load()
    .selectExpr("CAST(value AS STRING) as jsonData") // Kafka sends bytes
    
  2. 对您的数据执行某些操作(我更喜欢SQL,但您可以使用DataFrame API)将每个元素转换为键值对:

    spark.sqlContext.udf.register("getKey", getKey) // You define this function; I'm assuming you will be using the name as key in your example.
    
    val keyPairsStream = rawDataStream
    .sql("getKey(jsonData) as ID, jsonData from rawData")
    .groupBy($"ID")
    
  3. 使用 mapGroupsWithState 功能(我将向您展示基本想法;您必须根据需要定义 myGrpFunct ):

    keyPairsStream
    .mapGroupsWithState(GroupStateTimeout.ProcessingTimeTimeout())(myGrpFunct)
    
  4. 多数民众赞成!如果您正确实施 myGrpFunct ,您将拥有一个合并数据流,您可以进一步转换,如下所示:

  5. [ “汤姆”,{ “id为”: “1”, “姓名”: “汤姆”},{ “名称”: “汤姆”, “年龄”: “25”}]

    [ “标记”,{ “id为”: “2”, “姓名”: “标记”},{ “名称”: “标记”, “年龄” 35" }]

    希望这有帮助!

    出色的解释,其中包含一些代码段:http://asyncified.io/2017/07/30/exploring-stateful-streaming-with-spark-structured-streaming/

答案 3 :(得分:-1)

一种方法是将两个流转换为(K,V)格式。在您的情况下,这可能采取(name,otherJSONData)的形式。有关加入流的更多信息和位于Spark documentation的示例,请参阅here。然后在两个流上进行连接,然后在新连接的流上执行任何功能。如果需要,您可以使用map返回(K,(W,V))到(K,V)。