Elasticsearch搜索原理及詳細(xì)過程講解
Elasticsearch 的搜索過程是一個(gè)高效、分布式的流程,設(shè)計(jì)用于在大量數(shù)據(jù)中快速定位相關(guān)信息。以下是其詳細(xì)步驟:
核心流程:分散/聚集模型 (Scatter/Gather)
Elasticsearch 的搜索本質(zhì)上是 分散 請求到相關(guān)分片,然后 聚集/合并 結(jié)果的過程。
1. 客戶端發(fā)起請求 (Client Request Initiation)
- 用戶或應(yīng)用程序向 任意一個(gè) Elasticsearch 節(jié)點(diǎn)(通常通過 REST API)發(fā)送搜索請求 (
GET /<index>/_search)。 - 請求包含查詢 DSL(如
match,term,bool查詢)、過濾條件、排序、分頁(from/size)、高亮、聚合等參數(shù)。 - 收到請求的節(jié)點(diǎn)自動成為本次搜索請求的 協(xié)調(diào)節(jié)點(diǎn) (Coordinating Node)。
2. 查詢解析與路由 (Query Parsing & Routing)
- 協(xié)調(diào)節(jié)點(diǎn) 解析查詢 DSL,確定需要搜索哪些 索引 (Indices)。
- 對于每個(gè)目標(biāo)索引,協(xié)調(diào)節(jié)點(diǎn)根據(jù)索引的 分片 (Shards) 配置(主分片數(shù)量)和 路由策略(通?;谖臋n ID 的哈希):
- 計(jì)算查詢應(yīng)該發(fā)送到哪些 分片副本 (Shard Replicas)。
- ES 默認(rèn)會將搜索請求 輪詢 (Round-Robin) 發(fā)送到索引的所有分片(包括主分片和副本分片)的一個(gè)副本。這樣做是為了充分利用所有節(jié)點(diǎn)的資源,實(shí)現(xiàn)負(fù)載均衡。
- 如果查詢指定了路由參數(shù) (
routing),協(xié)調(diào)節(jié)點(diǎn)會根據(jù)路由值計(jì)算出目標(biāo)分片 ID,并只將請求發(fā)送到該特定分片(及其副本)。
3. 查詢階段 - 分散到分片 (Query Phase - Scatter)
- 協(xié)調(diào)節(jié)點(diǎn) 將解析和處理后的搜索請求 并行地 發(fā)送到在步驟 2 中確定的所有 相關(guān)分片副本(目標(biāo)分片的主分片或副本分片)。
- 每個(gè)目標(biāo)分片副本 在其本地獨(dú)立執(zhí)行查詢:
- 加載倒排索引: 查找查詢詞項(xiàng)在倒排索引中對應(yīng)的文檔 ID (
_id) 列表。 - 執(zhí)行查詢邏輯: 根據(jù)查詢類型(布爾組合、短語匹配、范圍查詢等)處理這些文檔 ID 列表,過濾掉不匹配的文檔。例如:
Term Query: 直接查找對應(yīng) term 的倒排列表。Match Query: 分詞后對每個(gè)詞項(xiàng)查找倒排列表,再按邏輯(如 OR)合并。Bool Query: 組合多個(gè)子查詢的 MUST/MUST_NOT/SHOULD/FILTER 邏輯。Range Query: 查找數(shù)值或日期范圍字段的倒排索引或 Doc Values。
- 評分 (Scoring - 如果適用):
- 對于需要相關(guān)性排序 (
"sort": [{"_score": "desc"}]) 或track_scores: true的查詢,每個(gè)分片使用選定的相似度算法(如 TF/IDF, BM25)計(jì)算匹配文檔的 本地相關(guān)性分?jǐn)?shù) (_score)。評分基于該分片本地的詞頻、逆文檔頻率等統(tǒng)計(jì)信息。 - FILTER 上下文 中的查詢條件(如
filter子句、bool的filter或must_not)不參與評分,只用于二元過濾,效率通常更高。
- 對于需要相關(guān)性排序 (
- 構(gòu)建優(yōu)先級隊(duì)列:
- 每個(gè)分片根據(jù)請求的
size和from(或search_after)參數(shù)以及排序規(guī)則(默認(rèn)按_score降序),在本地維護(hù)一個(gè)優(yōu)先級隊(duì)列 (Priority Queue)。 - 隊(duì)列的大小是
size + from(對于 Top-K 結(jié)果合并足夠)。 - 該隊(duì)列保存了當(dāng)前分片本地得分最高(或按指定排序規(guī)則最靠前)的
size + from個(gè)文檔的元數(shù)據(jù):文檔 ID (_id)、分片 ID、排序字段值(主要是 _score)。注意:此時(shí)并不獲取文檔的實(shí)際源數(shù)據(jù) (_source) 或存儲字段。
- 每個(gè)分片根據(jù)請求的
- 加載倒排索引: 查找查詢詞項(xiàng)在倒排索引中對應(yīng)的文檔 ID (
4. 查詢階段 - 聚集結(jié)果 (Query Phase - Gather)
- 所有目標(biāo)分片副本將其本地執(zhí)行的查詢結(jié)果(即包含文檔 ID、分片 ID、排序值的優(yōu)先級隊(duì)列)并行地 發(fā)送回 協(xié)調(diào)節(jié)點(diǎn)。
- 協(xié)調(diào)節(jié)點(diǎn) 接收來自所有分片的結(jié)果。
- 協(xié)調(diào)節(jié)點(diǎn)合并與排序:
- 協(xié)調(diào)節(jié)點(diǎn)將來自各個(gè)分片的優(yōu)先級隊(duì)列 合并 成一個(gè)全局的優(yōu)先級隊(duì)列。
- 這個(gè)全局隊(duì)列的大小是用戶請求的
size + from。 - 合并時(shí),根據(jù)請求指定的排序規(guī)則(默認(rèn)
_score降序)決定文檔在全局結(jié)果中的最終順序。 - 關(guān)鍵點(diǎn): 協(xié)調(diào)節(jié)點(diǎn)此時(shí)只持有全局 Top
(size + from)結(jié)果的 文檔 ID (_id)、分片位置、_score 等排序元數(shù)據(jù),仍然沒有文檔內(nèi)容 (_source)。
5. 取回階段 (Fetch Phase)
- 一旦協(xié)調(diào)節(jié)點(diǎn)確定了全局排序后的最終文檔列表(
from到from + size之間的文檔),它需要獲取這些文檔的完整內(nèi)容 (_source) 和/或任何顯式請求的存儲字段(stored_fields)。 - 協(xié)調(diào)節(jié)點(diǎn) 向 持有這些文檔實(shí)際數(shù)據(jù)的分片 發(fā)送 多文檔獲取請求 (Multi-Get Request / mget)。
- 請求包含需要獲取的文檔的
_id和它們所在的具體分片 ID。
- 請求包含需要獲取的文檔的
- 相關(guān)分片 接收到
mget請求后:- 根據(jù)
_id在其本地存儲中查找對應(yīng)的文檔。 - 加載 _source: 從存儲(通常是文件系統(tǒng)緩存中的 Lucene 段文件)中讀取文檔的原始 JSON 源數(shù)據(jù) (
_source)。 - 應(yīng)用高亮 (Highlighting): 如果需要,對
_source中指定字段的內(nèi)容執(zhí)行高亮處理(查找匹配詞并添加高亮標(biāo)簽)。 - 應(yīng)用字段過濾: 如果請求指定了
_source過濾(如"_source": ["title", "date"]),則只返回請求的字段。 - 將處理好的文檔數(shù)據(jù)(
_id,_source, 高亮結(jié)果,存儲字段等)返回給協(xié)調(diào)節(jié)點(diǎn)。
- 根據(jù)
6. 最終響應(yīng)組裝與返回 (Response Assembly & Return)
- 協(xié)調(diào)節(jié)點(diǎn) 收集來自各個(gè)分片的
mget響應(yīng)。 - 它組裝最終的搜索結(jié)果響應(yīng) (Search Response):
hits數(shù)組:包含排好序的實(shí)際文檔數(shù)據(jù) (_source),高亮信息等。數(shù)組長度由size決定,跳過前from個(gè)結(jié)果。hits.total:匹配文檔的總數(shù) (這是一個(gè)下限值,如需精確值需設(shè)置track_total_hits: true,代價(jià)較高)。took:整個(gè)搜索請求消耗的總時(shí)間(毫秒)。_shards:報(bào)告參與搜索的分片總數(shù)、成功數(shù)、失敗數(shù)。aggregations(如果請求了聚合):包含聚合結(jié)果。- 其他信息:如是否超時(shí) (
timed_out)、滾動 ID (_scroll_id) 等。
- 協(xié)調(diào)節(jié)點(diǎn) 將組裝好的最終 JSON 響應(yīng)返回給原始客戶端。
關(guān)鍵概念與注意事項(xiàng)
分布式本質(zhì):
- 查詢在每個(gè)分片本地并行執(zhí)行,極大提高速度。
- 協(xié)調(diào)節(jié)點(diǎn)負(fù)責(zé)路由、分發(fā)、合并和最終組裝。
深度分頁 (Deep Pagination) 問題:
- 當(dāng)
from+size的值非常大時(shí)(如from: 10000, size: 10),每個(gè)分片都需要構(gòu)建一個(gè)大小為 10010 的本地優(yōu)先級隊(duì)列,協(xié)調(diào)節(jié)點(diǎn)需要合并number_of_shards * 10010個(gè)結(jié)果來找到全局的 Top 10010,然后只返回最后 10 個(gè)。這對 CPU、內(nèi)存和網(wǎng)絡(luò)帶寬消耗巨大,性能極差。 - 解決方案: 使用
search_after參數(shù)(基于上一頁最后一個(gè)結(jié)果的排序值)或滾動 API (scroll)(用于深度遍歷或?qū)С?,非?shí)時(shí))替代傳統(tǒng)的from/size。
- 當(dāng)
相關(guān)性評分 (_score):
- 評分在每個(gè)分片本地計(jì)算,基于該分片的本地統(tǒng)計(jì)信息(如 IDF)。這在大集群中通常是足夠準(zhǔn)確的近似值。
- 如果索引非常小或要求極端精確的全局評分(代價(jià)很高),可設(shè)置
search_type: dfs_query_then_fetch。它會在查詢階段增加一個(gè)額外的步驟,先收集所有分片的全局詞頻統(tǒng)計(jì)信息,再分發(fā)下去重新評分。通常不推薦使用,除非絕對必要。
聚合 (Aggregations):
- 聚合計(jì)算也是在查詢階段在每個(gè)分片上并行執(zhí)行的(構(gòu)建桶、計(jì)算指標(biāo))。
- 每個(gè)分片返回其本地聚合結(jié)果(部分桶和指標(biāo))。
- 協(xié)調(diào)節(jié)點(diǎn)負(fù)責(zé)將來自所有分片的聚合結(jié)果合并成全局聚合結(jié)果(例如,合并桶、累加總和、計(jì)算全局平均值等)。這通常非常高效。
- 某些聚合(如
terms)默認(rèn)返回的是每個(gè)分片的 Top 桶合并后的結(jié)果,可能遺漏低頻項(xiàng)(可通過增大shard_size緩解)。cardinality和percentiles等聚合使用近似算法。
過濾上下文 (Filter Context) vs. 查詢上下文 (Query Context):
- 查詢上下文: 影響評分 (
_score),用于全文搜索和相關(guān)性排序。must/should通常在此上下文。 - 過濾上下文: 只關(guān)心文檔是否匹配(是/否),不評分。結(jié)果會被緩存,性能更高。
filter/must_not/constant_score通常在此上下文。將不關(guān)心評分的條件放入filter可以顯著提升性能。
- 查詢上下文: 影響評分 (
緩存:
- 分片級請求緩存: 緩存整個(gè)查詢請求的結(jié)果(通常是
size=0的聚合請求或頻繁重復(fù)的查詢)。默認(rèn)開啟,但僅緩存特定查詢(如bool的filter部分)。 - 分片級查詢緩存 (Query Cache): Lucene 級別,緩存查詢結(jié)果的文檔 ID 位集 (bitset)。對過濾 (
filter上下文) 性能提升明顯,但對文本評分查詢效果有限。默認(rèn)開啟但大小有限。 - 文件系統(tǒng)緩存: OS 會將頻繁訪問的 Lucene 段文件緩存在內(nèi)存中,極大加速索引讀取。確保有足夠內(nèi)存給文件系統(tǒng)緩存是 ES 性能的關(guān)鍵。
- 分片級請求緩存: 緩存整個(gè)查詢請求的結(jié)果(通常是
副本的作用:
- 副本不僅提供高可用性,也能分擔(dān)讀負(fù)載(搜索請求)。協(xié)調(diào)節(jié)點(diǎn)會將請求發(fā)送到分片副本(主或副),實(shí)現(xiàn)負(fù)載均衡。
總結(jié)流程圖示:
[客戶端] | | (1. 發(fā)送搜索請求) V [協(xié)調(diào)節(jié)點(diǎn)] | | (2. 解析查詢, 確定目標(biāo)分片) |-------------------------------------------------- | | V (3a. 發(fā)送查詢請求) V (3a. 發(fā)送查詢請求) [分片副本 A] [分片副本 B] | (執(zhí)行本地查詢, 構(gòu)建優(yōu)先級隊(duì)列) | (執(zhí)行本地查詢, 構(gòu)建優(yōu)先級隊(duì)列) | (4a. 返回文檔ID/分片/分?jǐn)?shù)隊(duì)列) | (4a. 返回文檔ID/分片/分?jǐn)?shù)隊(duì)列) | | |<-------------------------------------------------| | V [協(xié)調(diào)節(jié)點(diǎn)] | (4b. 合并所有分片的隊(duì)列, 確定全局Top-K) | | (5a. 發(fā)送mget請求獲取具體文檔) |-------------------------------------------------- | | V (5b. 返回文檔_source/高亮) V (5b. 返回文檔_source/高亮) [分片副本 A] (持有Doc X) [分片副本 N] (持有Doc Y) | | |<-------------------------------------------------| | V (6. 組裝最終響應(yīng)) [協(xié)調(diào)節(jié)點(diǎn)] | | (返回搜索結(jié)果給客戶端) V [客戶端]
理解這個(gè)分散/聚集流程對于診斷 Elasticsearch 搜索性能問題、優(yōu)化查詢 DSL 和配置集群至關(guān)重要。
總結(jié)
到此這篇關(guān)于Elasticsearch搜索原理及詳細(xì)過程的文章就介紹到這了,更多相關(guān)Elasticsearch搜索原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
LibrarySystem圖書管理系統(tǒng)開發(fā)(一)
這篇文章主要為大家詳細(xì)介紹了LibrarySystem圖書管理系統(tǒng)開發(fā),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05
SpringBoot集成Aviator實(shí)現(xiàn)參數(shù)校驗(yàn)的示例代碼
在實(shí)際開發(fā)中,參數(shù)校驗(yàn)是保障系統(tǒng)穩(wěn)定和數(shù)據(jù)可靠性的重要措施,Aviator 是一個(gè)高性能的表達(dá)式引擎,它能夠簡化復(fù)雜的邏輯判斷并提升參數(shù)校驗(yàn)的靈活性,本文將介紹如何在 Spring Boot 中集成 Aviator,并利用它來實(shí)現(xiàn)靈活的參數(shù)校驗(yàn),需要的朋友可以參考下2025-02-02
java對xml節(jié)點(diǎn)屬性的增刪改查實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄猨ava對xml節(jié)點(diǎn)屬性的增刪改查實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-10-10
合并有序數(shù)組的實(shí)現(xiàn)(java與C語言)
這篇文章主要介紹了合并有序數(shù)組的實(shí)現(xiàn)(java與C語言)的相關(guān)資料,這里對有序數(shù)組的合并分享了java版本和C語言版本的示例,需要的朋友可以參考下2017-08-08

