惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
The Last Watchdog
The Last Watchdog
TaoSecurity Blog
TaoSecurity Blog
Schneier on Security
Schneier on Security
SecWiki News
SecWiki News
V
Vulnerabilities – Threatpost
Project Zero
Project Zero
O
OpenAI News
W
WeLiveSecurity
Security Archives - TechRepublic
Security Archives - TechRepublic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Hacker News: Front Page
Cisco Talos Blog
Cisco Talos Blog
Spread Privacy
Spread Privacy
Help Net Security
Help Net Security
P
Privacy & Cybersecurity Law Blog
K
Kaspersky official blog
S
Security @ Cisco Blogs
Latest news
Latest news
AWS News Blog
AWS News Blog
U
Unit 42
Martin Fowler
Martin Fowler
阮一峰的网络日志
阮一峰的网络日志
S
Secure Thoughts
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Know Your Adversary
Know Your Adversary
Scott Helme
Scott Helme
博客园 - 司徒正美
B
Blog RSS Feed
C
Check Point Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
Docker
Google Online Security Blog
Google Online Security Blog
Jina AI
Jina AI
aimingoo的专栏
aimingoo的专栏
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Last Week in AI
Last Week in AI
月光博客
月光博客
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
SegmentFault 最新的问题
NISL@THU
NISL@THU
T
The Blog of Author Tim Ferriss
C
Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
小众软件
小众软件

暗无天日

读:AI Agent 安全日志——从可见性与隐私的两难说起 - 暗无天日 AI写作的语言指纹——如何让文字不那么像机器 - 暗无天日 读:50 条 Claude Code 技巧——一个工程经理的六个月使用心得 读:AI 辅助开发为什么让 E2E 测试更有价值 - 暗无天日 读:在Emacs中使用Claude Code(Spacemacs适配版) - 暗无天日 Claude Code 背后的工程哲学——读 Agent Harness Engineering 读:Agent Harness Engineering——AI 智能体不只是模型,还有套件 - 暗无天日 browser-harness:让 AI 直接接管你的浏览器 - 暗无天日 读:Security-First CI/CD —— DevSecOps 自动化实践指南 TIL: 数字小键盘的小数点陷阱与行内算术求值 - 暗无天日 读:Immutability 不是万能药,它是一种权衡 - 暗无天日 Conducty:给 Claude Code 加上项目记忆和并行执行能力 - 暗无天日 读 — GitHub Trending 里的 Claude Code 技能包 读 — Prompt Caching 省钱指南 TIL: Emacs 中那些跟鼠标配合的冷门快捷键 - 暗无天日 读:Anvil——把 Emacs 变成 AI 的工具服务器 读:Emacs 代码折叠终极指南 - 暗无天日 读:Clojure 搭车客指南 - 暗无天日 git推送失败后恢复仓库损坏的完整记录 - 暗无天日 多智能体系统的两个有效模式——以及对 Claude Code 用户的启示 - 暗无天日 用 Org Babel 写 Literate 博文:扩展执行 + 定制导出 proced:Emacs 内置的进程查看器 - 暗无天日 从 proced 定制中学到的 Elisp 模式 读:让 Emacs proced 在 macOS 上显示 CPU 和内存 异步编程的函数着色税 - 暗无天日 链式调用的代价:JavaScript 和 Clojure 的共同教训 - 暗无天日 hyperfine:命令行基准测试工具 - 暗无天日 管道中的变量去哪了?——子 shell 作用域陷阱 - 暗无天日 开源包装器的信任陷阱:四个危险信号 - 暗无天日 程序员愿意为 AI 写文档,却不愿为同事写 - 暗无天日 mktemp: Shell 脚本中临时文件的安全陷阱与最佳实践 - 暗无天日 WSL9x —— 在 Windows 9x 里跑 Linux 内核 6.19 用 ox.el 做你想做的事 —— org-export 高级编程指南 读:Hot-wiring the Lisp Machine —— 用纯 Elisp 构建零依赖的 Org 静态站点生成器 Elisp 性能优化的六个实战教训 - 暗无天日 fcitx5 下 Emacs 无法切换输入法的排查 - 暗无天日 ERT 测试交互命令的三种方式 - 暗无天日 SEM Assistant: 当 Elisp 守护进程遇上 LLM 用 dmsg 给 Elisp 加上结构化调试日志 用 org-habit 追踪非每日习惯 - 暗无天日 Clojure X-Men:当编程语言特性变成超能力 - 暗无天日 TIL: 用 diff-hl 在 fringe 中显示 git 变更 读:llm-test —— 用 LLM agent 驱动 Emacs 测试 TIL: AI 时代的橡皮鸭调试 - 暗无天日 fcitx 启动后键盘输入卡顿的排查 - 暗无天日 TIL: 早期网页的图片热区导航 - 暗无天日 读 Seeing the Whole System 用 Emacs 自动生成每周链接推荐 - 暗无天日 读:ASCII control characters in my terminal 读 What to learn - 暗无天日 Lisp 的括号之痛——一个愚人节玩笑揭开的老伤疤 - 暗无天日 一本书该"线性读"还是"并行读" - 暗无天日 读 How to Monetize a Blog:一篇伪装成变现指南的讽刺文 Python Mock 第三方依赖的四种策略 - 暗无天日 Emacs Lisp 热重载实用指南 - 暗无天日 Prot 的 Emacs 配置哲学 - 暗无天日 TIL: 从直播对谈中学到的三个 Emacs 技巧 - 暗无天日 TIL: 自动使用项目虚拟环境的 Python - 暗无天日 TIL: 让 Help buffer 自动获得焦点 一条命令让本地开发用上 HTTPS —— slim 工具介绍 用 fsck 检查和修复 Linux 文件系统 排查Linux进程"卡死"实战:从strace到gdb全流程 - 暗无天日 PostgreSQL 索引:从基础到你可能不知道的高级用法 - 暗无天日 用 .pdbrc 自定义 Python 调试器 ANSI 转义码的标准化现状 - 暗无天日 终端程序的潜规则 - 暗无天日 PARA Org-mode 测试配置 - 暗无天日 AI越强越辣鸡?控制论说这是必然的 - 暗无天日 AI 越强越需要你盯着——反馈循环实操指南 - 暗无天日 你的AI代理正在偷你的密钥——四种你没想到的泄露通道 - 暗无天日 LLM 在 DevOps 中的三种角色 - 暗无天日 写作风格的反建议 - 暗无天日 反驳本质复杂性——Dan Luu 论为什么《没有银弹》错了 - 暗无天日 文件充满了危险——Dan Luu 谈文件系统的可靠性陷阱 - 暗无天日 AI 时代的 PARA 方法:用 Org-mode 和 AI 打造个人知识管理系统 Linux 数据去重学习笔记 - 暗无天日 创建跨平台 ZIP 文件的隐藏陷阱:Extra Field - 暗无天日 X11 Forwarding 排障指南 - 暗无天日 IP欺骗端口扫描:当别人冒充你去扫描别人 - 暗无天日 Linux 输入栈全景解析:从硬件按键到屏幕响应 - 暗无天日 Unix 系统中那些被埋没的配置开关——以 FontConfig 为例 - 暗无天日 在Linux上限制儿童使用电脑 - 暗无天日 GIF不仅仅是一种图片格式——用GIF流做些奇怪的事 - 暗无天日 Leiningen 学习笔记:Clojure 项目构建与管理从入门到实战配置 - 暗无天日 Google SRE Book 读书笔记 - 暗无天日 yes 管道 head 发生了什么 - 暗无天日 为什么 nohup 在 crontab 中不起作用 Bash中的Indirection与Nameref - 暗无天日 Linux PAM 简介 - 暗无天日 从Linux ISO文件启动计算机 - 暗无天日 用 Bash 打造一个Screen Locker 用GitHub Actions自动构建EGO博客 - 暗无天日 blocking I/O 的作用 - 暗无天日 mobileog 手机端同步提示Error:2 No such file 的解决方法 回收 WSL2 VHDX 文件占用空间 使用 org-mode columnview 生成任务列表 - 暗无天日 Emacs 作为 MPD 客户端 - 暗无天日 移动文件路径却不破坏org file link的方法 - 暗无天日 如何合理的导出help link 成HTML - 暗无天日 笑话理解之Biology - 暗无天日
读:数据管道中Schema变更的四种形状 - 暗无天日
2026-05-16 · via 暗无天日

数据管道跑了几个月没问题,某天突然挂了。翻日志一看,报了 SchemaError ,原因是上游数据加了一列属性。

原文 来自 Polars 官方博客,讨论的就是这个问题:schema 变更不可避免,但不同存储格式应对变更的能力差异很大。原文以 Polars 为工具讲解具体参数,本文提取其中的通用原则,重点看不同格式在 schema 演化上的设计取舍。

四种形状

Schema 变更看似五花八门,归纳起来只有四种:

形状 例子 能否自动处理
新增列(Additive) 上游加了一个 category 字段 可以,旧数据填 null
缺失列(Subtractive) 期望的列不在新数据里了 可以,新数据填 null
类型漂移(Type drift) Int32 变成 Int64 ,因为数据量大了整数范围不够用 部分可以,只支持无损拓宽
破坏性变更(Breaking) 列被重命名、语义变了、类型不兼容 不行,必须手动处理

前三种有自动化的空间,第四种没有。遇到报错时,先判断是哪种形状,再找对应的处理方式。

顺便说一下"类型漂移只支持无损拓宽"这件事。 Int64 缩到 Int32 ,超过 2^31 的值就溢出了;浮点数缩窄精度也会丢失。所以自动处理只能往宽了走( Int32Int64 ),不能往窄了走。

四种格式的设计哲学

CSV:没有元数据,一切靠猜

CSV 文件不携带类型信息,读取时工具只能采样前若干行来推断类型。如果后面的行突然出现小数,而采样推断出来的是整数,就报错。

生产环境应该提前声明已知列的类型(告诉工具"这一列就是浮点数")。否则一旦推断错了就会酿成故障。

Parquet:文件级元数据,多文件时易出错

Parquet 是列式存储格式,同一列的数据连续存放。分析查询(对某列求和、求平均)只需读相关列,不用扫描整行。每个文件自带 schema 元数据(列名和类型),还附带统计信息(每列的最大值、最小值、记录数),查询引擎可以利用这些统计跳过不相关的文件。

单文件没有推断问题。问题出在"多个文件"上:多数工具(如 events_*.parquet )在扫描多文件时,以第一个文件的 schema 为基准,后续不一致就报错。

新增列时,可以声明一个超集 schema,让旧文件里没有的列填 null。类型漂移时,可以让整数自动拓宽。如果两种问题同时出现(列不同 + 类型不同),可以独立读取各文件再按列名对齐,类型取公共超类型。

Delta Lake:事务日志,显式声明演化

Delta Lake 在 Parquet 数据旁边维护一个 _delta_log/ 目录,里面是按序号命名的 JSON 文件( 00001.json00002.json 、...),每次写入操作生成一个新的 JSON,记录这次加了哪些文件、删了哪些文件、schema 有没有变。定期还会合并为 Parquet 格式的 checkpoint 文件防止日志过长。这种设计让 Parquet 有了事务能力:多个写入者通过乐观并发控制协调(先提交者赢,其他人重试),读操作通过日志就知道该读哪些文件,不用扫描全部。

写入时默认严格匹配 schema,不一致就拒绝。要让 schema 演化,需要显式声明允许合并:新旧列的增减自动处理,旧数据自动填 null。重命名和类型不兼容仍然需要手动处理。和 Parquet 相比,Delta Lake 能通过事务日志回溯 schema 变更的历史,知道哪天加了列、哪天改了类型。

Iceberg:field ID 追踪

Iceberg 是四种格式中对 schema 演化支持最完整的。它的元数据是分层的:最上层是 metadata 文件,指向各个 snapshot(快照);每个 snapshot 指向一个 manifest list;manifest list 指向 manifest 文件;manifest 文件记录一组数据文件及其统计信息(记录数、文件大小、列的上下界)。这种分层结构让查询引擎在规划阶段就能跳过大量不相关的文件,不用真正读数据。底层数据文件可以是 Parquet、ORC 或 Avro 格式。

Schema 演化做得好,核心在于一个设计选择:用稳定的 field ID 而不是列名来追踪列。

其他格式都是按列名或位置匹配。列名改了,旧数据文件找不到对应的列;位置变了,列会对不上号。Iceberg 的做法是:每列有一个数字 ID(如 1、2、3),存储在 catalog(元数据服务,通常用 Hive Metastore、AWS Glue 或 REST catalog)里。列名改了,ID 不变。读的时候 catalog 知道 "ID=2 现在叫 category " ,自动映射。加列、删列、重命名,都不需要重写数据文件。

from pyiceberg.schema import Schema
from pyiceberg.types import NestedField, LongType

schema = Schema(
    NestedField(field_id=1, name="id", field_type=LongType()),
    NestedField(field_id=2, name="value", field_type=LongType()),
)

注意 field_id 参数:这是 Iceberg 追踪列的标识符,和列名无关。之后通过 catalog 的 update_schema() 方法加列、删列、重命名,都是操作这个 ID 映射,不动数据文件。读取时,扫描器始终读 catalog 中的最新 snapshot(快照,某个时间点的完整表状态),自动处理列的增删和重命名,不需要任何额外参数。

对比与选择

CSV 四项全部手动,不单独列出。

需求 Parquet Delta Lake Iceberg
新增列 声明超集 schema 自动(merge 模式) 自动(field ID)
缺失列 指定参数填充 null 自动(merge 模式) 自动(field ID)
类型漂移 自动拓宽 手动 自动(无损拓宽)
列重命名 手动 手动 自动(field ID 不变)
额外设施 需要 catalog 服务

Iceberg 支持最完整,但需要额外搭建 catalog 服务。Delta Lake 不需要额外服务,文件系统就够了。Parquet 也没有额外依赖,但多个文件 schema 不一致时只能自己写代码处理。CSV 连列类型都没有,全靠工具猜。

你的 schema 变更频繁吗?如果频繁且需要自动化,Iceberg 的 catalog 开销就值。schema 稳定的话,Parquet 或 Delta Lake 就足够。如果连 schema 都还没有,那么先搞定 CSV 的类型推断再说吧。