
下面即是文章目录,也对应到了本文的结论,小伙伴可以先看结论快速了解博主期望本文能给小伙伴们带来什么帮助:
你是否遇到过一下的场景:
那么你能想到哪些解决方案呢?
熟悉离线计算的小伙伴可能很快就能给出答案。没错,hive sql 中的 row_number = 1。flink sql 中也是提供了一模一样的功能,xdm,完美的解决这个问题。
下面开始正式篇章。
先来一个实际案例来看看在具体输入值的场景下,输出值应该长啥样。
场景:埋点数据上报的的字段有 id(标识唯一一条日志),timestamp(事件时间戳),page(时间发生的当前页面),param1,param2,paramN...。但是日志上报时由于一些机制导致日志上报重复,下游算多了,因此需要做一次去重,下游再去消费去过重的数据。
来一波输入数据:
id | timestamp | page | param1 | param2 | paramN |
|---|---|---|---|---|---|
1 | 2021-11-01 00:01:00 | A | xxx1 | xxx2 | xxxN |
1 | 2021-11-01 00:01:00 | A | xxx1 | xxx2 | xxxN |
2 | 2021-11-01 00:01:00 | A | xxx3 | xxx2 | xxxN |
2 | 2021-11-01 00:01:00 | A | xxx3 | xxx2 | xxxN |
3 | 2021-11-01 00:03:00 | C | xxx5 | xxx2 | xxxN |
其中第二条和第四条是重复上报的数据,则预期输出数据如下:
id | timestamp | page | param1 | param2 | paramN |
|---|---|---|---|---|---|
1 | 2021-11-01 00:01:00 | A | xxx1 | xxx2 | xxxN |
2 | 2021-11-01 00:01:00 | A | xxx3 | xxx2 | xxxN |
3 | 2021-11-01 00:03:00 | C | xxx5 | xxx2 | xxxN |
还是上面的案例,我们来看看最终的 sql 应该怎么写:
select id,
timestamp,
page,
param1,
param2,
paramN
from (
SELECT
id,
timestamp,
page,
param1,
param2,
paramN
-- proctime 代表处理时间即 source 表中的 PROCTIME()
row_number() over(partition by id order by proctime) as rn
FROM source_table
)
where rn = 1
上面的 sql 应该很好理解。其中由于我们并不关心重复数据上报的时间前后,所以此处就直接使用 order by proctime 进行处理,按照数据来的前后时间去第一条。
算子图如下所示:

deduplication
具体的去重算子为 deduplication。我们通过 transformation 可以看到去重算子为下图所示:

transformation
上述的去重逻辑集中在 org.apache.flink.table.runtime.operators.deduplicate.ProcTimeDeduplicateKeepFirstRowFunction 的 processFirstRowOnProcTime,如下图所示:

ProcTimeDeduplicateKeepFirstRowFunction
本文主要介绍了 deduplication 的应用场景案例以及其运行原理,主要包含下面两部分: