我使用Spark structured streaming
来处理从Kafka
读取的记录。这就是我想要实现的目标:
(a)每条记录都是Tuple2
类型的(Timestamp, DeviceId)
。
(b)我创建了一个静态Dataset[DeviceId]
,其中包含预期在DeviceId
中看到的所有有效设备ID(类型为Kafka
)的集合流。
(c)我需要写一个Spark structured streaming
查询
(i) Groups records by their timestamp into 5-minute windows
(ii) For each window, get the list of valid device IDs that were **not** seen in that window
例如,假设所有有效设备ID的列表为[A,B,C,D,E]
,并且某个5分钟窗口中的kafka记录包含设备ID [A,B,E]
。然后,对于该窗口,我正在查找的看不见的设备ID列表为[C,D]
。
问题
except()
公开的join()
和Dataset
方法。但是,他们都抛出了一个运行时异常,抱怨streaming Dataset
上都不支持这些操作。这是我的代码片段:
val validDeviceIds: Dataset[(DeviceId, Long)] = spark.createDataset[DeviceId](listOfAllDeviceIds.map(id => (id, 0L)))
case class KafkaRecord(timestamp: TimestampType, deviceId: DeviceId)
// kafkaRecs is the data stream from Kafka - type is Dataset[KafkaRecord]
val deviceIdsSeen = kafkaRecs
.withWatermark("timestamp", "5 minutes")
.groupBy(window($"timestamp", "5 minutes", "5 minutes"), $"deviceId")
.count()
.map(row => (row.getLong(0), 1L))
.as[(Long, Long)]
val unseenIds = deviceIdsSeen.join(validDeviceIds, Seq("_1"), "right_outer")
.filter(row => row.isNullAt(1))
.map(row => row.getLong(0))
最后一个语句抛出以下异常:
Caused by: org.apache.spark.sql.AnalysisException: Right outer join with a streaming DataFrame/Dataset on the left is not supported;;
提前致谢。
答案 0 :(得分:4)
火花结构化流媒体中join operations
的情况如下所示:可以将DataFrames
加入与static DataFrames
,以便进一步创建新的{{1} }。但streaming DataFrames
和outer joins
之间的streaming
支持有条件,而支持static Datasets
的right/left joins
不支持streaming Dataset
一般来说是结构化流媒体。结果,您遇到了AnalysisException,当您尝试使用流数据集创建连接静态数据集时抛出了line。作为我的话语的证明,你可以查看spark的源代码,在这个{{3}}异常抛出,表示你试过的操作不受支持。
我尝试使用静态stream of DataFrames
在DataFrames
上进行联接操作。
val streamingDf = sparkSession
.readStream
.format("kafka")
.option("kafka.bootstrap.servers", "127.0.0.1:9092")
.option("subscribe", "structured_topic")
.load()
val lines = spark.readStream
.format("socket")
.option("host", "localhost")
.option("port", 9999)
.load()
val staticDf = Seq((1507831462 , 100)).toDF("Timestamp", "DeviceId")
//Inner Join
streamingDf.join(staticDf, "Timestamp")
line.join(staticDf, "Timestamp")
//Left Join
streamingDf.join(staticDf, "Timestamp", "left_join")
line.join(staticDf, "Timestamp", "left_join")
如您所见,除了从Kafka
使用数据之外,我还从通过nc
(netcat)启动的套接字读取数据,它可以在您对流应用进行测试时显着简化生活。
这种方法适合我,Kafka
和socket
作为数据来源。
希望有所帮助。
答案 1 :(得分:0)
与对侧are just not supported的流数据集进行外连接:
- 有条件地支持流式传输和静态数据集之间的外连接。
- 不支持使用流式数据集的完全外部联接
- 不支持右侧带有流式数据集的外部联接
- 不支持左侧带有流数据集的右外连接
如果其他Dataset
很小,您可以使用Map
或类似结构broadcast
,并在UserDefinedFunction
内引用它。
val map: Broadcast[Map[T, U]] = ???
val lookup = udf((x: T) => map.value.get(x))
df.withColumn("foo", lookup($"_1"))