
上一篇【第17篇】Elasticsearch并发控制——refresh参数与乐观并发控制下一篇【第19篇】Elasticsearch Body模式搜索详解——分页、排序与高亮摘要搜索是Elasticsearch最核心的能力也是其相比传统数据库最突出的优势。本文作为搜索系列的开篇全面介绍了Elasticsearch搜索功能的基础知识。涵盖分布式搜索机制的Query Phase查询阶段和Fetch Phase获取阶段两阶段模型详细解释了Elasticsearch如何在多个分片上执行搜索并合并结果。深入讲解了搜索API端点的使用方法GET/POST两种HTTP方法、URI搜索模式的Lucene查询语法字段查询、布尔运算、通配符、范围查询等以及重要URI参数df默认字段、analyzer指定分析器、lenient宽松模式、explain评分解释、sort排序、from/size分页。同时介绍了搜索分片信息API_search_shards的使用方法和搜索响应结构的详细解析hits、total、shards、_score、_source。掌握这些基础知识将为后续学习Query DSL和高级搜索特性打下坚实的基础。一、分布式搜索机制1.1 搜索的两种阶段在Elasticsearch中执行搜索时请求被发送到协调节点接受请求的节点协调节点负责将请求分发到所有相关分片然后收集并合并结果。分布式搜索操作分为两个阶段第一阶段Query Phase查询阶段协调节点将查询请求广播到所有相关分片主分片或副本。每个分片在本地执行搜索生成匹配文档的排序列表然后只返回足够的信息给协调节点排序字段值和文档ID以便协调节点合并并重新排序结果。第二阶段Fetch Phase获取阶段协调节点根据第一阶段收集到的排序结果确定哪些文档需要返回完整内容然后向相关分片请求这些文档的完整_source数据以及高亮信息等。1.2 自适应副本选择默认情况下Elasticsearch使用自适应副本选择机制来选择数据的最佳副本。协调节点根据以下因素做出选择因素说明响应时间协调节点与数据节点之间的历史响应时间搜索时间数据节点执行过去搜索请求的耗时队列大小数据节点上搜索线程池的队列大小如果需要关闭此机制可以设置动态集群配置PUT_cluster/settings{persistent:{cluster.routing.use_adaptive_replica_selection:false}}关闭后搜索请求将在所有数据副本之间以循环round-robin方式分发。1.3 路由与搜索在索引时使用路由参数可以将相关文档放在同一分片上搜索时也可以指定路由以只搜索特定分片GETtwitter/_search?routinguser1,user2{query:{match:{message:elasticsearch}}}路由参数可以是多值的用逗号分隔。指定路由后搜索只命中路由值匹配的相关分片显著提升搜索效率。1.4 搜索类型对比Elasticsearch允许通过search_type参数控制搜索执行方式搜索类型行为准确性性能query_then_fetch默认先查询后获取高高dfs_query_then_fetch先收集全局词频再查询更高较低dfs_query_then_fetch在初始分发阶段计算分布式词频以获得更精确的评分。但由于额外的网络开销性能较差通常不建议使用。二、搜索API端点2.1 基本格式搜索API_search支持GET和POST两种HTTP方法都可以执行搜索查询并返回匹配结果。URI模式使用查询参数GETtwitter/_search?quser:kimchyBody模式使用请求体POSTtwitter/_search{query:{match:{user:kimchy}}}2.2 多索引搜索搜索API支持跨多个索引执行可以使用多索引语法搜索指定索引GETtwitter/_search?quser:kimchy搜索多个索引GETkimchy,elasticsearch/_search?qtag:wow搜索所有索引GET_all/_search?qtag:wow使用通配符GETtwitter*/_search?quser:kimchy2.3 搜索端点格式总结端点说明GET /index/_search搜索指定索引GET /index1,index2/_search搜索多个索引GET /*/_search搜索所有索引GET /_search搜索所有索引POST /index/_searchBody模式搜索指定索引注意为了确保快速响应如果一个或多个分片失败搜索API将以部分结果响应HTTP状态码仍为200。相关分片的失败信息记录在响应的shards字段中。三、URI搜索模式3.1 基本语法URI搜索模式通过q参数提供Lucene查询字符串虽然功能不如Body模式的Query DSL丰富但对于快速查询和调试非常方便GETtwitter/_search?quser:kimchy3.2 Lucene查询语法字段查询字段名:值user:kimchy # 搜索user字段包含kimchy的文档 message:hello # 搜索message字段包含hello的文档通配符查询user:k* # 以k开头的用户名 user:*chy # 以chy结尾的用户名 user:k*mchy # 包含k和mchy的用户名布尔运算user:kimchy AND message:hello # 同时满足 user:kimchy OR message:hello # 满足任一 user:kimchy NOT message:hello # 排除范围查询age:[20 TO 30] # 闭区间包含20和30 age:{20 TO 30} # 开区间不包含20和30 age:[20 TO 30} # 半开区间 created:[2024-01-01 TO 2024-12-31] # 日期范围模糊查询user:kimchy~2 # 编辑距离为2的模糊查询短语查询message:quick brown fox # 精确短语匹配分组查询(user:kimchy OR user:elasticsearch) AND message:hello通配符查询所有字段*:* # 匹配所有文档 _message:* # 匹配所有非message字段的文档3.3 查询语法示例对比查询语法含义等价Query DSLuser:kimchyuser字段匹配kimchy{term:{user:kimchy}}user:kimchy AND message:hello同时满足两个条件{bool:{must:[...]}}user:k*mchy~2模糊匹配{wildcard:{...}}{fuzzy:{...}}age:[20 TO 30]范围查询{range:{age:{gte:20,lte:30}}}*:*匹配所有{match_all:{}}四、重要URI参数详解4.1 df默认字段df参数指定当查询字符串中未指定字段时的默认搜索字段GETtwitter/_search?qelasticsearchdfmessage上述查询等价于message:elasticsearch。4.2 analyzer指定分析器analyzer参数指定用于解析查询字符串的分析器GETtwitter/_search?qhello worldanalyzerik_smart4.3 lenient宽松模式lenient参数设置为true时将忽略格式错误的查询而不是返回错误。默认为falseGETtwitter/_search?quser:kimchylenienttrue4.4 explain评分解释explain参数设置为true时响应中将包含每个命中文档的评分计算细节GETtwitter/_search?quser:kimchyexplaintrueExplain API可以帮助分析文档的相关性分数是如何计算的。响应中最重要的是总分和总分的计算过程。如果总分等于0则该文档不匹配给定的查询。两个关键因子是词频Term在某字段中出现的次数和文档频率Term在索引中出现的文档数量。4.5 sort排序sort参数控制结果的排序方式。默认按_score降序排列GETtwitter/_search?qmessage:elasticsearchsortpost_date:desc多字段排序Body模式GETtwitter/_search{query:{match:{message:elasticsearch}},sort:[{post_date:{order:desc}},{_score:{order:desc}}]}按_doc排序不关心排序时使用_doc排序效率最高特别适用于滚动查询GETtwitter/_search?sort_doc4.6 from和size分页from参数定义结果偏移量size参数定义返回的最大结果数GETtwitter/_search?qmessage:elasticsearchfrom0size10参数默认值说明from0结果偏移量size10返回最大结果数注意from size不能超过index.max_result_window的默认值10000。增大会导致系统开销线性增长。深度分页应使用scrollAPI或search_after。4.7 terminate_afterterminate_after参数指定每个分片在收集到足够命中结果后停止查询执行GET_search?qmessage:numbersize0terminate_after1适用于只需要知道是否有文档匹配的场景不关心具体结果。4.8 URI参数完整对比参数说明默认值q查询字符串-df默认搜索字段-analyzer分析器名称索引默认分析器lenient宽松模式falseexplain评分解释falsesort排序字段_scorefrom结果偏移量0size返回结果数10terminate_after每分片最大命中数无限制request_cache请求缓存索引级设置preference分片选择偏好自适应选择timeout搜索超时时间无超时routing路由值-五、搜索分片信息5.1 _search_shards API_search_shardsAPI返回搜索请求将针对其执行的索引和分片信息对于调试路由和分片偏好问题非常有用GETtwitter/_search_shards响应示例{nodes:{r1A2WoRbTwKZ516z6NEs5A:{name:node_1,transport_address:127.0.0.1:9300}},indices:{twitter:{}},shards:[[{index:twitter,node:r1A2WoRbTwKZ516z6NEs5A,primary:true,state:STARTED},{index:twitter,node:r1A2WoRbTwKZ516z6NEs5A,primary:false,state:STARTED}]]}5.2 带路由的分片信息GETtwitter/_search_shards?routingfoo,bar5.3 支持的参数参数说明routing逗号分隔的路由值列表preference控制优先在哪些分片上执行local是否在本地读取集群状态六、搜索响应结构解析6.1 完整响应示例GETtwitter/_search?qmessage:elasticsearch响应如下{took:5,timed_out:false,_shards:{total:5,successful:5,skipped:0,failed:0},hits:{total:{value:1,relation:eq},max_score:1.3862944,hits:[{_index:twitter,_type:_doc,_id:1,_score:1.3862944,_source:{user:kimchy,post_date:2009-11-15T14:12:12,message:Trying out Elasticsearch}}]}}6.2 响应字段详解字段说明took处理请求的毫秒数从接收请求到返回结果timed_out请求是否超时_shards.total搜索涉及的总分片数_shards.successful成功返回结果的分片数_shards.skipped跳过的分片数因优化_shards.failed失败的分片数hits.total.value匹配文档总数hits.total.relation计数精确度eq精确gte下限hits.max_score最高相关度得分hits.hits[]命中文档数组hits.hits[n]._index文档所属索引hits.hits[n]._id文档IDhits.hits[n]._score文档相关度得分hits.hits[n]._source文档原始内容6.3 命中总数追踪track_total_hits参数控制命中总数的精确度精确计数默认GETtwitter/_search{track_total_hits:true,query:{match:{message:elasticsearch}}}限制计数精度GETtwitter/_search{track_total_hits:100,query:{match_all:{}}}命中数在100以内精确计数relation: eq超过100时返回100作为下限relation: gte。不跟踪总数GETtwitter/_search{track_total_hits:false,query:{match:{message:elasticsearch}}}6.4 空结果处理当没有匹配文档时hits数组为空max_score为null{took:2,timed_out:false,_shards:{total:5,successful:5,skipped:0,failed:0},hits:{total:{value:0,relation:eq},max_score:null,hits:[]}}七、URI搜索与Body搜索对比特性URI搜索q参数Body搜索Query DSL复杂度简单完整功能基本查询支持所有查询类型可读性较差URL编码好JSON格式调试快速测试适合生产代码布尔查询AND/OR/NOTbool查询must/should/must_not/filter聚合不支持支持高亮不支持支持排序简单排序支持所有排序方式适用场景快速测试、简单查询生产应用、复杂查询八、总结与最佳实践8.1 核心要点回顾分布式搜索采用Query Phase Fetch Phase两阶段模型先收集排序结果再获取完整文档搜索API支持GET和POST两种方法支持跨索引和多索引搜索URI搜索使用Lucene查询语法适合快速测试和简单查询Body搜索使用Query DSL功能更完整是生产环境的推荐方式分页使用from/size参数但有10000条的限制深度分页需要使用scroll或search_after搜索响应包含took、shards、hits等丰富信息是监控和调试的重要数据来源8.2 生产环境最佳实践优先使用Body搜索在生产代码中始终使用Query DSL避免URI搜索的URL编码问题合理设置size不要设置过大的size值避免一次性返回大量数据利用路由优化带路由的查询只搜索目标分片显著提升搜索效率关注_shards信息监控failed分片数及时发现集群问题使用preference_local在读取密集型场景中使用_local减少网络开销分页优化浅分页使用from/size深分页使用scroll离线处理或search_after实时翻页上一篇【第17篇】Elasticsearch并发控制——refresh参数与乐观并发控制下一篇【第19篇】Elasticsearch Body模式搜索详解——分页、排序与高亮