Kafka Streams - 过滤在时间窗口中频繁出现的消息

时间:2017-10-19 10:34:19

标签: apache-kafka apache-kafka-streams

我正在尝试过滤任何在长度为N的给定(跳跃)时间窗口中密钥出现频率超过阈值T的邮件。

例如,在以下流中:

#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

Kafka Streams可以实现吗?

到目前为止,我已尝试创建流的windowed countKTable的实例)并将其连接回原始流。我使用windowed countKTable#toStream((k,v) -> k.key())的密钥更改回原始密钥,然后执行dummy aggregation返回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");

我还尝试使用适当的窗口执行KStream - KStream联接(省略虚拟聚合):

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

这导致重复输出,因为每个UPSERT进入wcount会触发一个事件。

2 个答案:

答案 0 :(得分:1)

这当然是可能的。您可以应用窗口聚合来收集列表中的所有原始数据(即,您手动实现窗口)。然后,应用评估窗口的flatMap。如果尚未达到阈值,则不发出任何内容。如果第一次满足阈值,则发出所有缓冲数据。对于计数大于阈值的flatMap的所有进一步调用,您只发出列表中的最新一个(您知道您之前发出的所有其他调用flatMap,即仅发出新添加的一个)。 / p>

  

注意:您需要禁用KTable缓存,即设置配置参数“cache.max.bytes.buffering”= 0.否则,算法将无法正常工作。

这样的事情:

KStream<Windowed<K>, List<V>> windows = stream.groupByKey()
                                              .aggregate(
                                                /*init with empty list*/,
                                                /*add value to list in agg*/,
                                                TimeWindows.of()...),
                                                ...)
                                                .toStream();
KStream<K,V> thresholdMetStream = windows.flatMap(
                                            /* if List#size < threshold
                                               then return empty-list, ie, nothing
                                               elseif List#size == threshold
                                               then return whole list
                                               else [List#size > threshold]
                                               then return last element from list
                                            */);

答案 1 :(得分:0)

AFAIK这是Count-Min-Sketch算法的最佳选择。参见例如stream-lib实现:

https://github.com/addthis/stream-lib