卡夫卡流中的状态过滤/ flatMapValues?

时间:2019-04-15 19:33:31

标签: apache-kafka apache-kafka-streams

我正在尝试编写一个简单的Kafka Streams应用程序(针对Kafka 2.2 / Confluent 5.2),将具有至少一次语义的输入主题转换为一次精确的输出流。我想对以下逻辑进行编码:

  • 对于每个具有给定密钥的消息:
    • 从消息值中的字符串字段读取消息时间戳记
    • 从本地状态存储中检索我们之前为该密钥所见的最大时间戳
      • 如果消息时间戳小于或等于状态存储中的时间戳,请不要发出任何消息
      • 如果时间戳大于状态存储中的时间戳,或者状态存储中不存在密钥,则发出消息并使用消息的密钥/时间戳更新状态存储

(这肯定会基于我们从上游系统获得的订购保证而提供正确的结果;我在这里不想做任何不可思议的事情。)

起初我以为我可以使用Kafka Streams flatMapValues operator来做到这一点,它可以让您使用相同的键将每个输入消息映射到零个或多个输出消息。但是,该文档明确警告:

  

这是一个无记录的逐记录操作(请参阅transformValues(ValueTransformerSupplier,String ...)以进行有状态值转换。

这听起来很有希望,但是transformValues documentation不清楚如何在每个输入消息中发出零或一个输出消息。除非示例中的// or null试图这么说?

flatTransform看上去也很有前途,但是我不需要操纵密钥,并且在可能的情况下,我希望避免重新分区。

有人知道如何正确执行这种过滤吗?

1 个答案:

答案 0 :(得分:2)

您可以使用Transformer来实现如上所述的有状态操作。为了不向下游传播消息,您需要从null Java文档中提到的transform方法返回Transformer。您可以通过processorContext.forward(key, value)管理传播。下面提供了简化的示例

kStream.transform(() -> new DemoTransformer(stateStoreName), stateStoreName)

public class DemoTransformer implements Transformer<String, String, KeyValue<String, String>> {
    private ProcessorContext processorContext;
    private String stateStoreName;
    private KeyValueStore<String, String> keyValueStore;

    public DemoTransformer(String stateStoreName) {
        this.stateStoreName = stateStoreName;
    }

    @Override
    public void init(ProcessorContext processorContext) {
        this.processorContext = processorContext;
        this.keyValueStore = (KeyValueStore) processorContext.getStateStore(stateStoreName);
    }

    @Override
    public KeyValue<String, String> transform(String key, String value) {
        String existingValue = keyValueStore.get(key);
        if (/* your condition */) {
            processorContext.forward(key, value);
            keyValueStore.put(key, value);
        }

        return null;
    }

    @Override
    public void close() {
    }
}
相关问题