如何在Hive中展开含空数组列的表并避免笛卡尔积?
Hive数组展开并匹配对应位置元素(避免笛卡尔积)
原始表结构及数据
| key | arrival | carrier | class | departure |
|---|---|---|---|---|
| 50B1AE7A0C1BF0001521CEE | ["2024-02-15T11:35:00.000+08:00","2024-02-20T15:10:00.000+08:00"] | ["MU","MU"] | [] | ["2024-02-15T08:45:00.000+08:00","2024-02-20T12:35:00.000+08:00"] |
| 0B88E4801F1B1000544C097 | ["2024-07-25T09:00:00.000+04:00","2024-08-08T07:30:00.000+02:00"] | ["TX","TX"] | ["T","X"] | ["2024-07-24T19:55:00.000+02:00","2024-08-07T22:10:00.000+04:00"] |
| AC3668A4A61C800015210B6 | ["2024-04-08T20:40:00.000+03:00","2024-04-09T02:59:00.000+03:00","2024-06-29T06:40:00.000+03:00","2024-06-29T13:35:00.000+01:00"] | ["MS","MS","MS","MS"] | ["T","T"] | ["2024-04-08T15:00:00.000+01:00","2024-04-08T23:40:00.000+03:00","2024-06-29T04:00:00.000+03:00","2024-06-29T10:10:00.000+03:00"] |
| 86BF7C03C222300004DE0EE | ["2024-01-21T22:35:00.000+06:00"] | ["BG"] | [] | ["2024-01-21T21:15:00.000+05:30"] |
期望输出
| key | arrival | carrier | class | departure |
|---|---|---|---|---|
| 50B1AE7A0C1BF0001521CEE | 2024-02-15T11:35:00.000+08:00 | MU | null | 2024-02-15T08:45:00.000+08:00 |
| 50B1AE7A0C1BF0001521CEE | 2024-02-20T15:10:00.000+08:00 | MU | null | 2024-02-20T12:35:00.000+08:00 |
| 0B88E4801F1B1000544C097 | 2024-07-25T09:00:00.000+04:00 | TX | T | 2024-07-24T19:55:00.000+02:00 |
| 0B88E4801F1B1000544C097 | 2024-08-08T07:30:00.000+02:00 | TX | X | 2024-08-07T22:10:00.000+04:00 |
| AC3668A4A61C800015210B6 | 2024-04-08T20:40:00.000+03:00 | MS | T | 2024-04-08T15:00:00.000+01:00 |
| AC3668A4A61C800015210B6 | 2024-04-09T02:59:00.000+03:00 | MS | T | 2024-04-08T23:40:00.000+03:00 |
| AC3668A4A61C800015210B6 | 2024-06-29T06:40:00.000+03:00 | MS | T | 2024-06-29T04:00:00.000+03:00 |
| AC3668A4A61C800015210B6 | 2024-06-29T13:35:00.000+01:00 | MS | T | 2024-06-29T10:10:00.000+03:00 |
| 86BF7C03C222300004DE0EE | 2024-01-21T22:35:00.000+06:00 | BG | null | 2024-01-21T21:15:00.000+05:30 |
解决方案
直接使用多个LATERAL VIEW EXPLODE会触发笛卡尔积,因为每个数组的展开元素会两两组合。正确做法是用posexplode获取元素的位置索引,再根据索引匹配其他数组对应位置的元素,同时处理class数组为空或长度不足的场景:
方法一:通过索引关联多数组展开
SELECT key, arrival_arr AS arrival, carrier_arr AS carrier, CASE WHEN size(class) = 0 THEN null WHEN pos >= size(class) THEN class[size(class)-1] ELSE class[pos] END AS class, departure_arr AS departure FROM your_table_name LATERAL VIEW posexplode(arrival) exploded_arrival AS pos, arrival_arr LATERAL VIEW posexplode(carrier) exploded_carrier AS pos_c, carrier_arr LATERAL VIEW posexplode(departure) exploded_departure AS pos_d, departure_arr WHERE pos = pos_c AND pos = pos_d;
方法二:单次展开+索引直接访问(更高效)
SELECT key, arrival[pos] AS arrival, carrier[pos] AS carrier, CASE WHEN size(class) = 0 THEN null WHEN pos >= size(class) THEN class[size(class)-1] ELSE class[pos] END AS class, departure[pos] AS departure FROM your_table_name LATERAL VIEW posexplode(arrival) exploded AS pos, dummy WHERE pos < size(carrier) AND pos < size(departure);
关键说明
posexplode会同时返回数组元素的位置索引和对应值,从根源避免多数组展开的笛卡尔积问题。- 针对
class数组为空的情况直接返回null;当class数组长度短于其他数组时,取其最后一个元素(匹配示例中第三行数据的处理逻辑)。 - 第二种方法仅做一次数组展开,通过索引直接访问其他数组元素,性能更优。
内容的提问来源于stack exchange,提问作者saurabh chauhan
相关产品推荐
相关产品推荐

