Apache kafka 卡夫卡流-过滤在时间窗口中频繁出现的消息
我正在尝试筛选任何消息,这些消息的密钥在长度为Apache kafka 卡夫卡流-过滤在时间窗口中频繁出现的消息,apache-kafka,apache-kafka-streams,Apache Kafka,Apache Kafka Streams,我正在尝试筛选任何消息,这些消息的密钥在长度为T的给定(跳跃)时间窗口中出现的频率超过阈值N 例如,在以下流中: #time, key 0, A 1, B 2, A 3, C 4, D 5, A 6, B 7, C 8, C 9, D 10, A 11, D 12, D 13, D 14, D 15, D 和N=2和T=3,结果应该是 0, A 2, A 7, C 8, C 9, D 11, D 12, D 13, D 14, D 15, D 或者,如果无法实现上述要求,则简化方法将仅用于在
T
的给定(跳跃)时间窗口中出现的频率超过阈值N
例如,在以下流中:
#time, key
0, A
1, B
2, A
3, C
4, D
5, A
6, B
7, C
8, C
9, D
10, A
11, D
12, D
13, D
14, D
15, D
和N=2
和T=3
,结果应该是
0, A
2, A
7, C
8, C
9, D
11, D
12, D
13, D
14, D
15, D
或者,如果无法实现上述要求,则简化方法将仅用于在满足阈值后过滤消息:
#time, key
2, A
8, C
11, D
12, D
13, D
14, D
15, D
卡夫卡流有可能吗
到目前为止,我已经尝试创建流的窗口计数
(KTable
)实例,并将其连接回原始流。我使用KTable#toStream((k,v)->k.key())
并执行返回到KTable
实例的操作,将窗口计数的键更改回原始键。这似乎引入了延迟,导致leftJoin
错过在超过阈值后非常接近的消息
final Serde<String> stringSerde = Serdes.String();
final Serde<Long> longSerde = Serdes.Long();
KStream<String, Long> wcount = source.groupByKey()
.count(TimeWindows.of(TimeUnit.SECONDS.toMillis(5)),"Counts")
.toStream((k,v) -> k.key());
// perform dummy aggregation to get KTable
KTable<String, Long> wcountTable = wcount.groupByKey(stringSerde, longSerde)
.reduce((aggValue, newValue) -> newValue,
"dummy-aggregation-store");
// left join and filter with threshold N=1
source.leftJoin(wcountTable, (leftValue, rightValue) -> rightValue,stringSerde, stringSerde )
.filter((k,v) -> v!=null)
.filter((k,v) -> v>1)
.print("output");
这会导致重复输出,因为每个向上插入wcount
都会触发一个事件 AFAIK这是Count Min Sketch算法的完美匹配。例如,请参见流库实现:
AFAIK这非常适合Count Min草图算法。例如,请参见流库实现:
这当然是可能的。您可以应用窗口聚合来收集列表中的所有原始数据(即,手动具体化窗口)。然后,应用计算窗口的平面贴图。如果尚未达到阈值,则不会发射任何东西。如果第一次达到阈值,则发出所有缓冲数据。对于所有计数大于阈值的flatMap的后续调用,您只会发出列表中最新的一个调用(您知道在调用flatMap之前,您确实发出了所有其他调用,即只发出新添加的调用)
注意:您需要禁用KTable缓存,即设置配置参数“cache.max.bytes.buffering”=0。否则,算法将无法正常工作
大概是这样的:
KStream windows=stream.groupByKey()
.合计(
/*具有空列表的init*/,
/*将值添加到agg*/,中的列表中,
TimeWindows.of()),
...)
.toStream();
KStream thresholdMetStream=windows.flatMap(
/*如果列表#大小<阈值
然后返回空列表,即不返回任何内容
elseif列表#大小==阈值
然后返回整个列表
else[列表#大小>阈值]
然后返回列表中的最后一个元素
*/);
这当然是可能的。您可以应用窗口聚合来收集列表中的所有原始数据(即,手动具体化窗口)。然后,应用计算窗口的平面贴图。如果尚未达到阈值,则不会发射任何东西。如果第一次达到阈值,则发出所有缓冲数据。对于所有计数大于阈值的flatMap的后续调用,您只会发出列表中最新的一个调用(您知道在调用flatMap之前,您确实发出了所有其他调用,即只发出新添加的调用)
注意:您需要禁用KTable缓存,即设置配置参数“cache.max.bytes.buffering”=0。否则,算法将无法正常工作
大概是这样的:
KStream windows=stream.groupByKey()
.合计(
/*具有空列表的init*/,
/*将值添加到agg*/,中的列表中,
TimeWindows.of()),
...)
.toStream();
KStream thresholdMetStream=windows.flatMap(
/*如果列表#大小<阈值
然后返回空列表,即不返回任何内容
elseif列表#大小==阈值
然后返回整个列表
else[列表#大小>阈值]
然后返回列表中的最后一个元素
*/);
谢谢,我的工作(几乎)符合要求。对于a,除了在新时间窗口开始时发生的事件(当相关事件位于前一个窗口中时)外,这是有效的。对于跳转窗口,输出流中存在重复,因为多个窗口可以包含单个事件触发序列。因此,我选择使用处理器API和窗口持久存储实现一个解决方案。谢谢,我(几乎)按预期工作。对于a,除了在新时间窗口开始时发生的事件(当相关事件位于前一个窗口中时)外,这是有效的。对于跳转窗口,输出流中存在重复,因为多个窗口可以包含单个事件触发序列。因此,我选择使用处理器API和窗口持久存储实现一个解决方案。
source.join(wcount, (leftValue, rightValue) -> rightValue, JoinWindows.of(TimeUnit.SECONDS.toMillis(5)),stringSerde, stringSerde, longSerde)
.filter((k,v) -> v!=null)
.filter((k,v) -> v>1)
.print("output");