Java Flink SQL:在GROUP BY查询的结果中重复分组键
我想在一个包含GROUPBY语句的表中使用Flink SQL执行一个简单的查询。但是在结果中,GROUPBY语句中指定的列有重复的行。这是因为我使用的是流媒体环境,它不记得状态吗Java Flink SQL:在GROUP BY查询的结果中重复分组键,java,apache-kafka,apache-flink,flink-streaming,flink-sql,Java,Apache Kafka,Apache Flink,Flink Streaming,Flink Sql,我想在一个包含GROUPBY语句的表中使用Flink SQL执行一个简单的查询。但是在结果中,GROUPBY语句中指定的列有重复的行。这是因为我使用的是流媒体环境,它不记得状态吗 final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); final StreamTableEnvironment tableEnv = TableEnvironment.getTableEn
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
final StreamTableEnvironment tableEnv = TableEnvironment.getTableEnvironment(env);
// configure Kafka consumer
Properties props = new Properties();
props.setProperty("bootstrap.servers", "localhost:9092"); // Broker default host:port
props.setProperty("group.id", "flink-consumer"); // Consumer group ID
FlinkKafkaConsumer011<BlocksTransactions> flinkBlocksTransactionsConsumer = new FlinkKafkaConsumer011<>(args[0], new BlocksTransactionsSchema(), props);
flinkBlocksTransactionsConsumer.setStartFromEarliest();
DataStream<BlocksTransactions> blocksTransactions = env.addSource(flinkBlocksTransactionsConsumer);
tableEnv.registerDataStream("blocksTransactionsTable", blocksTransactions);
Table sqlResult
= tableEnv.sqlQuery(
"SELECT block_hash, count(tx_hash) " +
"FROM blocksTransactionsTable " +
"GROUP BY block_hash");
DataStream<Test> resultStream = tableEnv
.toRetractStream(sqlResult, Row.class)
.map(t -> {
Row r = t.f1;
String field2 = r.getField(0).toString();
long count = Long.valueOf(r.getField(1).toString());
return new Test(field2, count);
})
.returns(Test.class);
resultStream.print();
resultStream.addSink(new FlinkKafkaProducer011<>("localhost:9092", "TargetTopic", new TestSchema()));
env.execute();
final StreamExecutionEnvironment env=StreamExecutionEnvironment.getExecutionEnvironment();
最终StreamTableEnvironment tableEnv=TableEnvironment.getTableEnvironment(env);
//配置卡夫卡消费者
Properties props=新属性();
props.setProperty(“bootstrap.servers”,“localhost:9092”);//代理默认主机:端口
props.setProperty(“group.id”、“flink consumer”);//消费者组ID
FlinkKafkaConsumer011 flinkBlocksTransactionsConsumer=新FlinkKafkaConsumer011(参数[0],新区块链管理架构(),道具);
flinkBlocksTransactionsConsumer.setStartFromEarliest();
DataStream blocksTransactions=env.addSource(flinkBlocksTransactionsConsumer);
tableEnv.registerDataStream(“区块链稳定”,区块链稳定);
表sqlResult
=tableEnv.sqlQuery(
选择块散列、计数(发送散列)+
“来自区块链稳定”+
“按块分组_散列”);
DataStream resultStream=tablenv
.toRetractStream(sqlResult,Row.class)
.map(t->{
行r=t.f1;
String field2=r.getField(0).toString();
long count=long.valueOf(r.getField(1.toString());
返回新测试(字段2,计数);
})
.returns(Test.class);
resultStream.print();
结果stream.addSink(新FlinkKafkaProducer011(“localhost:9092”,“TargetTopic”,新TestSchema());
execute();
我将GROUPBY语句用于block_哈希列,但我有多次相同的block_哈希。这是打印()的结果:
测试{field2='0x2C4A021D514E4F8F0BEB8F0CE71165230492852487DC7811D06FA77C375B5E1',计数=1}
测试{field2='0x2C4A021D514E4F8F0BEB8F0CE71165230492852487DC7811D06FA77C375B5E1',计数=1}
测试{field2='0x2C4A021D514E4F8F0BEB8F0CE71165230492852487DC7811D06FA77C375B5E1',计数=2}
测试{field2='0x780AADC08C294DA46E174FA287172038BBA7AFACF2DFF41FF0F6DEF03906E60',计数=1}
测试{field2='0x182D31BD491527E1E93C4E4468052707EE90C6A8428308A2BD7B6A4D2E10E53',计数=1}
测试{field2='0x182D31BD491527E1E93C4E4468052707EE90C6A8428308A2BD7B6A4D2E10E53',计数=1}
如何在不使用BatchEnvironment的情况下修复此问题?在流上运行的
分组查询必须生成更新。考虑下面的例子:
SELECT user, COUNT(*) FROM clicks GROUP BY user;
每次,单击
表格都会收到一个新行,相应的用户
的计数需要增加和更新
将表
转换为数据流
时,这些更新必须在流中编码。Flink使用收回和添加消息来做到这一点。通过调用tEnv.toRetractStream(table,Row.class)
,您可以将表
表
转换为一个数据流一个分组依据
在流上运行的查询必须生成更新。考虑下面的例子:
SELECT user, COUNT(*) FROM clicks GROUP BY user;
每次,单击
表格都会收到一个新行,相应的用户
的计数需要增加和更新
将表
转换为数据流
时,这些更新必须在流中编码。Flink使用收回和添加消息来做到这一点。通过调用tEnv.toRetractStream(table,Row.class)
,您可以将表
表
转换为一个数据流感谢它真正帮助了我的回复。我现在明白布尔域了。但是我如何才能只得到行的最后一个结果呢?如果我过滤那些有假值的行,我仍然会得到更新后的值。。。。我无法将结果存储在某个地方以在花费太多时间后进行更新…恐怕您必须自己维护更新。流式查询的一个特点是需要更新结果。如果您有一个有界流,您可以附加一个ProcessFunction
,它保留每个键的最后一个结果,并在作业终止时发出该结果。我有一个有界流,因此ProcessFunction应该是解决方案。你能帮助我吗?除了这个例子:,我没有找到其他例子。我可以给你一些建议。按分组键上的结果流设置键,并添加存储每个键的行版本的键控状态。还将每个键的事件时间计时器设置为Long.MAX_VALUE-1
,该计时器将在流终止时调用。在onTimer
方法中,发出所有结果。但是,我实际上建议以批处理模式进行处理。如果你不需要中间结果,流媒体不会提供任何好处,而且成本更高。谢谢你的回复,它确实帮助了我。我现在明白布尔域了。但是我如何才能只得到行的最后一个结果呢?如果我过滤那些有假值的行,我仍然会得到更新后的值。。。。我无法将结果存储在某个地方以在花费太多时间后进行更新…恐怕您必须自己维护更新。流式查询的一个特点是需要更新结果。如果您有一个有界流,您可以附加一个ProcessFunction
,它保留每个键的最后一个结果,并在作业终止时发出该结果。我有一个有界流,因此ProcessFunction应该是解决方案。你能帮助我吗?除了这个例子:,我没有找到其他例子。我可以给你一些建议。按分组键上的结果流设置键,并添加存储每个键的行版本的键控状态。还将每个键的事件时间计时器设置为Long.MAX_VALUE-1
,该计时器将在流终止时调用。在onTimer
方法中,发出所有结果。但是,我实际上建议以批处理模式进行处理。流式传输不起作用
(+, (Bob, 1)) // add first result for Bob
(+, (Liz, 1)) // add first result for Liz
(-, (Bob, 1)) // remove outdated result for Bob
(+, (Bob, 2)) // add updated result for Bob