不,Elasticsearch 查询 ≠ Mapping。
这是两个根本不同但紧密关联的核心概念:
- Mapping(映射)定义了数据如何存储与索引(写时结构)
- Query(查询)定义了如何检索已存储的数据(读时逻辑)
将二者等同,会导致查询失效、性能崩溃、结果错误。
一、本质区别:写时 vs 读时
| 维度 | Mapping | Query |
|---|---|---|
| 作用时机 | 写入文档时(Indexing Time) | 查询文档时(Search Time) |
| 核心职责 | 定义字段类型、分析器、存储策略 | 定义匹配逻辑、评分规则、聚合方式 |
| 类比 | 数据库的表结构(Schema) | SQL 的WHERE / SELECT 子句 |
| 变更成本 | 高(需重建索引) | 低(即时生效) |
💡关键认知:
Mapping 是 Query 的“地基”——地基不牢,查询必崩
二、Mapping 如何决定 Query 能力?
▶ 1.字段类型 → 查询类型
| Mapping 类型 | 可用 Query | 不可用 Query |
|---|---|---|
text | match,multi_match | term(除非用.keyword) |
keyword | term,terms,wildcard | match(无分词意义) |
integer/date | range,term | match(非文本) |
▶ 2.分析器 → 全文搜索行为
// Mapping{"description":{"type":"text","analyzer":"ik_max_word"}}- Query 影响:
- 搜“手机” → 匹配“智能手机”(因 IK 分词)
- 搜“手” → 可能匹配(细粒度分词)
▶ 3.Doc Values → 聚合/排序能力
text字段默认关闭 Doc Values→无法聚合/排序keyword字段默认开启 Doc Values→支持高效聚合
⚠️陷阱:
对text字段执行terms聚合 → 报错或需启用fielddata(内存爆炸)
三、Query 如何暴露 Mapping 设计缺陷?
▶ 场景 1:查不到数据
- Query:
{"term":{"product_name":"iPhone 15"}} - Root Cause:
product_name是text类型 → 分词为["iphone", "15"]→ 无完整 term - Fix:
- Mapping 增加
.keyword子字段 - Query 改为
product_name.keyword
- Mapping 增加
▶ 场景 2:聚合结果异常
- Query:
{"terms":{"field":"email"}} - Root Cause:
email是text类型 → 聚合分词后的碎片(如["gmail", "com"]) - Fix:
- Mapping 改为
keyword - 或使用
email.keyword
- Mapping 改为
▶ 场景 3:性能雪崩
- Query:
{"script":{"source":"doc['price'].value * 1.1"}} - Root Cause:
price是text类型 → 无法数值计算 - Fix:
- Mapping 改为
float
- Mapping 改为
四、PHP 实战:Mapping 与 Query 协同设计
▶ 步骤 1:定义 Mapping(写时)
// 创建索引$client->indices()->create(['index'=>'products','body'=>['mappings'=>['properties'=>['name'=>['type'=>'text','analyzer'=>'ik_max_word','fields'=>['keyword'=>['type'=>'keyword']]// 关键!],'price'=>['type'=>'float'],// 数值类型'brand'=>['type'=>'keyword']// 精确值]]]]);▶ 步骤 2:构建 Query(读时)
// 全文搜索 + 精确过滤 + 聚合$params=['index'=>'products','body'=>['query'=>['bool'=>['must'=>[['match'=>['name'=>$keyword]]],'filter'=>[['term'=>['brand.keyword'=>'Apple']],['range'=>['price'=>['gte'=>5000]]]]]],'aggs'=>['brands'=>['terms'=>['field'=>'brand.keyword']]// 必须 keyword]]];$response=$client->search($params);五、避坑指南
| 陷阱 | 破局方案 |
|---|---|
| 先写 Query 再设计 Mapping | 先定义 Mapping,再写 Query |
| 依赖动态映射 | 显式定义所有字段类型 |
| 忽略 .keyword 子字段 | 所有字符串字段必加.keyword |
六、终极心法
**“Mapping 不是配置,
而是查询的基因——
- 当你设计 text,
你在定义全文搜索能力;- 当你设计 keyword,
你在锁定精确操作边界;- 当你协同二者,
你在构建全能搜索系统。真正的 ES 大师,
始于对 Mapping 的敬畏,
成于对 Query 的精控。”
结语
从今天起:
- 所有索引必预定义 Mapping
- 字符串字段必设
.keyword - Query 前必验证字段类型
因为最好的搜索系统,
不是临时拼凑,
而是写读协同。