复杂查询(wildcard、range、geo、script)分别说一下它们是怎么重写的?

下面把四类“复杂查询”在 Lucene/Elasticsearch 中的**重写(rewrite)流程**拆开说:  
核心思路都是“**先把索引里真正命中的底层 Term 或点集合找出来,再组合成可快速倒排扫描的原子查询**”。

-------------------------------------------------
1. WildcardQuery  
-------------------------------------------------
原始查询  
```
WildcardQuery("title", "jav*")
```
重写步骤  
1. 读取 title 字段的 **TermsEnum**(已按字典序排序)。  
2. 用 **Automaton**(通配符自动机)在字典里 **顺序遍历** 所有以 `jav` 开头的真实词项,例如:`java`, `javascript`, `javaw`。  
3. 把这些词项封装成一个 **BooleanQuery**(默认 SHOULD):  
   ```
   BooleanQuery
   ├── TermQuery(title:java)
   ├── TermQuery(title:javascript)
   └── TermQuery(title:javaw)
   ```
4. 如果命中的 Term 太多(默认 ≥1024,受 `indices.query.bool.max_clause_count` 限制),会改写成 **MultiTermQueryConstantScoreWrapper**(常量分数 + 位图合并),避免 BooleanQuery 爆炸。

-------------------------------------------------
2. RangeQuery(numeric/date/ip)  
-------------------------------------------------
原始查询  
```
RangeQuery("price", [50, 100)
```
重写步骤  
1. 判断字段类型:  
   • keyword/text → 退化成 **TermRangeQuery**,过程同 Wildcard 的顺序遍历。  
   • numeric/date/ip → 走 **PointRangeQuery**(BKD 树)。  
2. 在 BKD 树中 **点范围查询**,一次性拿到所有落在 `[50, 100)` 的 **docId 位图**。  
3. 重写成 **PointRangeQuery**(内部直接返回位图),不再拆 Term,速度 O(log N)。

-------------------------------------------------
3. Geo 查询  
-------------------------------------------------
以 `GeoDistanceQuery` 为例:  
1. 计算中心点 + 半径 → 得到 **覆盖矩形**。  
2. 在 BKD 树(geo_point 字段)中 **行/列扫描** 拿到矩形内的所有点。  
3. 再精确 **Haversine 公式** 过滤掉矩形四角外的点。  
4. 最终重写成 **LatLonPointDistanceQuery**(位图),无 Term 级拆分。

-------------------------------------------------
4. ScriptQuery  
-------------------------------------------------
原始查询  
```
ScriptQuery("doc['price'].value * doc['discount'].value > 40")
```
重写步骤  
1. **无法拆成 Term**,因为逻辑是任意代码。  
2. 重写阶段 **原样保留**(`ScriptQuery` 本身已是原子查询)。  
3. 执行时变成真正的 **逐文档脚本计算**(最昂贵,无法走倒排索引)。  
4. 如果脚本里引用了 `_score`,还会强制收集原始分数;否则可跳过。

-------------------------------------------------
一句话速记  
- Wildcard/Prefix → 拆 **Term 列表** → BooleanQuery  
- Range/Geo → 直接走 **BKD 树** → 位图  
- Script → **不拆分**,执行期逐条算  

重写结束后,QueryPhase 拿到全是可位图/跳表直接算交集的“原子查询”,才开始真正的倒排扫描。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值