使用kafka流基于消息密钥将消息发送到主题

时间:2019-09-17 17:57:16

标签: java apache-kafka apache-kafka-streams

我希望能够基于消息密钥的密钥将Kafkastream中的所有记录发送到另一个主题。 例如Kafka中的流包含名称作为键和记录作为值。我想根据记录的关键将这些记录分配到不同的主题

data:(jhon-> {jhonsRecord}),(sean-> {seansRecord}),(mary-> {marysRecord}),(jhon-> {jhonsRecord2}), 预期

  • topic1:名称:jhon->(jhon-> {jhonsRecord}),(jhon-> {jhonsRecord2})
  • topic2:sean->(sean-> {seansRecord})
  • topic3:mary->(mary-> {marysRecord})

下面是我现在执行此操作的方式,但是由于名称列表比较笨拙,因此速度很慢。另外,即使有一些记录,我也需要遍历整个列表。请提出修复建议

    for( String name : names )
    {
        recordsByName.filterNot(( k, v ) -> k.equalsIgnoreCase(name)).to(name);
    } 

3 个答案:

答案 0 :(得分:5)

我认为您应该使用KStream::to(final TopicNameExtractor<K, V> topicExtractor)函数。它使您能够计算每条消息的主题名称。

示例代码:

final KStream<String, String> stream = ???;
stream.to((key, value, recordContext) -> key);

答案 1 :(得分:1)

我认为您正在寻找的是KStream#branch

以下未经测试,但显示了总体思路

// get a list of predicates to branch a topic on
final List<String> names = Arrays.asList("jhon", "sean", "mary");
final Predicate[] predicates = names.stream()
    .map((Function<String, Predicate<String, Object>>) n -> (s, o) -> s.equals(n))
    .toArray(Predicate[]::new);

// example input
final KStream<Object, Object> stream = new StreamsBuilder().stream("names");

// split the topic
KStream<String, Object>[] branches = stream.branch(predicates);
for (int i = 0; i < names.size(); i++) {
    branches[i].to(names.get(i));
}

// KStream branches[0] contains all records whose keys are "jhon"
// KStream branches[1] contains all records whose keys are "sean"
...

答案 2 :(得分:1)

如果您需要为每个用户生成汇总数据,则无需为每个用户写一个单独的主题。您最好在源流上编写聚合。这样一来,您不会在每个键上出现一个主题,但仍然可以对每个用户独立运行操作。

Serde<UserRecord> recordSerde = ...
KStream<Stream, UserAggregate> aggregateByName = recordsByName
   .groupByKey(Grouped.with(Serdes.String(), recordSerde))
   .aggregate(...)
   .toStream()

有关详情,请参见https://docs.confluent.io/current/streams/developer-guide/dsl-api.html#aggregating

此方法将扩展到数百万个用户,而您目前无法通过每个用户一个主题的方法来实现这一目标。