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"
            }
          }
        }
      ]
    }
  }
}

错误速查

症状根因定位修复
termtext 字段中文内容命中率极低text 字段被分词,term 按分词后的 token 精确匹配精确匹配用 .keyword 子字段或将字段改为 keyword
range 查询日期无结果或报日期解析错误gte/lte 的日期字符串和字段 format 不匹配调整 DSL 中日期格式与 mappings 中的 format 保持一致
exists 查询命中数异常少字段实际未写入、字段名拼写错误或被动态映射为对象/嵌套结构_source 查看原始文档结构,确认字段路径与名称
prefix / regexp 查询占用 CPU 高、响应慢在高基数字段上做前缀/正则扫描,且正则以 * 开头尽量添加固定前缀,避免 .*xxx 这种模式
fuzzy 查询返回结果不稳定或耗时明显上升fuzziness 设置过大,允许的编辑距离过高控制 fuzziness 在 1–2
bool 查询结果比预期多或少混淆 mustshouldfiltermust_not 语义精确区分各关键字含义
ids 查询部分 ID 无法命中写入时 ID 为字符串/数值混用或索引名不一致保持 ID 类型一致;确认索引名称正确