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精确搜索:

  1. term查询用于精确匹配
  2. terms查询支持多值匹配
  3. range查询用于范围过滤
  4. exists查询检查字段存在性
  5. filter上下文性能更好
  6. 合理使用缓存优化查询

下一步,我们将学习聚合分析。

最后更新:2026-03-27