深入学习 ElasticSearch 的搜索(一):先理解 Query DSL

前面已经整理过 ElasticSearch 的安装、插件管理、中文分词和倒排索引。理解这些基础后,再看搜索语法会清楚很多。

ElasticSearch 的搜索不是简单的字符串包含判断,而是围绕下面几件事展开:

  • 字段是否分词
  • 查询内容是否分词
  • 查询走的是全文检索还是精确匹配
  • 多个条件之间是 AND、OR 还是 NOT
  • 命中文档如何计算相关性评分

这一篇先做总览,重点理解 ElasticSearch 的 Query DSL 怎么写,以及 matchmatch_phrasetermbool 这几类查询分别适合什么场景。


一、准备一个测试索引

为了后面几篇文章都能复用,先准备一个简单的文章索引。

PUT article_search
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "standard"
      },
      "content": {
        "type": "text",
        "analyzer": "standard"
      },
      "category": {
        "type": "keyword"
      },
      "status": {
        "type": "keyword"
      },
      "author": {
        "type": "keyword"
      },
      "views": {
        "type": "integer"
      },
      "created_at": {
        "type": "date"
      }
    }
  }
}

这里有两类字段:

  • text:会分词,适合全文检索
  • keyword:不分词,适合精确匹配、过滤、聚合、排序

这也是后面理解 matchterm 差异的关键。


二、写入测试数据

写入几条文档:

POST article_search/_doc/1
{
  "title": "ElasticSearch 入门教程",
  "content": "本文介绍 ElasticSearch 的安装、索引、倒排索引和基础搜索。",
  "category": "elasticsearch",
  "status": "published",
  "author": "admin",
  "views": 120,
  "created_at": "2026-04-01"
}
POST article_search/_doc/2
{
  "title": "理解 ElasticSearch 的倒排索引",
  "content": "倒排索引把文档到词的关系反过来,变成词到文档的映射。",
  "category": "elasticsearch",
  "status": "published",
  "author": "admin",
  "views": 260,
  "created_at": "2026-04-10"
}
POST article_search/_doc/3
{
  "title": "Redis 缓存入门",
  "content": "本文介绍 Redis 的字符串、哈希、列表和缓存使用场景。",
  "category": "redis",
  "status": "draft",
  "author": "ops",
  "views": 80,
  "created_at": "2026-04-12"
}
POST article_search/_doc/4
{
  "title": "ElasticSearch match 查询详解",
  "content": "match 查询会分析查询文本,然后使用分析后的 term 去倒排索引中检索。",
  "category": "elasticsearch",
  "status": "published",
  "author": "dev",
  "views": 180,
  "created_at": "2026-04-18"
}

刷新索引:

POST article_search/_refresh

三、Query DSL 是什么

ElasticSearch 的查询主要通过 JSON 表达,这套 JSON 查询语法通常叫 Query DSL。

最基本的搜索请求是:

POST article_search/_search
{
  "query": {
    "match_all": {}
  }
}

其中:

  • POST article_search/_search:搜索 article_search 索引
  • query:查询条件
  • match_all:匹配全部文档

Query DSL 的好处是结构清晰,可以表达很复杂的查询条件,比如:

  • 全文检索
  • 精确匹配
  • 范围过滤
  • 多条件组合
  • 排序
  • 分页
  • 高亮
  • 聚合

1. _search 用 GET 还是 POST

ElasticSearch 的 _search API 同时支持 GETPOST

例如:

GET article_search/_search
POST article_search/_search

不过只要查询条件放在 request body 中,更推荐统一使用 POST

原因是:

  • 查询 DSL 通常写在请求体里
  • 有些 HTTP 客户端或代理对 GET body 支持不一致
  • POST 更符合提交复杂查询条件的使用习惯

所以本文后续示例统一使用:

POST article_search/_search

2. 搜索请求不只有 query

一个业务搜索请求中,除了 query,还经常会出现:

  • from / size:分页
  • sort:排序
  • _source:控制返回字段
  • highlight:高亮
  • aggs:聚合统计

例如:

POST article_search/_search
{
  "from": 0,
  "size": 10,
  "_source": ["title", "category", "created_at"],
  "query": {
    "match": {
      "content": "ElasticSearch"
    }
  },
  "sort": [
    {
      "created_at": {
        "order": "desc"
      }
    }
  ]
}

四、一个最简单的 match 查询

查询标题中包含 ElasticSearch 的文章:

POST article_search/_search
{
  "query": {
    "match": {
      "title": "ElasticSearch"
    }
  }
}

match 是全文检索中最常用的查询。

它会做两件事:

  1. 先分析查询文本
  2. 再用分析后的 term 去倒排索引中查找

所以 match 适合查 text 字段,例如:

  • 标题
  • 正文
  • 摘要
  • 评论内容

五、查询结果怎么看

搜索结果里最常看的字段有这些:

{
  "hits": {
    "total": {
      "value": 3,
      "relation": "eq"
    },
    "hits": [
      {
        "_index": "article_search",
        "_id": "1",
        "_score": 0.8,
        "_source": {
          "title": "ElasticSearch 入门教程"
        }
      }
    ]
  }
}

其中:

  • hits.total.value:命中文档数量
  • hits.hits:具体命中的文档列表
  • _score:相关性评分
  • _source:原始文档内容

_score 越高,通常表示 ElasticSearch 认为这篇文档和查询越相关。


六、常见搜索类型概览

后面几篇会详细讲几类常用查询,这里先做一个总览。


1. match

match 是全文查询。

示例:

POST article_search/_search
{
  "query": {
    "match": {
      "content": "倒排索引"
    }
  }
}

特点:

  • 查询内容会被 analyzer 分析
  • 适合 text 字段
  • 会计算相关性评分
  • 是全文检索最常用的入口

适合:

  • 搜标题
  • 搜正文
  • 搜文章内容
  • 搜用户输入的关键词

2. match_phrase

match_phrase 是短语查询。

示例:

POST article_search/_search
{
  "query": {
    "match_phrase": {
      "content": "倒排索引"
    }
  }
}

特点:

  • 查询内容也会被分析
  • 不只要求 term 命中,还要求位置关系符合短语顺序
  • match 更严格

适合:

  • 搜固定短语
  • 搜连续词组
  • 搜文章标题中的完整表达

3. term

term 是精确词项查询。

示例:

POST article_search/_search
{
  "query": {
    "term": {
      "category": "elasticsearch"
    }
  }
}

特点:

  • 查询值不会像 match 那样走全文分析
  • 直接拿给定 term 去倒排索引里找
  • 最适合 keyword、数字、布尔、日期这类结构化字段

适合:

  • 分类过滤
  • 状态过滤
  • 用户 ID
  • 标签精确匹配

4. bool

bool 用来组合多个查询条件。

示例:

POST article_search/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "content": "ElasticSearch"
          }
        }
      ],
      "filter": [
        {
          "term": {
            "status": "published"
          }
        }
      ]
    }
  }
}

常见子句:

  • must:必须匹配,并参与评分
  • should:应该匹配,可以提升评分
  • filter:必须匹配,但不参与评分
  • must_not:必须不匹配

适合:

  • 多条件搜索
  • 关键词 + 状态过滤
  • 分类 + 时间范围 + 关键词组合
  • 后台列表筛选

5. multi_match

multi_match 用来在多个字段中做全文检索。

例如同时搜索标题和正文:

POST article_search/_search
{
  "query": {
    "multi_match": {
      "query": "ElasticSearch 搜索",
      "fields": ["title", "content"]
    }
  }
}

它适合用户输入一个关键词,同时查标题、正文、摘要等多个字段的场景。

fields 里还可以给字段设置权重:

POST article_search/_search
{
  "query": {
    "multi_match": {
      "query": "ElasticSearch 搜索",
      "fields": ["title^3", "content"]
    }
  }
}

这里 title^3 表示标题命中比正文命中更重要。

multi_match 还有几种常见 type

  • best_fields:哪个字段最匹配,主要看哪个字段
  • most_fields:多个字段命中可以叠加
  • cross_fields:把多个字段当成一个整体看
  • phrase_prefix:适合短语前缀
  • bool_prefix:适合搜索框输入中的联想式查询

6. range

range 用于范围查询。

例如查询浏览量大于 100 的文章:

POST article_search/_search
{
  "query": {
    "range": {
      "views": {
        "gt": 100
      }
    }
  }
}

它适合数字范围、时间范围、价格范围等结构化条件。


7. exists

exists 用于判断字段是否存在。

POST article_search/_search
{
  "query": {
    "exists": {
      "field": "created_at"
    }
  }
}

它适合筛选字段不为空的数据,也适合做数据质量排查。


七、全文查询和精确查询的区别

理解 ElasticSearch 查询时,最容易混淆的是 matchterm

可以先这样记:

match:先分析,再查询
term:不分析,直接查 term

例如 titletext 字段,写入:

ElasticSearch 入门教程

match 查询:

{
  "match": {
    "title": "ElasticSearch"
  }
}

通常可以命中。

但如果用 term 查询 text 字段:

{
  "term": {
    "title": "ElasticSearch"
  }
}

就可能因为大小写、分词结果不一致而查不到。

所以经验上:

  • 搜正文、标题:优先 match
  • 查分类、状态、ID:优先 term
  • 查连续短语:使用 match_phrase
  • 多条件组合:使用 bool

精确搜索里还会见到一些特殊查询:

  • prefix:前缀匹配
  • wildcard:通配符匹配
  • regexp:正则匹配

这些查询很直观,但不要轻易作为普通搜索框的主力方案。尤其是前导通配、复杂通配和正则,在数据量大时可能带来明显性能压力。


八、总结

这一篇是搜索系列的入口。

先记住下面几条就够了:

  • ElasticSearch 搜索主要用 Query DSL 表达
  • match 适合全文检索
  • match_phrase 适合短语匹配
  • term 适合精确词项查询
  • bool 适合组合多个查询条件
  • multi_match 适合多字段全文检索
  • range 适合数字和时间范围
  • exists 适合判断字段是否存在
  • text 字段通常配合全文查询
  • keyword 字段通常配合精确查询和过滤

后面几篇会分别展开 matchmatch_phrasetermbool


参考链接

在这里插入图片描述

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐