KSQL:将多个子记录追加到父记录

时间:2018-11-26 19:01:53

标签: apache-kafka confluent ksql

我正在尝试使用KSQL(作为confluent-5.0.0的一部分)从一组父记录和子记录中创建一条记录,其中每个父记录都有多个子记录(通常是付款明细和付款涉及的各方)。这些父母/子女记录通过父母的ID链接。为了说明这一点,我正在处理源系统中这种结构的记录:

payment:
| id    | currency | amount | payment_date |
|------------------------------------------|
| pmt01 | USD      | 20000  | 2018-11-20   |
| pmt02 | USD      | 13000  | 2018-11-23   |

payment_parties:
| id    | payment_id | party_type   | party_ident | party_account |
|-----------------------------------------------------------------|
| prt01 | pmt01      | sender       | XXYYZZ23    | (null)        |
| prt02 | pmt01      | intermediary | AADDEE98    | 123456789     |
| prt03 | pmt01      | receiver     | FFGGHH56    | 987654321     |
| prt04 | pmt02      | sender       | XXYYZZ23    | (null)        |
| prt05 | pmt02      | intermediary | (null)      | (null)        |
| prt06 | pmt02      | receiver     | FFGGHH56    | 987654321     |

这些记录使用Oracle Golden Gate以AVRO格式加载到一组Kafka主题上,每个表都有一个主题。这意味着存在以下主题:src_paymentsrc_payment_parties。根据源系统运行的方式,这些记录的时间戳在几毫秒内。

现在,目的是将这些记录“扁平化”为单个记录,该记录将从传出主题中使用。为了说明,对于上面的记录,所需的输出将遵循以下几行:

payment_flattened:
| id    | currency | amount | payment_date | sender_ident | sender_account | intermediary_ident | intermediary_account | receiver_ident | receiver_account |
|----------------------------------------------------------------------------------------------------------------------------------------------------------|
| pmt01 | USD      | 20000  | 2018-11-20   | XXYYZZ23     | (null)         | AADDEE98           | 123456789            | FFGGHH56       | 987654321        |
| pmt02 | USD      | 13000  | 2018-11-23   | XXYYZZ23     | (null)         | (null)             | (null)               | FFGGHH56       | 987654321        |

在这里我要问的第一个问题是:如何最好地从源主题中获得这种数据组合?

当然,我自己尝试了一些操作。为了简洁起见,我将描述我为实现将第一个付款方追加到付款记录而尝试实现的目标。

第一步:设置源流
注意:由于OGG安装程序向AVRO模式添加了一个名为“表”的属性,因此我必须指定要从该主题获取的字段。另外,我对指定操作类型(例如插入或更新)的字段不感兴趣。

create stream payment_stream (id varchar, currency varchar, amount double, \
payment_date varchar) with (kafka_topic='src_payment',value_format='avro');

create stream payment_parties_stream (id varchar, payment_id varchar, party_type varchar, \
party_ident varchar, party_account varchar) with (kafka_topic='src_payment_parties',\
value_format='avro');

第二步:为付款发送者创建流
注意:根据我从文档中收集的信息以及从实验中发现的内容,为了能够将付款流加入到付款方流中,后者需要按付款ID进行分区。另外,我获得加入工作的唯一方法是重命名该列。

create stream payment_sender_stream as select payment_id as id, party_ident, \
party_account from payment_parties_stream where party_type = 'sender' partition by id;

第三步:加入两个流
注意:我使用的是左联接,因为并非所有付款方都在场。就像上面的示例记录一样,其中pmt02没有中介。

create stream payment_with_sender as select pmt.id as id, pmt.currency, pmt.amount, \
pmt.payment_date, snd.party_ident, snd.party_account from payment_stream pmt left join \
payment_sender_stream snd within 1 seconds on pmt.id = snd.id;

现在,我期望从此流中得到的输出符合以下内容:

ksql> select * from payment_with_sender;
rowtime | pmt01 | pmt01 | USD | 20000 | 2018-11-20 | XXYYZZ23 | null
rowtime | pmt02 | pmt02 | USD | 13000 | 2018-11-23 | XXYYZZ23 | null

相反,我看到的输出是这样的:

ksql> select * from payment_with_sender;
rowtime | pmt01 | pmt01 | USD | 20000 | 2018-11-20 | null | null
rowtime | pmt01 | pmt01 | USD | 20000 | 2018-11-20 | XXYYZZ23 | null
rowtime | pmt02 | pmt02 | USD | 13000 | 2018-11-23 | null | null
rowtime | pmt02 | pmt02 | USD | 13000 | 2018-11-23 | XXYYZZ23 | null

因此,我想问的第二个问题(分为两部分)是:为什么左联接会产生这些重复的记录?可以避免吗?

很抱歉,在问题描述中,我尽量做到完整。当然,我很乐意添加任何可能缺少的信息,并据我所知回答有关设置的问题。

1 个答案:

答案 0 :(得分:0)

您快要到了:-)

SELECT * FROM abcd AS t WHERE NOT EXISTS ( select 1 from abcd as d where (t.a is null or d.a = t.a) and (t.b is null or d.b = t.b) and (t.c is null or d.c = t.c) and (t.d is null or d.d = t.d) and (case when t.a is null then 0 else 1 end + case when t.b is null then 0 else 1 end + case when t.c is null then 0 else 1 end + case when t.d is null then 0 else 1 end) < (case when d.a is null then 0 else 1 end + case when d.b is null then 0 else 1 end + case when d.c is null then 0 else 1 end + case when d.d is null then 0 else 1 end) ); 将为您提供从联接的双方触发的结果。

请尝试使用WITHIN 1 SECONDS。然后,仅连接右边的记录将被添加到左边,反之亦然。

您可以在文章I wrote here中了解有关此模式的更多信息。


顺便说一句,如果您想解决OGG的WITHIN (0 SECONDS, 1 SECONDS)保留字问题,可以在GG配置中设置includeTableName to false