如何在ADF中单次扫描为级联主从层级生成多代理序列编号?
问题背景
半结构化XML/JSON常用来序列化主从级联的关系数据,这类有序文件无需唯一键就能保留数据的顺序与层级。多数ETL工具在将这类文件反序列为主从级联表时,能按层级生成即时整数代理序列——既作为主记录的唯一代理键,也作为从记录关联主记录的外键。但ADF的现有转换组件(如Parse、Flatten、Surrogate等)无法直接实现:仅在主层级分组生成编号会丢失与从记录的关联;全量扁平化源数据则冗余繁重,需要大量重扫描与查找操作。
XML示例
<geo> <country name="USA"> <city>Miami</city> <city>Frisco</city> </country> <country name="France"> <city>Paris</city> <city>Brest</city> </country> </geo>
期望输出
可行输出1:拆分为主从表
- 国家表:
| country_id | country_name |
|---|---|
| 1 | USA |
| 2 | France |
- 城市表:
| country_id | city_id | city_name |
|---|---|---|
| 1 | 1 | Miami |
| 1 | 2 | Frisco |
| 2 | 3 | Paris |
| 2 | 4 | Brest |
可行输出2:非规范化表
| country_id | country_name | city_id | city_name |
|---|---|---|---|
| 1 | USA | 1 | Miami |
| 1 | USA | 2 | Frisco |
| 2 | France | 3 | Paris |
| 2 | France | 4 | Brest |
不可行输出(需避免)
| city_id | country_name | city_name |
|---|---|---|
| 1 | USA | Miami |
| 2 | USA | Frisco |
| 3 | France | Paris |
| 4 | France | Brest |
这类输出会导致深层嵌套的大数据集下游需要大量重处理与查找来重建主从关联,而前两种仅需单次解析扫描即可完成。
实现方案(单次扫描数据流)
通过ADF数据流组件的组合,实现单次扫描源文件同时生成层级代理键:
步骤1:读取并解析XML源
使用Source组件读取目标XML文件,配置格式为XML,指定根节点为geo,确保输出包含嵌套结构:每个country节点包含属性@name和子数组city。
步骤2:生成全局唯一的city_id
添加Surrogate Key组件,基于整个数据流生成全局递增的city_id,起始值设为1。此组件会为每条待展开的city记录分配唯一编号,对应需求中的全局唯一城市ID。
步骤3:生成country_id并关联至下属city
添加Window组件,按country.@name作为分区键(确保同一国家的记录分到同一窗口),排序键选择数据流的原始顺序(保证country_id按文件中国家的出现顺序生成)。在窗口中新增列country_id,表达式为row_number()——这会为每个国家生成唯一的递增编号,同时将country_id和country.@name关联到该国家下的所有city记录上。
步骤4:生成目标数据集
方案A:拆分为主从表
- 添加Branch组件将数据流分为两支:
- 分支1(国家表):使用Aggregate组件,按
country_id和country.@name进行聚合(去重),得到唯一的国家记录集,输出到国家表。 - 分支2(城市表):使用Flatten组件展开
city数组,保留country_id、city_id字段,将展开后的city值重命名为city_name,输出到城市表。
- 分支1(国家表):使用Aggregate组件,按
方案B:生成非规范化表
直接使用Flatten组件展开city数组,保留country_id、country.@name、city_id字段,将展开后的city值重命名为city_name,输出即可。
验证
执行数据流后,可分别查看输出数据集,确认country_id按国家出现顺序递增,city_id全局唯一,且主从关联关系正确,符合预期输出。
内容的提问来源于stack exchange,提问作者XKB

