TL;DR
- 场景:业务既有精确匹配(价格、ID、时间),又有容错需求(前缀、模糊、错别字)。
- 结论:用 term-level queries 处理结构化精确条件,再用 bool 组合 must/filter/should/must_not。
- 产出:给出从建索引、写入数据到 term/terms/range/exists/prefix/regexp/fuzzy/ids/bool 全流程 DSL 示例。
版本矩阵
| 项目 | 说明 |
|---|---|
| Elasticsearch 7.x | 按文中 DSL 在 7.x 环境完成验证 |
| Elasticsearch 8.x | 查询 DSL 语法保持兼容 |
| IK 分词插件 | 示例依赖 ik_max_word 分词器 |
| Dev Tools / Kibana 控制台 | 所有示例基于 Dev Tools 控制台执行 |
初始索引
新建一个 book 索引:
PUT /book
{
"settings": {},
"mappings" : {
"properties" : {
"description" : {
"type" : "text",
"analyzer" : "ik_max_word"
},
"name" : {
"type" : "text",
"analyzer" : "ik_max_word"
},
"price" : {
"type" : "float"
},
"timestamp" : {
"type" : "date",
"format" : "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
写入数据
PUT /book/_doc/1
{
"name": "lucene",
"description": "Lucene Core is a Java library providing powerful indexing and search features...",
"price":100.45,
"timestamp":"2020-08-21 19:11:35"
}
PUT /book/_doc/2
{
"name": "solr",
"description": "Solr is highly scalable, providing fully fault tolerant distributed indexing...",
"price":320.45,
"timestamp":"2020-07-21 17:11:35"
}
PUT /book/_doc/3
{
"name": "Hadoop",
"description": "The Apache Hadoop software library is a framework...",
"price":620.45,
"timestamp":"2020-08-22 19:18:35"
}
PUT /book/_doc/4
{
"name": "ElasticSearch",
"description": "Elasticsearch是一个基于Lucene的搜索服务器...",
"price":999.99,
"timestamp":"2020-08-15 10:11:35"
}
词条搜索(term query)
term 查询用于查询指定字段包含某个词项的文档。term 是精确检索,多一个少一个都不行。
POST /book/_search
{
"query": {
"term" : {
"name" : "solr"
}
}
}
词条集合搜索(terms query)
terms 查询用于查询指定字段包含某些词项的文档。
POST /book/_search
{
"query": {
"terms" : {
"name" : ["solr", "elasticsearch"]
}
}
}
范围搜索(range query)
- gte 大于等于
- gt 大于
- lte 小于等于
- lt 小于
- boost 查询权重
POST /book/_search
{
"query": {
"range" : {
"price" : {
"gte" : 10,
"lte" : 200,
"boost" : 2.0
}
}
}
}
日期范围检索:
POST /book/_search
{
"query": {
"range" : {
"timestamp" : {
"gte": "18/08/2020",
"lte": "2021",
"format": "dd/MM/yyyy||yyyy"
}
}
}
}
不为空搜索(exists query)
查询指定字段不为空的文档,相当于 SQL 中的 column is not null。
POST /book/_search
{
"query": {
"exists" : { "field" : "price" }
}
}
词项前缀搜索(prefix query)
POST /book/_search
{
"query": {
"prefix" : {
"name" : "so"
}
}
}
正则搜索(regexp query)
regexp 允许使用正则表达式进行 term 查询。注意:如果使用不正确,会给服务器带来很严重的性能压力,比如 * 开头的查询,将会匹配所有倒排索引中的关键字,这几乎是全表扫描。
POST /book/_search
{
"query": {
"regexp":{
"name": "s.*"
}
}
}
带 boost 值:
POST /book/_search
{
"query": {
"regexp":{
"name":{
"value":"s.*",
"boost":1.2
}
}
}
}
模糊搜索(fuzzy query)
POST /book/_search
{
"query": {
"fuzzy" : {
"name" : "sol"
}
}
}
POST /book/_search
{
"query": {
"fuzzy" : {
"name" : "so"
}
}
}
POST /book/_search
{
"query": {
"fuzzy" : {
"name" : {
"value": "so",
"fuzziness": 2
}
}
}
}
错别字匹配:
POST /book/_search
{
"query": {
"fuzzy" : {
"name" : {
"value": "sorl"
}
}
}
}
POST /book/_search
{
"query": {
"fuzzy" : {
"name" : {
"value": "osrl",
"fuzziness":2
}
}
}
}
ids 搜索(id 集合查询)
POST /book/_search
{
"query": {
"ids" : {
"values" : ["1", "3"]
}
}
}
复合搜索(compound query)- 布尔搜索(bool query)
bool 查询操作来组合查询子句为一个查询,可用关键字:
- must 必须满足
- filter 必须满足,对集合包含/排除进行简单检查,速度非常快,不参与也不影响评分结果
- should 或关系
- must_not 必须不满足,在 filter 上下文中执行,不参与、不影响评分
示例业务需求:
- description 中必须有 Java
- price 必须满足大于 100 小于 1000
- name 字段可以是 lucene 或者 solr 的一种即可
- 时间满足某个时间节点
POST /book/_search
{
"query": {
"bool": {
"filter": {
"match": {
"description": "java"
}
},
"must": [
{
"range": {
"price": {
"gte": 100,
"lte": 1000
}
}
},
{
"bool": {
"should": [
{
"term": {
"name": "lucene"
}
},
{
"term": {
"name": "solr"
}
}
]
}
}
],
"must_not": [
{
"range": {
"timestamp": {
"gte": "18/08/2020",
"lte": "2021",
"format": "dd/MM/yyyy||yyyy"
}
}
}
]
}
}
}
错误速查
| 症状 | 根因定位 | 修复 |
|---|---|---|
用 term 查 text 字段中文内容命中率极低 | text 字段被分词,term 按分词后的 token 精确匹配 | 精确匹配用 .keyword 子字段或将字段改为 keyword |
range 查询日期无结果或报日期解析错误 | gte/lte 的日期字符串和字段 format 不匹配 | 调整 DSL 中日期格式与 mappings 中的 format 保持一致 |
exists 查询命中数异常少 | 字段实际未写入、字段名拼写错误或被动态映射为对象/嵌套结构 | 用 _source 查看原始文档结构,确认字段路径与名称 |
prefix / regexp 查询占用 CPU 高、响应慢 | 在高基数字段上做前缀/正则扫描,且正则以 * 开头 | 尽量添加固定前缀,避免 .*xxx 这种模式 |
fuzzy 查询返回结果不稳定或耗时明显上升 | fuzziness 设置过大,允许的编辑距离过高 | 控制 fuzziness 在 1–2 |
bool 查询结果比预期多或少 | 混淆 must、should、filter、must_not 语义 | 精确区分各关键字含义 |
ids 查询部分 ID 无法命中 | 写入时 ID 为字符串/数值混用或索引名不一致 | 保持 ID 类型一致;确认索引名称正确 |