我正在使用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执行此操作?
由于
答案 0 :(得分:0)
遵循当前文档(Spark 2.1.1)
两个流式数据集之间的任何类型的连接还没有 支撑。
此时此刻,我认为你需要依赖@ igodfried的回答提出的Spark Streaming。
答案 1 :(得分:0)
我希望你得到你的解决方案。如果没有,那么您可以尝试从两个主题创建两个KStream,然后加入这些KStream并将连接的数据放回一个主题。现在,您可以使用Spark Structured Streaming将连接的数据作为一个DataFrame读取。现在,您将能够对连接的数据应用所需的任何转换。由于结构化流式传输不支持两个流式数据框架的连接,因此您可以按照此方法完成任务。
答案 2 :(得分:0)
前段时间我遇到了类似的要求:我有2个流必须根据某些标准“加入”在一起。我使用的是一个名为 mapGroupsWithState 的函数。
这个函数的作用(简言之,下面参考的更多细节)是以(K,V)的形式获取流,并根据每对的密钥将其元素累积在一个公共状态上。然后你可以在状态为完成(根据你的应用程序)时告诉Spark,或者甚至对不完整的状态超时。
基于您的问题的示例:
将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
对您的数据执行某些操作(我更喜欢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")
使用 mapGroupsWithState 功能(我将向您展示基本想法;您必须根据需要定义 myGrpFunct ):
keyPairsStream
.mapGroupsWithState(GroupStateTimeout.ProcessingTimeTimeout())(myGrpFunct)
多数民众赞成!如果您正确实施 myGrpFunct ,您将拥有一个合并数据流,您可以进一步转换,如下所示:
[ “汤姆”,{ “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)。