Flink SQL:在GROUP BY查询结果中重复分组键

时间:2018-08-31 08:58:58

标签: java apache-kafka apache-flink flink-streaming flink-sql

我想在Flink SQL中的一个表中做一个简单的查询,其中包含一个group by语句。但是在结果中,group by语句中指定的列存在重复的行。那是因为我使用的是流环境,而且它不记得状态了吗?

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();

我对block_hash列使用了group by语句,但是同一块block_hash有好几次。这是print()的结果:

  

Test {field2 ='0x2c4a021d514e4f8f0beb8f0ce711652304928528487dc7811d06fa77c375b5e1',count = 1}   测试{field2 ='0x2c4a021d514e4f8f0beb8f0ce711652304928528487dc7811d06fa77c375b5e1',计数= 1}   测试{field2 ='0x2c4a021d514e4f8f0beb8f0ce711652304928528487dc7811d06fa77c375b5e1',count = 2}   测试{field2 ='0x780aadc08c294da46e174fa287172038bba7afacf2dff41fdf0f6def03906e60',计数= 1}   测试{field2 ='0x182d31bd491527e1e93c4e44686057207ee90c6a8428308a2bd7b6a4d2e10e53',计数= 1}   测试{field2 ='0x182d31bd491527e1e93c4e44686057207ee90c6a8428308a2bd7b6a4d2e10e53',计数= 1}

如何在不使用BatchEnvironment的情况下解决此问题?

1 个答案:

答案 0 :(得分:1)

在流上运行的GROUP BY查询必须产生更新。考虑以下示例:

SELECT user, COUNT(*) FROM clicks GROUP BY user;

每次clicks表都会收到一个新行,相应的user的计数需要增加和更新。

Table转换为DataStream时,这些更新必须在流中进行编码。 Flink使用撤消并添加消息来做到这一点。通过调用tEnv.toRetractStream(table, Row.class),可以将Table table转换为DataStream<Tuple2<Boolean, Row>Boolean标志很重要,它指示是否添加Row或从结果表中撤回。

鉴于上面的示例查询,输入表clicks

user | ...
------------
Bob  | ...
Liz  | ...
Bob  | ...

您将收到以下撤回流

(+, (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

您需要自己主动维护结果,并按照撤回流的Boolean标志的指示添加和删除行。