kafka streams中kstreams join globalktable时使用flatMapValues()将一条数据变成多条数据

需求:有一个topic:student-grade是学生的各门课程的成绩,第二个topic:student-course是学生的弱势学科,需要重点关注的,现在想把每个学生的每个弱势科目的成绩单独变成一条记录,这样可以达到老师只看学生弱势科目的成绩。这个需求并不是真实的,只是在这里想来实现一下kstream  join  globalktable时只能得到一条记录,如果在一条记录里面存在多个值的集合,但是想把每个值都单独作为一条记录流向topic中。本来想的是使用branch来实现,但仔细想了下对于不同个数的值,就不确定要分多少个branch,最后找到了flatMapValues()实现该效果。

先启动kafka。

1.创建一个学生成绩的topic:

[root@bogon kafka_2.12-2.1.0]# bin/kafka-topics.sh --create --zookeeper 192.168.184.128:2181 --replication-factor 1 --partitions 1 --topic student-grade

添加记录:

​producer.send(new ProducerRecord<>("student-grade","201403","{\"Chinese\":\"94\",\"Math\":\"75\",\"English\":\"88\",\"Physics\":\"65\",\"Chemistry\":\"83\",\"Biology\":\"89\"}"));

2.创建一个关于每个学生的薄弱学科的topic(每个学生的薄弱学科不一样):

[root@bogon kafka_2.12-2.1.0]# bin/kafka-topics.sh --create --zookeeper 192.168.184.128:2181 --replication-factor 1 --partitions 1 --topic student-course

添加记录:

​producer.send(new ProducerRecord<>("student-course","201403","Math|Physics"));

3.创建一个最后要流出的topic:

[root@bogon kafka_2.12-2.1.0]# bin/kafka-topics.sh --create --zookeeper 192.168.184.128:2181 --replication-factor 1 --partitions 1 --topic student-result

4.创建项目:

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>www.wyhuii.com</groupId>
  <artifactId>wyhuii</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>MyKafkaStreams</name>
 
  
  <dependencies>
  	<!-- kafka -->
	 <dependency>
	 	<groupId>org.apache.kafka</groupId>
	 	<artifactId>kafka-clients</artifactId>
	 	<version>2.1.0</version>
	 </dependency>
	 <!-- kafka streams -->
	 <dependency>
	 	<groupId>org.apache.kafka</groupId>
	 	<artifactId>kafka-streams</artifactId>
	 	<version>2.1.0</version>
	 </dependency>
	 <!-- JSONObject -->
	 <dependency>
                <groupId>org.json</groupId>
                <artifactId>json</artifactId>
                <version>20160810</version>
         </dependency>
  </dependencies>
</project>
​

5.创建stream进行流处理:

package teststreams;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import org.apache.kafka.common.serialization.Serdes;
import org.apache.kafka.common.utils.Bytes;
import org.apache.kafka.streams.KafkaStreams;
import org.apache.kafka.streams.StreamsBuilder;
import org.apache.kafka.streams.StreamsConfig;
import org.apache.kafka.streams.kstream.GlobalKTable;
import org.apache.kafka.streams.kstream.KStream;
import org.apache.kafka.streams.kstream.KeyValueMapper;
import org.apache.kafka.streams.kstream.Materialized;
import org.apache.kafka.streams.kstream.ValueJoiner;
import org.apache.kafka.streams.kstream.ValueMapper;
import org.apache.kafka.streams.state.KeyValueStore;
import org.json.JSONObject;

public class OneToMultipleStream {

	public static void main(String[] args) {
		//配置kafka服务信息
		Properties prop = new Properties();
		prop.put(StreamsConfig.APPLICATION_ID_CONFIG, "kstreams-join");
		prop.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.184.128:9092");
		prop.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass());
		prop.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass());
		prop.put(StreamsConfig.STATE_DIR_CONFIG, "C:\\IT\\tool\\kafka-state-store");//设置状态仓库的存储路径
		StreamsBuilder builder = new StreamsBuilder();
		//创建KStreams
		KStream<String, String> gradeStream = builder.stream("student-grade");
		//创建globalKtable
		GlobalKTable<String, String> courseTable = builder.globalTable(
				"student-course",
				Materialized.<String, String, KeyValueStore<Bytes, byte[]>>as("student-course-statestore")//由于是ktable,需要指定一个存储statestore的文件
				.withKeySerde(Serdes.String())
				.withValueSerde(Serdes.String())
				);
		//将kstream与globalktable  join得到一条结果
		KStream<String, String> join = gradeStream.join(courseTable,
				//指定了kstream中的key,即要与globalktable  join的key,利用这个key在globalktable中相同的key
				new KeyValueMapper<String, String, String>(){

					@Override
					public String apply(String key, String value) {
						return key;
					}
			},
				//join之后的新value,根据需求自己处理
				new ValueJoiner<String, String, String>(){

					@Override
					public String apply(String gradeValue, String courseValue) {
						return gradeValue+"#"+courseValue;
					}
			}
		);
		//我们想把一条学生的所有科目的成绩与该学生需要重点关注的科目进行组合之后,只想得到需要重点关注的那些科目,并将每个科目的成绩都单独成为一条记录,所以使用flatMapValues()可以得到多条结果
		KStream<String, String> resultStream = join.flatMapValues(new ValueMapper<String, Iterable<String>>(){

			@Override
			public Iterable<String> apply(String value) {
				List<String> list = new ArrayList<String>();
				String[] split = value.split("#");
				String gradeValue = split[0];
				String courseValue = split[1];
				String[] course = courseValue.split("\\|");
				for(int i = 0; i< course.length; i++) {
					String newValue = null;
					newValue = course[i]+":"+new JSONObject(gradeValue).get(course[i]).toString();
					list.add(newValue);
				}
				return list;
			}
			
		});
		resultStream.to("student-result");
		KafkaStreams streams = new KafkaStreams(builder.build(), prop);
		streams.start();
	}

}

6.启动消费者查看student-result的topic的记录:

这样就达到了我们要的效果,使得kstream与globalktable  join之后的结果可以进行细化得到多条记录。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QYHuiiQ

听说打赏的人工资翻倍~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值