
本文介绍如何利用 Polars 的 SQL API(支持 UNNEST 和数组聚合)或原生 DataFrame API,将源表中存储的城市数组,基于查找表动态转换为对应国家数组。
本文介绍如何利用 polars 的 sql api(支持 `unnest` 和数组聚合)或原生 dataframe api,将源表中存储的城市数组,基于查找表动态转换为对应国家数组。
在 Polars 的 SQL 环境中,虽然原生不支持对数组字段直接进行“逐元素 JOIN”,但可通过 UNNEST → 关联匹配 → ARRAY_AGG 三步完成等效转换。该方案完全符合标准 SQL 数组处理范式,且被 Polars SQL 引擎(基于 DataFusion)完整支持。
✅ 推荐 SQL 方案(简洁、声明式、可读性强)
WITH Exploded AS (
SELECT Name, UNNEST(Cities) AS City
FROM Data
),
Matched AS (
SELECT e.Name, l.Country
FROM Exploded e
JOIN Lookup l
ON e.City = l.Capital_City
OR e.City = ANY(l.Other_cities)
)
SELECT Name, ARRAY_AGG(DISTINCT Country) AS Countries
FROM Matched
GROUP BY Name;
✅ 说明:
UNNEST(Cities)将每个['Manchester', 'Paris']展开为两行,使城市可参与常规 JOIN;e.City = ANY(l.Other_cities)是 Polars SQL 支持的标准语法,用于判断标量值是否存在于数组中;ARRAY_AGG(DISTINCT Country)确保结果中无重复国家(如某人名下含多个英国城市),并自动重组为数组。
⚠️ 注意事项与边界处理
-
大小写与空格敏感性:确保
Cities、Capital_City和Other_cities中的字符串格式一致(建议预处理:TRIM(UPPER(...))); -
未匹配城市:若某城市在
Lookup表中完全不存在(既非首都也非其他城市),该行将被JOIN过滤掉。如需保留(显示NULL或'Unknown'),请改用LEFT JOIN并配合COALESCE; -
性能提示:对大表,建议在
Capital_City和展开后的Other_cities上建立逻辑索引(Polars 自动优化ANY检查,无需手动建索引); -
DISTINCT必须显式声明:避免同一国家因多城市匹配而重复入组。
? 替代方案:纯 Polars DataFrame API(更灵活、调试友好)
当 SQL 表达受限(如复杂条件、自定义映射逻辑)时,推荐使用以下 Python 实现:
import polars as pl
# 预处理 Lookup:合并首都与其他城市为统一城市列
lookup_flat = (
pl.concat([
lookup.select(["Country", "Capital_City"]).rename({"Capital_City": "City"}),
lookup.explode("Other_cities").rename({"Other_cities": "City"}),
])
.unique(["Country", "City"]) # 去重防冗余
)
# 主表展开 + 关联 + 聚合
result = (
data.explode("Cities")
.join(lookup_flat, left_on="Cities", right_on="City", how="left")
.group_by("Name")
.agg(pl.col("Country").drop_nulls().unique().alias("Countries"))
)
此方式优势在于:
- 可链式调试每一步(
.head()查看中间态); - 易扩展逻辑(如添加模糊匹配、权重排序);
- 兼容所有 Polars 特性(结构化数组、嵌套类型等)。
✅ 总结
| 场景 | 推荐方式 | 关键操作 |
|---|---|---|
| 简单一对一/一对多映射,追求 SQL 可移植性 | Polars SQL + UNNEST/ANY/ARRAY_AGG
|
UNNEST, ANY(array), ARRAY_AGG(DISTINCT ...)
|
| 需容错、调试、或复杂业务逻辑 | Polars DataFrame API |
.explode(), .concat(), .join(), .unique()
|
只要数据结构满足“数组元素可唯一映射到查找表字段”,该转换在 Polars 中就是完全可行且高效的——无需改变现有表设计,也无需引入外部计算引擎。










