在 Elasticsearch 里,“昂贵”并不单指“CPU 时间”,而是综合了 **CPU、内存、磁盘 I/O、网络传输** 以及 **实现复杂度** 的代价。下面把常见“昂贵算法”拆开说:
1. **高计算密度的文本算法**
• **match_phrase + slop**(带跨距的短语)
• **span_near / span_first / span_or**(跨度查询)
• **script_score** 自己写 Groovy/Painless(循环、数学函数、外部字段)
代价:每条文档都要跑正则、循环或复杂数学,CPU 飙升。
2. **向量/距离计算**
• **dense_vector + cosineSimilarity / dotProduct**
• **knn search + 向量量化再打分**
代价:一次向量运算 O(D)(D=维度),高维(512/1024) 再乘以 window_size=500 就十几万浮点乘法。
3. **机器学习/学习排序 (LTR)**
• **rank_feature + xgboost 模型**
• **自定义 feature、pair-wise loss**
代价:每条文档要提取几十上百个特征 → 内存抖动 + JNI 调用。
4. **跨字段或跨索引 Join**
• **has_child / has_parent / nested** 多层查询
• **terms lookup** 从另一索引拉百万 ID 列表
代价:大量随机磁盘读 + 网络序列化。
5. **大窗口二次脚本**
把 window_size 调到 5 000 甚至 50 000,再跑上述任意算法,延迟直接秒级起步。
---
一句话判断“贵不贵”:
**只要该算法在单条文档上的耗时 > 一次普通 BM25 match 的 5~10 倍,或需要额外内存/磁盘随机读,就可以称为“昂贵的算法”**——放到 rescore 里,只对 Top-N 跑,能把整体成本从 O(total_docs) 降到 O(window_size)。
一句话:
**“不昂贵的算法” ≈ 只用倒排索引、不走复杂计算、不随机磁盘读、不额外占内存的查询——典型就是最简单的 BM25/TF-IDF 关键词匹配。**
具体看 Elasticsearch 里的“便宜”操作:
| 类型 | 例子 | 便宜原因 |
|---|---|---|
| **Term 级查询** | `term`, `terms`, `range`(数值/日期) | 直接查倒排列表,O(log N) 跳表 |
| **Match 查询** | `match` 默认 BM25 | 纯倒排 + 预计算 norm,无额外 CPU |
| **Filter 子句** | `bool.filter` | 只算位图交集,**不计分、可缓存** |
| **常量打分** | `constant_score` | 直接给固定 1.0 分,不走 BM25 |
| **小结果集聚合** | `terms` / `date_histogram` 结果 < 几万 | 位图遍历在内存完成 |
对照“昂贵”算法(向量、脚本、嵌套、跨字段 join…),它们要么 **逐条做复杂计算**,要么 **随机磁盘读**,要么 **内存膨胀**;而上面这些“便宜”操作几乎只靠 **倒排索引 + 位图/跳表**,CPU 和内存开销都极低。