我正在从Kafka接收DStream,我想按键将所有消息分组在某个滑动窗口中。
重点是,该窗口必须基于每条消息中提供的时间戳(单独的字段):
Message structure
--------------------------
key1, ..., ..., 1557678233
key1, ..., ..., 1557678234
key2, ..., ..., 1557678235
因此,我想考虑消息中每个键timestamp of the first message
-timestamp of the last message
<= 5分钟
从这个question中可以看出,这是不可行的,因为Spark仅计算事件的系统时间。那边的那个人建议使用updateStateByKey
,这对我来说不太清楚...
也许我们可以使用另一种方法来实现这一目标?
在combiners
函数的combineByKey
中包括时间戳差异,并通过持续时间阈值进一步求和和过滤该怎么办?
请对此发表您的看法,或者,如果您有机会面对同样的问题,请分享您的解决方案...
谢谢!
答案 0 :(得分:1)
有可能吗?毫无疑问。 Apache Beam(其中包括Apache Spark backend)可以轻松处理此类操作。
但是,除非您拥有大量开发资源和大量专有技术,否则绝对不是您要自己实现的目标。如果有的话,您可能一开始就不会问这个问题。
处理大量晚情况,无序事件以及从节点故障中恢复可能是非常棘手的事情。
此外,在实际实现之前,它已经过时了-DStream
已经被认为是旧版API,并且很可能早日淘汰它。同时Structured Streaming已经可以立即处理事件时间窗口。
答案 1 :(得分:0)
使用以下示例数据进行了测试,我认为时间戳记采用的是时代格式-
[key1, ..., ..., 1557678233]
[key1, ..., ..., 1557678234]
[key2, ..., ..., 1557678235]
[key2, ..., ..., 1557678240]
[key2, ..., ..., 1557678271]
[key3, ..., ..., 1557678635]
[key3, ..., ..., 1557678636]
[key3, ..., ..., 1557678637]
[key3, ..., ..., 1557678638]
[key3, ..., ..., 1557678999]
//-创建udf以返回是否需要处理或拒绝记录
scala> spark.udf.register("recordStatusUDF", (ts:String) => {
| val ts_array = ts.split(",",-1)
| if ((ts_array.max.trim.toLong - ts_array.min.trim.toLong) <= 300) {
| "process"
| }
| else { "reject" }
| })
res83: org.apache.spark.sql.expressions.UserDefinedFunction = UserDefinedFunction(<function1>,StringType,Some(List(StringType)))
//-创建架构
scala> val schema = StructType(Seq(StructField("key", StringType, true),StructField("col2", StringType, true),StructField("col3", StringType, true),StructField("epoch_ts", StringType, true)))
schema: org.apache.spark.sql.types.StructType = StructType(StructField(key,StringType,true), StructField(col2,StringType,true), StructField(col3,StringType,true), StructField(epoch_ts,StringType,true))
//-创建数据框
scala> spark.createDataFrame(rdd,schema).createOrReplaceTempView("kafka_messages")
scala> spark.sql(s""" select x.key, recordStatusUDF(x.ts) as action_ind from ( select key, concat_ws(",", collect_list(epoch_ts)) as ts from kafka_messages group by key)x """).createOrReplaceTempView("action")
scala> val result = spark.sql(s""" select km.* from kafka_messages km inner join action ac on km.key = ac.key and ac.action_ind = "process" """)
result: org.apache.spark.sql.DataFrame = [key: string, col2: string ... 2 more fields]
scala> result.show(false)
+----+----+----+-----------+
|key |col2|col3|epoch_ts |
+----+----+----+-----------+
|key1| ...| ...| 1557678233|
|key1| ...| ...| 1557678234|
|key2| ...| ...| 1557678235|
|key2| ...| ...| 1557678240|
|key2| ...| ...| 1557678271|
+----+----+----+-----------+
您可以在每个rdd(kafka消息)上使用上述代码。希望这会有所帮助。