kafka流进行本地聚合

时间:2019-10-22 06:16:20

标签: apache-kafka-streams

我正在尝试进行本地聚合。

输入主题包含包含多个元素的记录,我正在使用flatmap用另一个键(此处为element_id)将记录拆分为多个记录。这将触发重新分区,因为我稍后将在流过程中应用分组进行聚合。 问题:此分区主题中的记录太多,应用程序无法处理它们(延迟不断增加)。

以下是传入数据的示例

键:another ID

值:

{
  "cat_1": {
    "element_1" : 0,
    "element_2" : 1,
    "element_3" : 0
  },
  "cat_2": {
    "element_1" : 0,
    "element_2" : 1,
    "element_3" : 1
  }
}

以及所需聚合结果的示例: 密钥:element_2 值:

{
  "cat_1": 1,
  "cat_2": 1
}

因此,我想进行第一个“本地聚合”并停止拆分传入的记录,这意味着我想在30秒的窗口中本地聚合所有元素(不进行重新分区),然后为每个元素生成结果一个话题。稍后,消耗此主题的流将在更高级别聚合。

我正在使用Stream DSL,但是我不确定是否足够。我尝试使用允许我从Processor API中受益的process()transform()方法,但是我不知道如何正确地在标点符号中生成某些记录或将记录放入流中。

我该如何实现?谢谢

1 个答案:

答案 0 :(得分:1)

transform()返回一个KStream,您可以在其中调用to()将结果写入主题。

stream.transform(...).to("output_topic");

在标点符号中,您可以调用context.forward()向下游发送记录。您仍然需要调用to()才能将转发的记录写入主题。

要实现自定义聚合,请考虑以下伪ish代码:

builder = new StreamsBuilder();
final StoreBuilder<KeyValueStore<Integer, Integer>> keyValueStoreBuilder =
    Stores.keyValueStoreBuilder(Stores.persistentKeyValueStore(stateStoreName),
                                Serdes.Integer(),
                                Serdes.Integer());
builder.addStateStore(keyValueStoreBuilder);

stream = builder.stream(topic, Consumed.with(Serdes.Integer(), Serdes.Integer()));
stream.transform(() -> 
    new Transformer<Integer, Integer, KeyValue<Integer, Integer>>() {

    private KeyValueStore<Integer, Integer> state;

    @Override
    public void init(final ProcessorContext context) {
        state = (KeyValueStore<Integer, Integer>) context.getStateStore(stateStoreName);
        context.schedule(
            Duration.ofMinutes(1), 
            PunctuationType.STREAM_TIME, 
            timestamp -> {
                // You can get aggregates from the state store here 

                // Then you can send the aggregates downstream 
                // with context.forward();

                // Alternatively, you can output the aggregate in the 
                // transform() method as shown below
            }
        );
    }

    @Override
    public KeyValue<Integer, Integer> transform(final Integer key, final Integer value) {
        // Get existing aggregates from the state store with state.get().

        // Update aggregates and write them into the state store with state.put().

        // Depending on some condition, e.g., 10 seen records, 
        // output an aggregate downstream by returning the output.
        // You can output multiple aggregates by using KStream#flatTransform().

        // Alternatively, you can output the aggregate in a 
        // punctuation as shown above
    }

    @Override
    public void close() {
    }
}, stateStoreName)

使用此手动聚合,您可以在同一流应用中实施更高级别的聚合,并利用重新分区。

process()是终端操作,即不返回任何内容。