深入 Elasticsearch(05):近实时、Translog 与 Refresh/Flush
上一篇解决了文本怎样变成词项——analysis pipeline 把原始文本标准化为可索引的 term。这一篇进入文档写入后怎样变成可搜索的。 一条文档经过 analysis 生成词项后,并不会立即对搜索可见。ES 的写入路径涉及内存缓冲、translog 持久化、refresh 生成新 segment、flush 提交到磁盘四个步骤。这套机制让 ES 在写入吞吐和搜索延迟之间取得平衡,也是"近实时搜索"(near-real-time, NRT)这个名字的由来。 本文只抓一个问题:ES 的近实时搜索是怎么实现的,refresh 和 flush 的区别在哪里。 写入路径的完整流程 一条文档从客户端发出到最终持久化到磁盘,经过以下步骤: 123456789101112131415Document → Coordinating Node(路由到目标 shard 的 primary) → Primary Shard: 1. 写入 in-memory buffer(indexing buffer) 2. 追加到 translog(顺序写磁盘,...
深入 Elasticsearch(04):从原始文本到可搜索词项
上一篇解决了文档的结构定义——mapping 把 JSON 字段翻译成 Lucene 数据结构。这一篇进入 text 类型字段怎样从原始字符串变成可搜索的词项。 mapping 决定一个字段"要不要做全文索引",analysis 决定"怎样做"。一个 text 字段在写入时经过 analysis pipeline,产生一组标准化的词项(terms),这些词项被写入倒排索引。搜索时,查询文本也经过 analysis,产生同样标准化的词项,然后在倒排索引中匹配。 本文只抓一个问题:analysis pipeline 的三个阶段怎样工作,以及索引时分析和搜索时分析为什么可能用不同的 analyzer。 Analysis 三阶段 一个 analyzer 由三个组件按顺序组成: 12345原始文本 → Character Filter(s) 字符级预处理 → Tokenizer 切分为 token → Token Filter(s) token 级后处理 → [term1, term2, ...] 写入倒...
深入 Elasticsearch(03):Mapping 与字段类型
上一篇解决了 Lucene 内部的段和索引结构。这一篇进入 ES 如何把 JSON 文档映射到 Lucene 字段。 一个 JSON 文档写入 ES 后,每个字段会变成 Lucene 内部的某种数据结构——倒排索引、BKD-tree、Doc Values 或 Stored Fields。这个从"JSON 字段"到"Lucene 数据结构"的翻译规则,就是 mapping。 本文只抓一个问题:mapping 在 ES 中扮演什么角色,以及 dynamic mapping 和 explicit mapping 的差异会怎样影响搜索行为。 Mapping 是什么 Mapping 定义了一个 index 中文档的字段名、字段类型和索引方式。可以类比为关系型数据库的 DDL(CREATE TABLE),但有几个关键区别: Mapping 允许动态推断。写入一个未知字段时,ES 可以自动猜测类型并添加到 mapping 中。 Mapping 一旦创建,字段类型不可修改。只能添加新字段,不能把一个 text 字段改成 keyword。要改变已有字段的...
深入 Elasticsearch(02):Segment、倒排索引与 Doc Values
上一篇解决了 ES 集群级架构——节点角色、集群状态和数据路径。这一篇进入单个 shard 内部的 Lucene 存储结构。 ES 的每个 shard 就是一个 Lucene index。Lucene index 不是一整块文件,而是由多个不可变的段(segment)组成。理解 segment 的内部结构,才能理解后续文章中 refresh、flush、merge、搜索延迟等机制为什么是那样设计的。 本文只抓一个问题:一个 Lucene segment 内部有哪些数据结构,它们各自承担什么角色。 Segment:不可变的存储单元 一个 Lucene index 由零个或多个 segment 组成。每个 segment 是一批文档的完整索引——包含这批文档的倒排索引、正排数据、字段信息等所有内容。 12345Lucene Index (= ES Shard)├── Segment 0 (committed, immutable)├── Segment 1 (committed, immutable)├── Segment 2 (committed, immutable)└─...
深入 Elasticsearch(01):Node、Cluster 与集群状态
上一篇解决了 ES 的核心数据结构是什么——倒排索引。这一篇进入 ES 的运行时架构。 一个 Elasticsearch 集群不是若干台机器简单地连在一起。集群内部有明确的角色分工、中心化的状态管理和分布式的数据路径。理解这些,才能在后续文章中准确地定位每个机制发生在哪一层。 本文只抓一个问题:一个 ES 集群由哪些角色的节点组成,它们之间通过什么机制协调。 节点角色 一个 Elasticsearch 进程启动后就是一个节点(node)。多个节点通过相同的 cluster.name 组成一个集群(cluster)。每个节点可以承担一个或多个角色,角色通过配置文件或启动参数指定。 ES 8.x 中的主要节点角色: 角色 配置值 职责 Master-eligible master 参与 master 选举,管理集群状态 Data data 存储数据分片,执行搜索和聚合 Data Content data_content 存储非时序数据 Data Hot/Warm/Cold/Frozen data_hot 等 分层存储(ILM 相关) Ingest in...
深入 Elasticsearch(00):为什么 Elasticsearch 的核心是一张倒排索引
Elasticsearch 容易被归类成"分布式搜索引擎"或"日志分析平台"。这些标签描述了它的用途,但没有说清楚它的内部结构。把 Elasticsearch 拆到最底层,剩下的核心数据结构只有一个:倒排索引(inverted index)。mapping、analysis、shard、replica、aggregation 五个机制围绕这个数据结构逐层展开。 Elasticsearch 是一个以倒排索引为核心数据结构的分布式搜索与分析引擎。 本篇是系列导读。核心任务只有一个:说清楚倒排索引是什么,以及它和关系型数据库里的 B+Tree 索引有什么本质区别。 倒排索引的基本结构 关系型数据库的 B+Tree 索引从行出发。给定一个索引键值,B+Tree 能定位到存储这行数据的磁盘页。查找路径是: 1索引键值 → B+Tree 内部节点 → 叶子节点 → 行指针 → 数据页 倒排索引从词项(term)出发。给定一个词项,倒排索引能定位到包含这个词项的所有文档。查找路径是: 1词项 → Term Dictionary → Posting ...
上下文管理全景:Agentic Coding 工具操纵 Messages 数组的六种策略
一次工具调用返回了几万 token 的日志。十轮之后,这段日志是否还在上下文里?如果还在,是否每轮都按普通输入价格重新结算?如果触发 compact,工具定义、Skill 和缓存又会发生什么? 这三个问题经常被混成一个问题。实际上,它们分别属于逻辑上下文、请求结构和计费统计。旧日志仍在有效上下文里,不代表它每轮都按未缓存输入计费;一次请求命中了 prompt cache,也不代表这些 token 不占 context window。 本文保留原来的六种 Messages 操纵策略,但把分析边界收紧到可验证的结构:稳定前缀、可变尾部、渐进式能力加载,以及 API usage 中可以实际测量的缓存结果。未经公开文档或请求轨迹验证的产品排名,不再作为结论。 先分清三本账 讨论上下文成本前,需要同时记三本账。 账本 记录什么 常见观测方式 上下文占用 当前请求中模型可见的 token 工具的 /context、token 估算或请求追踪 请求变动 本轮新增、删除或重写了哪些 segment 对 tools、system、messages 分段哈希 计费输入 未缓存...
NRW 仲裁参数——分布式副本读写的数值问题
问题 分布式系统把数据复制到 N 个节点上。写入时让 W 个节点确认,读取时查询 R 个节点。W 和 R 取多少,才能保证读到最新写入的数据? "取多数派"是工程师最常见的直觉回答,但"多数"到底是多少——N 的一半多一个?还是 N 的三分之二?这两个数字分别在什么条件下出现,背后的推导和权衡,远比"取多数派"三个字复杂。 起源:Gifford 加权投票(1979) NRW 模型的源头是 David K. Gifford 在 1979 年 SOSP 会议上发表的论文 Weighted Voting for Replicated Data。Gifford 的模型比今天常见的等权版本更一般化:每个副本节点被分配一个投票权重 wᵢ,所有节点的总票数 V = Σwᵢ。读仲裁所需票数 Vr 和写仲裁所需票数 Vw 必须满足两个约束: 12约束 1:Vr + Vw > V约束 2:Vw > V / 2 约束 1 保证任何一次读操作至少触碰到一个持有最新版本的节点——读集合和写集合必然有交集。约束 2 保证任何两次写操作至...
共识算法推导——从鸽巢原理到 Paxos、ZAB 与 Raft
问题 三台服务器要对"当前值是什么"达成一致。任何一台随时可能宕机,网络消息可能延迟或丢失。怎样设计一套协议,使得所有正常运行的节点最终看到同一个结果? 这就是分布式共识问题。Paxos、ZAB、Raft 用不同的方式回答了这个问题,但背后的数学内核只有一个——鸽巢原理推出的多数派交叉。 唯一需要的数学工具 鸽巢原理 鸽巢原理(抽屉原理)是高中数学竞赛的常客:n+1 只鸽子飞进 n 个巢,至少有一个巢里有两只鸽子。 多数派一定交叉 设集群有 N = 2f + 1 个节点,f 是允许同时宕机的节点数。多数派(quorum)的大小是 f + 1。 任取两个多数派 Q₁ 和 Q₂: 1|Q₁| + |Q₂| = (f+1) + (f+1) = 2f+2 > 2f+1 = N 元素总数超过了全集大小,鸽巢原理给出结论:Q₁ ∩ Q₂ ≠ ∅,至少有一个节点同时属于两个多数派。 这条性质是 Paxos、ZAB、Raft 共同的地基。后面的推导都建立在它之上。 从零推导 Paxos 单提案者:没有任何困难 集群里只有一个提案者(proposer),问题极其简单: ...
英语语法的骨架:时态、从句和修饰语怎么连起来
学英语语法最容易乱,不是因为术语太多,而是因为很多术语根本不在同一层。时态属于谓语系统,从句属于句子嵌套,修饰语属于短语或句子的依附关系,中心语属于短语内部结构,同位语又是一种“重新命名”的关系。把它们平铺背下来,会像把城市、街道、门牌号和交通规则放在同一张清单里。 更稳的顺序是:先抓句子骨架,再看谓语怎样表达时间和状态,再看名词短语怎样扩张,最后处理从句、非限定动词和省略结构。 第一层:句子骨架 英语句子的基本单位是 clause,中文常译为“小句”或“分句”。一个典型小句至少有一个谓语中心,而真正带时态的是限定动词。 例句: The old book on the desk is useful. 主干是 The book is useful。book 是主语名词短语的中心语,old 和 on the desk 都在修饰 book。is 是限定动词,负责把这个小句固定到现在时。 如果句子变成: The old book that you bought yesterday is useful. 主干仍然是 The book is useful。that you bou...


