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");