5.1 搜索 API (Search API) Elasticsearch 核心操作:搜索与查询 - 5.1 搜索 API (Search API) 详解 在 Elasticsearch 的世界里,搜索是其核心价值所在。用户将海量数据存储在 Elasticsearch 中,最终目的都是为了能够快速、准确地从中检索出所需信息。而 搜索 API (Search API) 正是 Elasticsearch 提供的最重要、最核心的 API 之一,它是连接用户与 Elasticsearch 强大搜索能力的桥梁。 搜索 API 的基本概念 搜索 API (Search API) 允许用户通过 HTTP 请求向 Elasticsearch 发送搜索请求,并接收包含匹配文档的结果。
在 Elasticsearch 的世界里,搜索是其核心价值所在。用户将海量数据存储在 Elasticsearch 中,最终目的都是为了能够快速、准确地从中检索出所需信息。而 搜索 API (Search API) 正是 Elasticsearch 提供的最重要、最核心的 API 之一,它是连接用户与 Elasticsearch 强大搜索能力的桥梁。
搜索 API (Search API) 允许用户通过 HTTP 请求向 Elasticsearch 发送搜索请求,并接收包含匹配文档的结果。它基于 RESTful 风格,使用 JSON 作为数据交换格式,易于理解和使用。
核心功能:
全文搜索: 基于文本内容进行关键词匹配,支持多种分词器和分析器,实现高效的全文检索。
结构化搜索: 基于文档的结构化字段进行精确匹配、范围查询、布尔查询等,满足各种复杂查询需求。
组合查询: 可以将全文搜索和结构化搜索灵活组合,构建更精细、更强大的查询条件。
结果控制: 可以对搜索结果进行排序、分页、高亮显示、字段过滤等操作,提升用户体验。
聚合分析: 可以对搜索结果进行统计分析,例如计算平均值、最大值、最小值、词频统计等,为数据分析提供支持。
请求方式:
搜索 API 主要通过 GET 或 POST 请求方式访问。
GET: 适用于简单的查询场景,查询参数直接附加在 URL 中。
POST: 适用于复杂的查询场景,查询参数以 JSON 格式放在请求体中,更加灵活和安全,也更适合处理较长的查询语句。
请求路径:
搜索 API 的基本请求路径格式如下:
/[index]/_search /[index1],[index2]/_search /_search
[index]: 指定要搜索的索引名称。
[index1],[index2]: 指定要搜索的多个索引名称,用逗号分隔。
_search: 固定路径,表示搜索操作。
/_search: 搜索所有索引。
match_all 查询我们先从最简单的搜索开始,使用 match_all 查询,它会返回指定索引下的所有文档。
代码示例 (使用 curl 命令):
假设我们有一个名为 products 的索引,包含商品数据。
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "match_all": {} } } '
代码详解:
curl -X GET "localhost:9200/products/_search?pretty": 使用 GET 请求访问 Elasticsearch 的搜索 API,指定索引为 products,并添加 pretty 参数,使返回的 JSON 结果更易读。
-H 'Content-Type: application/json': 设置请求头,表明请求体是 JSON 格式。
-d' ... ': 指定请求体,包含 JSON 格式的查询语句。
"query": { ... }: query 字段是搜索请求的核心,定义了查询条件。
"match_all": {}: match_all 查询类型,表示匹配所有文档, {} 表示没有任何参数。
返回结果 (部分示例):
{ "took" : 2, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 3, "relation" : "eq" }, "max_score" : 1.0, "hits" : [ { "_index" : "products", "_type" : "_doc", "_id" : "1", "_score" : 1.0, "_source" : { "name" : "Elasticsearch Guide Book", "description" : "A comprehensive guide to Elasticsearch.", "price" : 49.99, "category" : "Books" } }, // ... 更多文档 ] } }
结果解析:
took: 查询耗时,单位毫秒。
timed_out: 是否超时。
_shards: 分片信息,包括总分片数、成功分片数、跳过分片数、失败分片数。
hits: 搜索结果的核心部分。
total: 匹配到的文档总数。
value: 文档总数。
relation: 文档总数关系,eq 表示精确匹配。
max_score: 最高得分。
hits: 匹配到的文档列表,每个文档包含以下信息:
_index: 文档所属索引。
_type: 文档类型 (在 Elasticsearch 版本后默认为 _doc)。
_id: 文档 ID。
_score: 文档得分,相关性越高得分越高。
_source: 文档的原始 JSON 数据。
Mermaid Graph TD 图示:
match 查询match_all 查询虽然简单,但在实际应用中很少直接使用。更常见的需求是根据关键词进行全文搜索。match 查询是 Elasticsearch 中最常用的全文搜索查询类型。
代码示例 (搜索商品描述中包含 "guide" 的商品):
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "match": { "description": "guide" } } } '
代码详解:
"match": { "description": "guide" }: 使用 match 查询类型,指定要查询的字段为 description,关键词为 "guide"。返回结果 (部分示例):
{ // ... 其他结果信息 "hits" : { // ... "hits" : [ { "_index" : "products", "_type" : "_doc", "_id" : "1", "_score" : 0.2876821, "_source" : { "name" : "Elasticsearch Guide Book", "description" : "A comprehensive guide to Elasticsearch.", "price" : 49.99, "category" : "Books" } } // ... ] } }
结果解析:
只有商品描述中包含 "guide" 关键词的文档被匹配到。
_score 值反映了文档与关键词的相关性,match 查询会根据关键词在文档中的出现频率、位置等因素计算得分。
match 查询的分析过程:
match 查询会先对输入的关键词进行分析 (analysis),例如分词、停用词处理、大小写转换等,然后将分析后的词项与索引中的倒排索引进行匹配。
可以通过 analyzer 参数指定分析器:
{ "query": { "match": { "description": { "query": "guide books", "analyzer": "standard" // 使用 standard 分析器 } } } }
如果不指定 analyzer,则默认使用字段映射中定义的分析器,或者索引的默认分析器。
match 查询的操作符 (operator):
match 查询可以通过 operator 参数控制关键词之间的匹配关系:
or (默认): 关键词之间是 OR 关系,只要文档包含任意一个关键词就匹配。
and: 关键词之间是 AND 关系,文档必须包含所有关键词才匹配。
示例 (搜索商品描述中同时包含 "guide" 和 "comprehensive" 的商品):
{ "query": { "match": { "description": { "query": "guide comprehensive", "operator": "and" } } } }
match 查询的最小匹配度 (minimum_should_match):
minimum_should_match 参数用于控制 should 子句 (OR 关系) 的最小匹配词项数量,可以更精细地控制匹配度。
示例 (搜索商品描述中至少包含 "guide", "comprehensive", "elasticsearch" 中的两个关键词):
{ "query": { "match": { "description": { "query": "guide comprehensive elasticsearch", "minimum_should_match": "2" } } } }
term 查询term 查询用于精确匹配某个字段的值,它不会对查询关键词进行分析,直接按照原始值进行匹配。
代码示例 (搜索 category 字段为 "Books" 的商品):
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "term": { "category": "Books" } } } '
代码详解:
"term": { "category": "Books" }: 使用 term 查询类型,指定要查询的字段为 category,精确匹配值为 "Books"。返回结果 (部分示例):
{ // ... 其他结果信息 "hits" : { // ... "hits" : [ { "_index" : "products", "_type" : "_doc", "_id" : "1", "_score" : 1.0, "_source" : { "name" : "Elasticsearch Guide Book", "description" : "A comprehensive guide to Elasticsearch.", "price" : 49.99, "category" : "Books" } } // ... ] } }
term 查询的应用场景:
枚举值字段: 例如商品分类、订单状态等,需要精确匹配特定值。
ID 字段: 根据文档 ID 进行精确查找。
不需要分词的字段: 例如数字、日期、keyword 类型字段。
注意: term 查询对文本字段进行精确匹配时,需要确保查询的关键词与索引中的词项完全一致,包括大小写。如果文本字段使用了分词器,term 查询可能无法匹配到原始文本,因为分词器会将文本拆分成多个词项。
range 查询range 查询用于查询某个字段值在指定范围内的文档。
代码示例 (搜索价格在 40 到 60 之间的商品):
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "range": { "price": { "gte": 40, // 大于等于 40 "lte": 60 // 小于等于 60 } } } } '
代码详解:
"range": { "price": { ... } }: 使用 range 查询类型,指定要查询的字段为 price。
"gte": 40: gte (greater-than-or-equal) 参数,表示价格大于等于 40。
"lte": 60: lte (less-than-or-equal) 参数,表示价格小于等于 60。
range 查询支持的范围操作符:
gte: 大于等于 (>=)
gt: 大于 (>)
lte: 小于等于 (<=)
lt: 小于 (<)
from: 范围起始值 (包含)
to: 范围结束值 (包含)
include_lower: 是否包含下界,默认为 true。
include_upper: 是否包含上界,默认为 true。
range 查询的应用场景:
价格范围: 例如搜索指定价格区间的商品。
日期范围: 例如搜索指定时间段内的订单。
年龄范围: 例如搜索指定年龄段的用户。
bool 查询bool 查询是 Elasticsearch 中最强大的复合查询类型,它可以将多个查询条件组合在一起,构建复杂的查询逻辑。
bool 查询包含四个子句:
must (必须): 文档必须满足 must 子句中的所有条件,类似于 AND 关系。
should (应该): 文档应该满足 should 子句中的至少一个条件,类似于 OR 关系。满足的 should 子句越多,文档得分越高。
must_not (必须不): 文档不能满足 must_not 子句中的任何条件,用于排除特定文档。
filter (过滤): 类似于 must,文档必须满足 filter 子句中的所有条件,但不计算相关性得分,性能更高,常用于过滤场景。
代码示例 (搜索分类为 "Books" 且描述中包含 "guide" 的商品):
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "bool": { "must": [ { "term": { "category": "Books" } }, { "match": { "description": "guide" } } ] } } } '
代码详解:
"bool": { ... }: 使用 bool 查询类型。
"must": [ ... ]: must 子句,包含两个查询条件:
{ "term": { "category": "Books" } }: term 查询,分类必须为 "Books"。
{ "match": { "description": "guide" } }: match 查询,描述中必须包含 "guide"。
Mermaid Graph TD 图示:
bool 查询的灵活组合:
bool 查询的子句可以灵活组合,构建各种复杂的查询逻辑。例如:
should 和 minimum_should_match 结合: 实现 "至少匹配 N 个条件" 的逻辑。
must_not 排除特定条件: 例如搜索 "不是 Books 分类的商品"。
filter 进行高效过滤: 例如先用 filter 过滤出指定价格范围的商品,再用 match 进行全文搜索。
嵌套 bool 查询: 可以在 bool 查询中嵌套其他 bool 查询,构建更复杂的查询树。
sort默认情况下,搜索结果按照相关性得分 _score 降序排列。可以使用 sort 参数自定义排序规则。
代码示例 (按照价格升序排列商品):
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "match_all": {} }, "sort": [ { "price": { "order": "asc" } } // 价格升序 ] } '
代码详解:
"sort": [ ... ]: sort 参数,定义排序规则,可以是一个数组,支持多字段排序。
{ "price": { "order": "asc" } }: 按照 price 字段排序,order: "asc" 表示升序 (ascending),order: "desc" 表示降序 (descending)。
支持的排序类型:
数值型字段: 例如 price, age。
日期型字段: 例如 create_time, update_time。
字符串字段: 默认按照字典顺序排序。
地理位置字段: 可以按照距离排序。
多字段排序:
"sort": [ { "category": { "order": "asc" } }, // 先按照分类升序 { "price": { "order": "desc" } } // 再按照价格降序 ]
from 和 size当搜索结果数量很大时,需要进行分页显示。可以使用 from 和 size 参数控制分页。
size: 指定每页返回的文档数量,默认值为 10。
from: 指定从第几条文档开始返回,默认值为 0,表示从第一条文档开始。
代码示例 (查询第二页,每页显示 2 条文档):
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "match_all": {} }, "from": 2, // 从第 3 条文档开始 (索引从 0 开始) "size": 2 // 每页显示 2 条文档 } '
分页计算公式:
当前页码 (page): 假设页码从 1 开始。
from 值: (page - 1) * size
深分页问题:
当 from 值很大时,例如查询第 10000 页之后的数据,会发生深分页问题,导致性能下降甚至超时。因为 Elasticsearch 需要从各个分片收集大量数据,并进行排序和截取。
避免深分页的方法:
避免使用过大的 from 值: 尽量限制分页深度。
使用 scroll API: 适用于需要遍历所有结果的场景,例如数据导出。
使用 search_after: 适用于实时分页场景,基于上一页最后一条文档的排序值进行分页,避免了深分页问题。
_source默认情况下,搜索结果会返回完整的源文档 (_source 字段)。可以使用 _source 参数控制返回的字段。
代码示例 (只返回商品名称和价格):
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "match_all": {} }, "_source": ["name", "price"] // 指定返回的字段 } '
代码详解:
"_source": ["name", "price"]: _source 参数,指定一个数组,包含要返回的字段名称。_source 参数的用法:
_source: false: 不返回源文档,只返回元数据 (_index, _type, _id, _score 等)。
_source: true (默认): 返回完整源文档。
_source: ["field1", "field2"]: 返回指定字段。
_source: { "includes": ["field*"], "excludes": ["field_exclude"] }: 使用 includes 和 excludes 进行更精细的字段过滤,支持通配符。
highlight高亮显示可以将搜索关键词在文档内容中突出显示,提升用户体验。
代码示例 (高亮显示商品描述中的 "guide" 关键词):
curl -X GET "localhost:9200/products/_search?pretty" -H 'Content-Type: application/json' -d' { "query": { "match": { "description": "guide" } }, "highlight": { "fields": { "description": {} // 对 description 字段进行高亮 } } } '
代码详解:
"highlight": { ... }: highlight 参数,定义高亮配置。
"fields": { "description": {} }: 指定要进行高亮的字段为 description, {} 表示使用默认高亮配置。
返回结果 (部分示例):
{ // ... 其他结果信息 "hits" : { // ... "hits" : [ { "_index" : "products", "_type" : "_doc", "_id" : "1", "_score" : 0.2876821, "_source" : { "name" : "Elasticsearch Guide Book", "description" : "A comprehensive guide to Elasticsearch.", "price" : 49.99, "category" : "Books" }, "highlight" : { "description" : [ "A comprehensive <em>guide</em> to Elasticsearch." // 高亮显示 ] } } // ... ] } }
结果解析:
在 hits 数组的每个文档中,会多出一个 highlight 字段,其中包含了高亮显示的字段和内容。
默认使用 <em></em> 标签进行高亮显示,可以通过 pre_tags 和 post_tags 参数自定义高亮标签。
自定义高亮标签:
"highlight": { "pre_tags": ["<span style='color:red'>"], // 前缀标签 "post_tags": ["</span>"], // 后缀标签 "fields": { "description": {} } }
本文详细介绍了 Elasticsearch 的 搜索 API (Search API) 的核心功能和常用查询类型,并通过代码示例演示了其基本用法。掌握搜索 API 是使用 Elasticsearch 的基础和关键。
核心要点回顾:
搜索 API 的基本概念和请求方式。
match_all 查询:匹配所有文档。
match 查询:全文搜索,支持多种操作符和分析器。
term 查询:精确匹配。
range 查询:范围查询。
bool 查询:复合查询,灵活组合多个查询条件。
sort:结果排序。
from 和 size:分页查询。
_source:源文档过滤。
highlight:高亮显示。
未来展望:
更丰富的查询类型: Elasticsearch 提供了更多高级查询类型,例如 nested 查询、geo 查询、script 查询等,可以满足更复杂的搜索需求。
性能优化: 在实际应用中,需要关注搜索性能,例如合理设计索引结构、选择合适的查询类型、优化查询语句、使用缓存等。
与客户端集成: 可以使用 Elasticsearch 提供的各种客户端库 (例如 Java, Python, JavaScript 等) 更方便地与搜索 API 进行交互,构建强大的搜索应用。