Elasticsearch精确搜索 #
一、精确搜索概述 #
1.1 精确搜索特点 #
text
精确搜索特点
├── 不分词
│ └── 精确匹配原始值
├── 不计算得分
│ └── 性能更好
├── 结果可缓存
│ └── 重复查询更快
└── 适用于
├── keyword字段
├── 数值字段
├── 日期字段
└── 布尔字段
1.2 查询上下文vs过滤上下文 #
| 特性 | 查询上下文 | 过滤上下文 |
|---|---|---|
| 得分计算 | 是 | 否 |
| 结果缓存 | 否 | 是 |
| 性能 | 较慢 | 较快 |
| 使用场景 | 全文搜索 | 精确过滤 |
二、term查询 #
2.1 基本用法 #
bash
GET /products/_search
{
"query": {
"term": {
"brand": "Apple"
}
}
}
2.2 完整语法 #
bash
GET /products/_search
{
"query": {
"term": {
"brand": {
"value": "Apple",
"boost": 1.0,
"case_insensitive": false
}
}
}
}
2.3 参数说明 #
| 参数 | 说明 | 默认值 |
|---|---|---|
| value | 查询值 | - |
| boost | 权重 | 1.0 |
| case_insensitive | 忽略大小写 | false |
2.4 注意事项 #
text字段使用term查询问题:
bash
GET /products/_search
{
"query": {
"term": {
"name": "iPhone 15"
}
}
}
问题:text字段会被分词,term查询可能无法匹配。
解决方案:
bash
GET /products/_search
{
"query": {
"term": {
"name.keyword": "iPhone 15"
}
}
}
三、terms查询 #
3.1 基本用法 #
bash
GET /products/_search
{
"query": {
"terms": {
"brand": ["Apple", "Samsung", "Google"]
}
}
}
3.2 Terms Lookup #
从其他文档获取terms值:
bash
GET /products/_search
{
"query": {
"terms": {
"brand": {
"index": "popular_brands",
"id": "1",
"path": "brands"
}
}
}
}
3.3 minimum_should_match #
bash
GET /products/_search
{
"query": {
"terms": {
"tags": ["tag1", "tag2", "tag3", "tag4"],
"minimum_should_match": 2
}
}
}
四、range查询 #
4.1 数值范围 #
bash
GET /products/_search
{
"query": {
"range": {
"price": {
"gt": 500,
"lt": 1000
}
}
}
}
4.2 范围操作符 #
| 操作符 | 说明 |
|---|---|
| gt | 大于 |
| gte | 大于等于 |
| lt | 小于 |
| lte | 小于等于 |
4.3 日期范围 #
bash
GET /products/_search
{
"query": {
"range": {
"created_at": {
"gte": "2024-01-01",
"lte": "2024-12-31",
"format": "yyyy-MM-dd"
}
}
}
}
4.4 相对日期 #
bash
GET /logs/_search
{
"query": {
"range": {
"@timestamp": {
"gte": "now-7d/d",
"lt": "now/d",
"time_zone": "+08:00"
}
}
}
}
日期数学表达式:
| 表达式 | 说明 |
|---|---|
| now | 当前时间 |
| now-1h | 1小时前 |
| now-1d | 1天前 |
| now-1w | 1周前 |
| now-1M | 1月前 |
| now-1y | 1年前 |
| now/d | 当天开始 |
| now+1d/d | 明天开始 |
4.5 时区处理 #
bash
GET /logs/_search
{
"query": {
"range": {
"@timestamp": {
"gte": "2024-01-01T00:00:00",
"lte": "2024-12-31T23:59:59",
"time_zone": "+08:00"
}
}
}
}
五、exists查询 #
5.1 基本用法 #
bash
GET /products/_search
{
"query": {
"exists": {
"field": "description"
}
}
}
5.2 查找缺失字段 #
bash
GET /products/_search
{
"query": {
"bool": {
"must_not": {
"exists": {
"field": "description"
}
}
}
}
}
5.3 判断逻辑 #
以下情况被认为字段不存在:
- 字段值为null
- 字段值为空数组[]
- 字段值为[null]
六、ids查询 #
6.1 基本用法 #
bash
GET /products/_search
{
"query": {
"ids": {
"values": ["1", "2", "3"]
}
}
}
6.2 与terms _id的区别 #
bash
GET /products/_search
{
"query": {
"terms": {
"_id": ["1", "2", "3"]
}
}
}
注意:ids查询更高效,因为它直接使用内部ID。
七、prefix查询 #
7.1 基本用法 #
bash
GET /products/_search
{
"query": {
"prefix": {
"name.keyword": {
"value": "iPh"
}
}
}
}
7.2 性能考虑 #
text
性能问题
├── 前缀查询需要扫描所有词项
├── 短前缀匹配大量词项
└── 建议
├── 使用keyword字段
├── 设置合理的max_expansions
└── 考虑使用edge_ngram
八、wildcard查询 #
8.1 基本用法 #
bash
GET /products/_search
{
"query": {
"wildcard": {
"name.keyword": {
"value": "i*15"
}
}
}
}
8.2 通配符 #
| 通配符 | 说明 |
|---|---|
| * | 匹配任意字符(包括空) |
| ? | 匹配单个字符 |
8.3 性能警告 #
text
性能警告
├── 避免以通配符开头
│ └── 如 *phone
├── 避免复杂通配符
│ └── 如 *a*b*c*
└── 替代方案
├── 使用ngram
└── 使用completion suggester
九、regexp查询 #
9.1 基本用法 #
bash
GET /products/_search
{
"query": {
"regexp": {
"name.keyword": {
"value": "i[A-Z].*15",
"flags": "ALL"
}
}
}
}
9.2 flags参数 #
| Flag | 说明 |
|---|---|
| ALL | 启用所有功能 |
| COMPLEMENT | 启用取反 |
| INTERVAL | 启用区间 |
| INTERSECTION | 启用交集 |
| ANYSTRING | 启用任意字符串 |
9.3 性能考虑 #
正则表达式查询性能较差,应谨慎使用。
十、过滤组合 #
10.1 bool filter #
bash
GET /products/_search
{
"query": {
"bool": {
"filter": [
{ "term": { "brand": "Apple" } },
{ "range": { "price": { "lte": 1000 } } },
{ "term": { "in_stock": true } }
]
}
}
}
10.2 must_not #
bash
GET /products/_search
{
"query": {
"bool": {
"filter": [
{ "term": { "brand": "Apple" } }
],
"must_not": [
{ "term": { "status": "deleted" } }
]
}
}
}
10.3 组合查询和过滤 #
bash
GET /products/_search
{
"query": {
"bool": {
"must": [
{ "match": { "name": "iPhone" } }
],
"filter": [
{ "term": { "brand": "Apple" } },
{ "range": { "price": { "lte": 1000 } } }
]
}
}
}
十一、post_filter #
11.1 基本用法 #
bash
GET /products/_search
{
"query": {
"match": {
"name": "iPhone"
}
},
"post_filter": {
"term": {
"brand": "Apple"
}
},
"aggs": {
"all_brands": {
"terms": {
"field": "brand"
}
}
}
}
11.2 使用场景 #
text
post_filter场景
├── 聚合不受过滤影响
│ └── 显示所有品牌的聚合结果
└── 结果集过滤
└── 只返回特定品牌的结果
十二、filter上下文优化 #
12.1 缓存机制 #
text
过滤器缓存
├── 自动缓存
│ └── filter子句结果
├── 缓存键
│ ├── 查询条件
│ └── 索引段
└── 缓存大小
└── indices.queries.cache.size
12.2 缓存策略 #
bash
GET /products/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"brand": {
"value": "Apple",
"cache": true
}
}
}
]
}
}
}
12.3 性能对比 #
| 查询类型 | 是否缓存 | 性能 |
|---|---|---|
| query | 否 | 较慢 |
| filter | 是 | 较快 |
十三、精确搜索最佳实践 #
13.1 字段类型选择 #
text
字段类型建议
├── 精确匹配字段
│ └── 使用keyword类型
├── 数值字段
│ └── 选择合适的数值类型
├── 日期字段
│ └── 使用date类型
└── 布尔字段
└── 使用boolean类型
13.2 查询优化 #
text
查询优化建议
├── 优先使用filter
│ └── 利用缓存
├── 避免通配符开头
│ └── 性能问题
├── 合理使用terms
│ └── 批量匹配
└── 使用exists检查
└── 字段存在性
13.3 组合策略 #
text
组合策略
├── 全文搜索 + 精确过滤
│ ├── must: match查询
│ └── filter: term/range过滤
├── 多条件过滤
│ └── filter数组
└── 排除条件
└── must_not
十四、总结 #
本章介绍了Elasticsearch精确搜索:
- term查询用于精确匹配
- terms查询支持多值匹配
- range查询用于范围过滤
- exists查询检查字段存在性
- filter上下文性能更好
- 合理使用缓存优化查询
下一步,我们将学习聚合分析。
最后更新:2026-03-27