您的位置首页 >要闻 > 人工智能 >

管 300 个域名的人,最怕的不是报警

官方 changelog 已核对到三条相关条目:解析限制放开、与普通条件混合、再加打分。下面是按你的固定结构写的稿子。

ES|QL 全文函数终于能进 OR 了:但同一个字段多词,还是塞进一个 MATCH

先说清楚结论:Elasticsearch 9.0 之前,ES|QL 里 MATCH(message, "timeout") OR MATCH(message, "refused") 这种写法会直接报错,全文函数只能单独作为 WHERE 的唯一条件;9.0 之后这个限制被拆成两步放开:先允许 “全文函数 ∨ 全文函数”,再允许 “全文函数 ∨ 普通条件”,随后补上这条路径的打分。依据很明确:9.0.0.yml 里有 ESQL - Remove restrictions for disjunctions in full text functions(PR 118544)、ESQL - Allow full text functions disjunctions for non-full text functions(PR 120334)和 ES|QL - Add scoring for full text functions disjunctions 三条记录;源码 EsqlCapabilities.java 里也留了 FULL_TEXT_FUNCTIONS_DISJUNCTIONS 与 FULL_TEXT_FUNCTIONS_DISJUNCTIONS_COMPUTE_ENGINE 两个能力位。但放开语法不等于推荐这么写:同一个字段、多个词的场景,正确做法仍然是写成一个 MATCH,把词都放进同一个查询串里(MATCH 多词默认就是 OR 语义),而不是拆成两个全文函数用 OR 连起来。原因在于打分口径、下推路径和可维护性;能不能写进 OR 并不是关键。

这个限制当年为什么存在

这里要分清楚哪些是官方说的、哪些是推断。官方 changelog 只给了一行 summary,没有解释动机;原文作者的推断是,全文检索和普通过滤的执行方式不一样,而源码注释支持这个判断。

  • 普通条件是 “是 / 否”:status == 500、范围比较这类谓词,每条文档要么符合要么不符合,随便怎么组合 AND/OR 都不影响语义。
  • 全文函数带分数:MATCH(message,"timeout") 返回的不只是 “符合”,还有 “相关度 0.73”。两个带分数的条件用 OR 连起来,合并分数是取大、相加还是别的规则,没有唯一正确答案。
  • 选错的代价很高:排序错了不像语法错误那样立刻暴露,可能跑很久才被发现。所以早期实现选择直接禁止:宁可报错,也不给出 “看着能用、排序说不清” 的行为。

还有一层是执行路径。ES|QL 有两种跑法:能翻译成 Lucene 查询的,走倒排索引,快;翻译不了的,走 compute engine 列式计算,通用但可能用不上索引。早期全文函数强依赖 “能否下推成 Lucene 查询”,而析取结构恰好是难翻译的那类,这也是限制来源之一。

9.0 到底放开了什么:四条 changelog 逐条对照

顺序很重要,它不是一次性放开,而是一步步补。

变更条目(9.0.0.yml)放开的范围意味着什么
Remove restrictions for disjunctions in full text functions全文 ∨ 全文MATCH(...) OR MATCH(...) 语法上不再报错
Allow full text functions disjunctions for non-full text functions全文 ∨ 普通条件MATCH(...) OR status == 500 这类混合写法可用
Add scoring for full text functions disjunctions析取路径的分数不只 “能筛”,还能参与排序
Fix scoring for full text functions / 打分下推改用 must打分正确性与下推修正打分行为,避免下推时算错

能力位 FULL_TEXT_FUNCTIONS_DISJUNCTIONS_COMPUTE_ENGINE 的注释写明 “as they are implemented in compute engine”;这被原文作者解读为第二阶段把实现挪到计算引擎,不再依赖能否翻译成 Lucene 查询。这一点属于推断,官方没写切换时点。

三种场景,三种写法

先把 “该不该用 OR” 判断清楚,再动手写。

场景推荐写法说明
同一字段,多个近义 / 并列词一个 MATCH,词用空格分隔默认 OR 语义,一次分析、一次下推
跨字段命中任意一个MATCH(title,...) OR MATCH(body,...)9.0 起可用,这才是 OR 的正确用途
同一个词,但语义要求不同MATCH(...) OR MATCH_PHRASE(...)分词匹配与短语匹配是两种查询,不能合并
全文条件 + 结构化条件混合MATCH(...) OR status == 5009.0 起可用,注意别把过滤条件写成全文函数
要求 “都命中”MATCH(...) AND ...AND 组合本来就更早支持

具体到代码:

// 推荐:同字段多词,一个 MATCH 搞定

FROM logs

| WHERE MATCH(message, "timeout refused unreachable")

// 可用但不推荐:同字段拆成两个全文函数 OR

FROM logs

| WHERE MATCH(message, "timeout") OR MATCH(message, "refused")

// 合理:跨字段析取

FROM docs

| WHERE MATCH(title, "kubernetes") OR MATCH(body, "kubernetes")

// 合理:全文 + 普通条件混合

FROM logs

| WHERE MATCH(message, "timeout") OR status_code == 500

同字段多词,为什么一个 MATCH 就够

这是标题后半句的重点,理由不止一条。

  • 语义本来就一样。MATCH 多词默认按 OR 处理,MATCH(f, "a b") 与 MATCH(f,"a") OR MATCH(f,"b") 在 “命中任一个” 的判定上等价,拆开写等于手写了一遍它内部已有的逻辑。
  • 打分更可控。一个 MATCH 内部对整串查询统一算分,词频、字段长度归一化都在同一次查询里完成;拆成两个全文函数再析取,分数要靠合并规则决定,而这个合并规则官方并没有给出明确说明,排序容易偏离直觉。
  • 少一次下推。两个全文函数意味着两个子查询加一次合并;一个 MATCH 通常能整体翻译成单个 Lucene 查询,路径更短。
  • 可维护性。同义词典要加词时,改一个字符串就行;拆成 OR 链,每加一个词就多一行,还容易漏改。
  • 参数一致。一个 MATCH 里 operator、fuzziness 这类选项对所有词统一生效,拆开后每个函数都得重复写一遍,容易不一致。

什么情况下确实该用 OR

也不是完全不用,这几类场景用 OR 是合理的:

  1. 跨字段:标题命中和正文命中是两套字段、两套分析器,没法塞进一个 MATCH。
  2. 跨函数:MATCH(分词)与 MATCH_PHRASE(短语、保序)语义不同,一个查询串表达不了两种要求。
  3. 跨参数:同一个字段,一次要模糊匹配、一次要精确短语,参数冲突时只能拆。
  4. 混合过滤:全文条件与结构化条件混用,本身就是 “任一满足” 的业务语义。
  5. 分支少:两三个同义词,可读性还不至于崩。

判断标准很朴素:能用一个全文函数表达清楚的,就别用 OR;只有当 “字段、函数或参数” 真的不同,OR 才是必须的。

老版本上的三种绕过方式

如果集群还停在 9.0 之前,遇到这个限制不必硬等升级。

办法写法适用
单函数多词MATCH(f, "a b c")同字段、同参数,覆盖大多数需求
非全文部分用 IN... OR status IN (500, 502)混合条件里只有全文那一侧受限
升级到 9.0+原样写 OR需求频繁出现时的根本解法

原文的判断值得记:这个限制能维持那么久,一部分原因是替代品足够好用 —— 真正需要跨字段全文析取的场景,比想象中少。

还留着的几个限制

  • 位置限制没变:全文函数只能出现在 WHERE 里,不能塞进 EVAL、聚合或其它表达式里。这是文档里明确写着的,跟 OR 无关。
  • 分数合并规则没官宣:析取支持了,但合并方式官方没细说。依赖排序时必须自己实测,尤其看 “两个词都命中” 的文档排在哪。
  • 取分方式要确认:9.0 的 changelog 里有 ESQL - enabling scoring with METADATA _score,说明通过 METADATA _score 取分在 9.0 已启用;此外 SCORE() 函数在 9.3 起以技术预览提供。用哪个取决于版本,别照抄旧文。
  • 分支多了要测延迟:五个以上全文函数做 OR,先压一下,逻辑上评估的条件越多开销越大。
  • 能写 ≠ 该写:这是全文里最该记住的一句。

【相关 FAQ】

问题 1:ES|QL 里全文函数以前为什么不能写进 OR?

回答 1:因为 ES|QL 的全文函数不只返回 “是否命中”,还带相关性分数,两个带分数的条件用 OR 连起来时,合并规则没有唯一答案,早期实现选择直接禁止以避免排序不可解释。官方 9.0 changelog 才出现 Remove restrictions for disjunctions in full text functions 与 Allow full text functions disjunctions for non-full text functions 两条,把 “全文 ∨ 全文” 和 “全文 ∨ 普通条件” 分两步放开,随后再补 Add scoring for full text functions disjunctions。

问题 2:既然 ES|QL 全文函数能写进 OR 了,为什么同字段多词还建议只写一个 MATCH?

回答 2:因为 MATCH 多词默认就是 OR 语义,MATCH(f,"a b") 与 MATCH(f,"a") OR MATCH(f,"b") 在命中判定上等价,但前者只产生一个全文函数、一次下推、一套打分。拆成 OR 之后,分数要靠析取合并规则决定,而这个规则官方没有明确说明,排序更容易偏离预期;参数也要在每个函数里重复写,同字段多词用 OR 属于把简单事写复杂。

问题 3:什么情况下 ES|QL 的全文函数必须用 OR,不能合并成一个 MATCH?

回答 3:字段不同、函数不同、参数不同这三种情况必须用 OR。跨字段(标题与正文各有分析器)没法合并;MATCH 和 MATCH_PHRASE 语义不同,一个是分词匹配、一个要求词序,也合不了;同一字段但一次要模糊、一次要精确短语时,参数冲突只能拆开写。此外全文条件与结构化过滤条件混合的 “任一满足” 语义,也是 OR 的合理场景。

问题 4:ES|QL 全文函数用 OR 组合后,怎么确认打分和排序是对的?

回答 4:先取分再看序。9.0 起可通过 METADATA _score 拿到分数,9.3 起另有 SCORE()(技术预览),然后 SORT _score DESC 观察 “两个词都命中” 的文档排位是否符合预期。因为官方没有明确析取分数的合并方式,这一步只能实测;同时建议用等价的 Query DSL bool.should 跑一遍做对照,两组结果对比着看,比单看 ES|QL 更容易判断行为是否异常。

【参考资料】

  • [2026-11-05](ES|QL|全文函数能写进 OR 了,同字段多词还是别这么写)腾讯云开发者社区
  • [2026-11-05](Elasticsearch 9.0.0 变更日志 changelog-bundles/9.0.0.yml:全文函数析取与析取打分条目)GitHub elastic/elasticsearch
  • [2026-11-05](ES|QL 搜索函数参考:MATCH、MATCH_PHRASE、QSTR 与 SCORE)Elastic 官方文档

【免责声明】

本文依据 Elasticsearch 官方变更日志、ES|QL 文档及第三方实测解读整理,其中 “限制为何存在” 与 “实现迁移到计算引擎” 属原文作者的推断,非官方说明;版本行为差异较大,具体语法、打分与可用性请以所用版本官方文档为准。示例查询为语法示意,未在全部版本上逐一实跑,生产使用前建议先在测试集群验证。