【问题标题】:Flink SQL: Repeating grouping keys in result of GROUP BY queryFlink SQL:在 GROUP BY 查询的结果中重复分组键
【发布时间】:2019-02-06 06:41:21
【问题描述】:

我想在一个包含 group by 语句的表中使用 Flink SQL 进行简单查询。但在结果中,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() 的结果:

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    给定上面的示例查询和输入表clicks as

    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 标志的指示添加和删除行。

    【讨论】:

    • 感谢您的回复,这对我很有帮助。我现在理解布尔字段。但是我怎样才能得到行的最后一个结果呢?如果我过滤具有错误值的行,我仍然会得到更新的值....我无法将结果存储在某处以在花费太多时间后对其进行更新...
    • 恐怕您必须自己维护更新。这是流式查询的一个特点,他们需要更新他们的结果。如果你有一个有界流,你可以附加一个 ProcessFunction 来保存每个键的最后一个结果,并在作业终止时发出它。
    • 我有一个有界流,所以 ProcessFunction 应该是解决方案。你能帮助我吗 ?除了这个例子:ci.apache.org/projects/flinkubuntu/flink-docs-stable/dev/stream/…,我没有找到其他例子。
    • 我可以给你一些建议。 keyBy 分组键上的结果流,并添加存储每个键的行版本的键控状态。还为每个键设置一个事件时间计时器Long.MAX_VALUE - 1,当流终止时将调用该计时器。在onTimer 方法中,您发出所有结果。 但是,我实际上建议以批处理模式进行处理。如果您不需要中间结果,流式传输不会提供任何好处,而且成本要高得多。
    猜你喜欢
    • 1970-01-01
    • 2022-01-03
    • 2020-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多