了解Kafka Streams的流处理:无状态操作

本文介绍了Kafka Streams的无状态操作,包括过滤、映射等,阐述了如何在Kafka Streams DSL API中定义流处理拓扑。文中通过实例展示了如何使用filter、map等方法,并提到了终端操作如to和print。
摘要由CSDN通过智能技术生成

Kafka Streams是一个Java库,用于在Apache Kafka之上开发流处理应用程序。 这是有关Kafka Streams及其API的一系列博客文章中的第一篇。

这不是有关Kafka Stream的“理论指南”(尽管我以前已经介绍过其中的某些方面)

在这一部分,我们将介绍无状态作业在Kafka Streams DSL API中-具体来说,KStream如过滤,地图,通过...分组 etc. The DSL API in Kafka Streams offers a powerful,functional style programming model to define stream processing topologies. Please note that the 桌子API还提供了无状态功能,本文所涵盖的内容也将适用于这种情况(或多或少)

The APIs (KStream etc.) referenced in this post can be found in the Kafka Streams javadocs

The setup

首先,您需要创建一个KafkaStreams实例。 它需要一个拓扑结构和相关配置(以java.util.Properties)

为您的Kafka流应用程序设置所需的配置:

Properties config = new Properties();

config.setProperty(StreamsConfig.APPLICATION_ID_CONFIG, App.APP_ID);
config.setProperty(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
config.setProperty(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
config.setProperty(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());

然后我们可以建立一个拓扑结构定义处理管道(此博客文章的其余部分将重点介绍拓扑的无状态部分)

您可以创建KafkaStreams实例并开始处理

KafkaStreams app = new KafkaStreams(topology, config);
app.start();
new CountdownLatch(1).await(); // wait forever

Stateless operations using KStream

我通常喜欢将事物归类到存储桶中-帮助我“分而治之”。 在这种情况下,我通过将各种KStream操作成过滤,地图等等

让我们开始吧!

filter

您可以使用过滤根据标准省略或包括记录。 例如,如果发送给主题的值包含一个单词,并且您想包含大于指定长度的单词。 您可以使用谓语并将其传递给过滤方法-这将创建一个新的KStream instance with the 过滤ed records

KStream<String, String> stream = builder.stream("words");
stream.filter(new Predicate<String, String>() {
    @Override
    public boolean test(String k, String v) {
            return v.length() > 5;
        }
    })

也可以使用filterNot如果你想排除根据条件进行记录。 这是一个lambda样式示例:

KStream<String, String> stream = builder.stream("words");
stream.filterNot((key,value) -> value.startsWith("foo"));

map

常用的无状态操作是地图。 对于Kafka Streams,可用于转换输入中的每个记录KStream by applying a 地图per function

这有多种口味-地图,地图Values,flatMap,flatMapValues

只需使用地图如果要同时更改键和值,则使用此方法。 例如,将键和值转换为大写

stream.map(new KeyValueMapper<String, String, KeyValue<String, String>>() {
    @Override
    public KeyValue<String, String> apply(String k, String v) {
            return new KeyValue<>(k.toUpperCase(), v.toUpperCase());
        }
    });

使用mapValues如果您要更改的只是值:

stream.mapValues(value -> value.toUpperCase());

flatMap与map类似,但是它允许您返回多个记录(核心价值s)

stream.flatMap(new KeyValueMapper<String, String, Iterable<? extends KeyValue<? extends String, ? extends String>>>() {
    @Override
    public Iterable<? extends KeyValue<? extends String, ? extends String>> apply(String k, String csv) {
        String[] values = csv.split(",");
        return Arrays.asList(values)
                    .stream()
                    .map(value -> new KeyValue<>(k, value))
                    .collect(Collectors.toList());
            }
    })

在上面的示例中,流中的每个记录获取flatMapped,以便首先将每个CSV(逗号分隔)值拆分为各部分,核心价值将为CSV字符串的每个部分创建一对。 例如 如果您有这些记录(富 <-> a,b,c)和(酒吧 <-> d,e)(哪里富和酒吧是键),则结果流将具有五个条目-(富,a),(富,b),(富,c),(酒吧,d),(酒吧,e)

使用flatMapValues如果您只想从流中接受一个值并返回值的集合

group

如果要对内容进行有状态的聚合KStream,您首先需要按其键将其记录分组以创建一个KGroupedStream。

我们将涵盖KGroupedStream在本系列的后续博客文章中

这是一个如何使用groupByKey

StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> stream = builder.stream(INPUT_TOPIC); 

KGroupedStream<String,String> kgs = stream.groupByKey();

的广义版本通过...分组Key是通过...分组这使您能够使用KeyValueMapper

stream.groupBy(new KeyValueMapper<String, String, String>() {
    @Override
    public String apply(String k, String v) {
        return k.toUpperCase();
    }
});

在两种情况下(通过...分组Key和通过...分组),如果您需要使用其他塞尔德(序列化器和解串器)而不是默认版本,请使用接受一个分组宾语

stream.groupByKey(Grouped.with(Serdes.Bytes(), Serdes.Long()));

Terminal operations

Kafka Streams中的终端操作是一种返回的方法虚空而不是另一个KStream要么桌子。

您可以使用至 method 至 s至re the records of a KStream 至 a 至pic in Kafka.

KStream<String, String> stream = builder.stream("words");

stream.mapValues(value -> value.toUpperCase())
      .to("uppercase-words");

的重载版本至 allows you 至 specify a 产生的 object 至 cus至mize the 塞德斯和隔板

stream.mapValues(value -> value.toUpperCase())
      .to("output-topic",Produced.with(Serdes.Bytes(), Serdes.Long()));

除了指定静态主题名称,您还可以使用TopicNameExtractor并包含任何自定义逻辑以动态方式选择特定主题

stream.mapValues(value -> value.toUpperCase())
    .to(new TopicNameExtractor<String, String>() {
        @Override
        public String extract(String k, String v, RecordContext rc) {
            return rc.topic()+"_uppercase";
        }
    });

在这个例子中,我们利用RecordContext其中包含记录的元数据,以获取主题并附加_大写对此

在上述所有情况下,接收器主题应预先存在于Kafka中

如果您想登录KStream记录(出于调试目的),请使用打印方法。 它接受一个实例印制配置行为。

StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> stream = builder.stream(INPUT_TOPIC);
stream.mapValues(v -> v.toUpperCase()).print(Printed.toSysOut());

这将打印出记录,例如 如果你通过(foo,bar)和(约翰·杜) to the input topic, they will get converted to uppercase和logged as such:

[KSTREAM-MAPVALUES-0000000001]: foo, BAR
[KSTREAM-MAPVALUES-0000000001]: john, DOE
您也可以使用打印到文件(代替toSysOut)定位到特定文件

前言方法类似于打印和窥视即

  • 这也是一个终端操作(例如打印)它接受一个Foreach动作(喜欢窥视)

Miscellaneous operations

以来打印方法是终端操作,您可以选择使用窥视返回相同KStream实例! 它接受一个Foreach动作可以用来指定您要对每条记录执行的操作,例如 记录键和值

StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> stream = builder.stream(INPUT_TOPIC);

stream.mapValues(v -> v.toUpperCase())
      .peek((k,v) -> System.out.println("key="+k+", value="+v))
      .to(OUTPUT_TOPIC);

在上面的示例中,您将能够看到正在记录的键和值,它们还将具体化为输出主题(与打印操作)

科是我没有使用过的一种方法(说实话!),但是看起来很有趣。 它使您能够评估记录中的每条记录KStream针对多个条件(以谓语)并输出多个(数组)KStreams。 The key here is that you can use multiple 谓语s instead of a single one as is the case with 过滤和过滤Not。

您可以合并二KStream一起成为一个。

StreamsBuilder builder = new StreamsBuilder(); 

KStream<String, String> stream1 = builder.stream("topic1");
KStream<String, String> stream2 = builder.stream("topic2");

stream1.merge(stream2).to("output-topic");
请注意,结果流可能没有按顺序排列所有记录

如果要为您的每个记录派生一个新键(也可以具有不同的类型)KStream, 使用selectKey接受一个的方法核心价值Mapper。selectKey类似于地图但不同的是地图将返回类型限制为核心价值宾语

StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> stream = builder.stream(INPUT_TOPIC);

stream.selectKey(new KeyValueMapper<String, String, String>() {
            @Override
            public String apply(String k, String v) {
                return k.toUpperCase();
            }
        })

在使用Kafka Streams DSL开发处理管道时,您会发现自己使用以下方法将结果流记录推送到输出主题至 and then creating a new stream from that (output) 至pic i.e.

StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> stream1 = builder.stream(INPUT_TOPIC);
stream1.mapValues(v -> v.toUpperCase()).to(OUTPUT_TOPIC);

//output topic now becomes the input source
KStream<String, String> stream2 = builder.stream(OUTPUT_TOPIC);

//continue processing with stream2
stream2.filter((k,v) -> v.length > 5).to(LENGTHY_WORDS_TOPIC);

可以使用通过方法。 因此,您可以按以下方式重写上面的内容:

StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> stream = builder.stream(INPUT_TOPIC);

stream.mapValues(v -> v.toUpperCase())
      .through(OUTPUT_TOPIC)
      .filter((k,v) -> v.length > 5)
      .to(LENGTHY_WORDS_TOPIC);

在这里,我们将记录(具有大写值)具体化为一个中间主题,然后继续处理(使用过滤在这种情况下),最后将过滤后的结果存储在另一个主题中

现在就这样。 请继续关注本系列中即将发布的帖子!

References

请不要忘记查看以下有关Kafka Streams的资源

from: https://dev.to//itnext/learn-stream-processing-with-kafka-streams-stateless-operations-1k4h

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值