Elasticsearch搜索原理及詳細(xì)過(guò)程講解
Elasticsearch 的搜索過(guò)程是一個(gè)高效、分布式的流程,設(shè)計(jì)用于在大量數(shù)據(jù)中快速定位相關(guān)信息。以下是其詳細(xì)步驟:
核心流程:分散/聚集模型 (Scatter/Gather)
Elasticsearch 的搜索本質(zhì)上是 分散 請(qǐng)求到相關(guān)分片,然后 聚集/合并 結(jié)果的過(guò)程。
1. 客戶(hù)端發(fā)起請(qǐng)求 (Client Request Initiation)
- 用戶(hù)或應(yīng)用程序向 任意一個(gè) Elasticsearch 節(jié)點(diǎn)(通常通過(guò) REST API)發(fā)送搜索請(qǐng)求 (
GET /<index>/_search)。 - 請(qǐng)求包含查詢(xún) DSL(如
match,term,bool查詢(xún))、過(guò)濾條件、排序、分頁(yè)(from/size)、高亮、聚合等參數(shù)。 - 收到請(qǐng)求的節(jié)點(diǎn)自動(dòng)成為本次搜索請(qǐng)求的 協(xié)調(diào)節(jié)點(diǎn) (Coordinating Node)。
2. 查詢(xún)解析與路由 (Query Parsing & Routing)
- 協(xié)調(diào)節(jié)點(diǎn) 解析查詢(xún) DSL,確定需要搜索哪些 索引 (Indices)。
- 對(duì)于每個(gè)目標(biāo)索引,協(xié)調(diào)節(jié)點(diǎn)根據(jù)索引的 分片 (Shards) 配置(主分片數(shù)量)和 路由策略(通?;谖臋n ID 的哈希):
- 計(jì)算查詢(xún)應(yīng)該發(fā)送到哪些 分片副本 (Shard Replicas)。
- ES 默認(rèn)會(huì)將搜索請(qǐng)求 輪詢(xún) (Round-Robin) 發(fā)送到索引的所有分片(包括主分片和副本分片)的一個(gè)副本。這樣做是為了充分利用所有節(jié)點(diǎn)的資源,實(shí)現(xiàn)負(fù)載均衡。
- 如果查詢(xún)指定了路由參數(shù) (
routing),協(xié)調(diào)節(jié)點(diǎn)會(huì)根據(jù)路由值計(jì)算出目標(biāo)分片 ID,并只將請(qǐng)求發(fā)送到該特定分片(及其副本)。
3. 查詢(xún)階段 - 分散到分片 (Query Phase - Scatter)
- 協(xié)調(diào)節(jié)點(diǎn) 將解析和處理后的搜索請(qǐng)求 并行地 發(fā)送到在步驟 2 中確定的所有 相關(guān)分片副本(目標(biāo)分片的主分片或副本分片)。
- 每個(gè)目標(biāo)分片副本 在其本地獨(dú)立執(zhí)行查詢(xún):
- 加載倒排索引: 查找查詢(xún)?cè)~項(xiàng)在倒排索引中對(duì)應(yīng)的文檔 ID (
_id) 列表。 - 執(zhí)行查詢(xún)邏輯: 根據(jù)查詢(xún)類(lèi)型(布爾組合、短語(yǔ)匹配、范圍查詢(xún)等)處理這些文檔 ID 列表,過(guò)濾掉不匹配的文檔。例如:
Term Query: 直接查找對(duì)應(yīng) term 的倒排列表。Match Query: 分詞后對(duì)每個(gè)詞項(xiàng)查找倒排列表,再按邏輯(如 OR)合并。Bool Query: 組合多個(gè)子查詢(xún)的 MUST/MUST_NOT/SHOULD/FILTER 邏輯。Range Query: 查找數(shù)值或日期范圍字段的倒排索引或 Doc Values。
- 評(píng)分 (Scoring - 如果適用):
- 對(duì)于需要相關(guān)性排序 (
"sort": [{"_score": "desc"}]) 或track_scores: true的查詢(xún),每個(gè)分片使用選定的相似度算法(如 TF/IDF, BM25)計(jì)算匹配文檔的 本地相關(guān)性分?jǐn)?shù) (_score)。評(píng)分基于該分片本地的詞頻、逆文檔頻率等統(tǒng)計(jì)信息。 - FILTER 上下文 中的查詢(xún)條件(如
filter子句、bool的filter或must_not)不參與評(píng)分,只用于二元過(guò)濾,效率通常更高。
- 對(duì)于需要相關(guān)性排序 (
- 構(gòu)建優(yōu)先級(jí)隊(duì)列:
- 每個(gè)分片根據(jù)請(qǐng)求的
size和from(或search_after)參數(shù)以及排序規(guī)則(默認(rèn)按_score降序),在本地維護(hù)一個(gè)優(yōu)先級(jí)隊(duì)列 (Priority Queue)。 - 隊(duì)列的大小是
size + from(對(duì)于 Top-K 結(jié)果合并足夠)。 - 該隊(duì)列保存了當(dāng)前分片本地得分最高(或按指定排序規(guī)則最靠前)的
size + from個(gè)文檔的元數(shù)據(jù):文檔 ID (_id)、分片 ID、排序字段值(主要是 _score)。注意:此時(shí)并不獲取文檔的實(shí)際源數(shù)據(jù) (_source) 或存儲(chǔ)字段。
- 每個(gè)分片根據(jù)請(qǐng)求的
- 加載倒排索引: 查找查詢(xún)?cè)~項(xiàng)在倒排索引中對(duì)應(yīng)的文檔 ID (
4. 查詢(xún)階段 - 聚集結(jié)果 (Query Phase - Gather)
- 所有目標(biāo)分片副本將其本地執(zhí)行的查詢(xún)結(jié)果(即包含文檔 ID、分片 ID、排序值的優(yōu)先級(jí)隊(duì)列)并行地 發(fā)送回 協(xié)調(diào)節(jié)點(diǎn)。
- 協(xié)調(diào)節(jié)點(diǎn) 接收來(lái)自所有分片的結(jié)果。
- 協(xié)調(diào)節(jié)點(diǎn)合并與排序:
- 協(xié)調(diào)節(jié)點(diǎn)將來(lái)自各個(gè)分片的優(yōu)先級(jí)隊(duì)列 合并 成一個(gè)全局的優(yōu)先級(jí)隊(duì)列。
- 這個(gè)全局隊(duì)列的大小是用戶(hù)請(qǐng)求的
size + from。 - 合并時(shí),根據(jù)請(qǐng)求指定的排序規(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ù),仍然沒(méi)有文檔內(nèi)容 (_source)。
5. 取回階段 (Fetch Phase)
- 一旦協(xié)調(diào)節(jié)點(diǎn)確定了全局排序后的最終文檔列表(
from到from + size之間的文檔),它需要獲取這些文檔的完整內(nèi)容 (_source) 和/或任何顯式請(qǐng)求的存儲(chǔ)字段(stored_fields)。 - 協(xié)調(diào)節(jié)點(diǎn) 向 持有這些文檔實(shí)際數(shù)據(jù)的分片 發(fā)送 多文檔獲取請(qǐng)求 (Multi-Get Request / mget)。
- 請(qǐng)求包含需要獲取的文檔的
_id和它們所在的具體分片 ID。
- 請(qǐng)求包含需要獲取的文檔的
- 相關(guān)分片 接收到
mget請(qǐng)求后:- 根據(jù)
_id在其本地存儲(chǔ)中查找對(duì)應(yīng)的文檔。 - 加載 _source: 從存儲(chǔ)(通常是文件系統(tǒng)緩存中的 Lucene 段文件)中讀取文檔的原始 JSON 源數(shù)據(jù) (
_source)。 - 應(yīng)用高亮 (Highlighting): 如果需要,對(duì)
_source中指定字段的內(nèi)容執(zhí)行高亮處理(查找匹配詞并添加高亮標(biāo)簽)。 - 應(yīng)用字段過(guò)濾: 如果請(qǐng)求指定了
_source過(guò)濾(如"_source": ["title", "date"]),則只返回請(qǐng)求的字段。 - 將處理好的文檔數(shù)據(jù)(
_id,_source, 高亮結(jié)果,存儲(chǔ)字段等)返回給協(xié)調(diào)節(jié)點(diǎn)。
- 根據(jù)
6. 最終響應(yīng)組裝與返回 (Response Assembly & Return)
- 協(xié)調(diào)節(jié)點(diǎn) 收集來(lái)自各個(gè)分片的
mget響應(yīng)。 - 它組裝最終的搜索結(jié)果響應(yīng) (Search Response):
hits數(shù)組:包含排好序的實(shí)際文檔數(shù)據(jù) (_source),高亮信息等。數(shù)組長(zhǎng)度由size決定,跳過(guò)前from個(gè)結(jié)果。hits.total:匹配文檔的總數(shù) (這是一個(gè)下限值,如需精確值需設(shè)置track_total_hits: true,代價(jià)較高)。took:整個(gè)搜索請(qǐng)求消耗的總時(shí)間(毫秒)。_shards:報(bào)告參與搜索的分片總數(shù)、成功數(shù)、失敗數(shù)。aggregations(如果請(qǐng)求了聚合):包含聚合結(jié)果。- 其他信息:如是否超時(shí) (
timed_out)、滾動(dòng) ID (_scroll_id) 等。
- 協(xié)調(diào)節(jié)點(diǎn) 將組裝好的最終 JSON 響應(yīng)返回給原始客戶(hù)端。
關(guān)鍵概念與注意事項(xiàng)
分布式本質(zhì):
- 查詢(xún)?cè)诿總€(gè)分片本地并行執(zhí)行,極大提高速度。
- 協(xié)調(diào)節(jié)點(diǎn)負(fù)責(zé)路由、分發(fā)、合并和最終組裝。
深度分頁(yè) (Deep Pagination) 問(wèn)題:
- 當(dāng)
from+size的值非常大時(shí)(如from: 10000, size: 10),每個(gè)分片都需要構(gòu)建一個(gè)大小為 10010 的本地優(yōu)先級(jí)隊(duì)列,協(xié)調(diào)節(jié)點(diǎn)需要合并number_of_shards * 10010個(gè)結(jié)果來(lái)找到全局的 Top 10010,然后只返回最后 10 個(gè)。這對(duì) CPU、內(nèi)存和網(wǎng)絡(luò)帶寬消耗巨大,性能極差。 - 解決方案: 使用
search_after參數(shù)(基于上一頁(yè)最后一個(gè)結(jié)果的排序值)或滾動(dòng) API (scroll)(用于深度遍歷或?qū)С?,非?shí)時(shí))替代傳統(tǒng)的from/size。
- 當(dāng)
相關(guān)性評(píng)分 (_score):
- 評(píng)分在每個(gè)分片本地計(jì)算,基于該分片的本地統(tǒng)計(jì)信息(如 IDF)。這在大集群中通常是足夠準(zhǔn)確的近似值。
- 如果索引非常小或要求極端精確的全局評(píng)分(代價(jià)很高),可設(shè)置
search_type: dfs_query_then_fetch。它會(huì)在查詢(xún)階段增加一個(gè)額外的步驟,先收集所有分片的全局詞頻統(tǒng)計(jì)信息,再分發(fā)下去重新評(píng)分。通常不推薦使用,除非絕對(duì)必要。
聚合 (Aggregations):
- 聚合計(jì)算也是在查詢(xún)階段在每個(gè)分片上并行執(zhí)行的(構(gòu)建桶、計(jì)算指標(biāo))。
- 每個(gè)分片返回其本地聚合結(jié)果(部分桶和指標(biāo))。
- 協(xié)調(diào)節(jié)點(diǎn)負(fù)責(zé)將來(lái)自所有分片的聚合結(jié)果合并成全局聚合結(jié)果(例如,合并桶、累加總和、計(jì)算全局平均值等)。這通常非常高效。
- 某些聚合(如
terms)默認(rèn)返回的是每個(gè)分片的 Top 桶合并后的結(jié)果,可能遺漏低頻項(xiàng)(可通過(guò)增大shard_size緩解)。cardinality和percentiles等聚合使用近似算法。
過(guò)濾上下文 (Filter Context) vs. 查詢(xún)上下文 (Query Context):
- 查詢(xún)上下文: 影響評(píng)分 (
_score),用于全文搜索和相關(guān)性排序。must/should通常在此上下文。 - 過(guò)濾上下文: 只關(guān)心文檔是否匹配(是/否),不評(píng)分。結(jié)果會(huì)被緩存,性能更高。
filter/must_not/constant_score通常在此上下文。將不關(guān)心評(píng)分的條件放入filter可以顯著提升性能。
- 查詢(xún)上下文: 影響評(píng)分 (
緩存:
- 分片級(jí)請(qǐng)求緩存: 緩存整個(gè)查詢(xún)請(qǐng)求的結(jié)果(通常是
size=0的聚合請(qǐng)求或頻繁重復(fù)的查詢(xún))。默認(rèn)開(kāi)啟,但僅緩存特定查詢(xún)(如bool的filter部分)。 - 分片級(jí)查詢(xún)緩存 (Query Cache): Lucene 級(jí)別,緩存查詢(xún)結(jié)果的文檔 ID 位集 (bitset)。對(duì)過(guò)濾 (
filter上下文) 性能提升明顯,但對(duì)文本評(píng)分查詢(xún)效果有限。默認(rèn)開(kāi)啟但大小有限。 - 文件系統(tǒng)緩存: OS 會(huì)將頻繁訪問(wèn)的 Lucene 段文件緩存在內(nèi)存中,極大加速索引讀取。確保有足夠內(nèi)存給文件系統(tǒng)緩存是 ES 性能的關(guān)鍵。
- 分片級(jí)請(qǐng)求緩存: 緩存整個(gè)查詢(xún)請(qǐng)求的結(jié)果(通常是
副本的作用:
- 副本不僅提供高可用性,也能分擔(dān)讀負(fù)載(搜索請(qǐng)求)。協(xié)調(diào)節(jié)點(diǎn)會(huì)將請(qǐng)求發(fā)送到分片副本(主或副),實(shí)現(xiàn)負(fù)載均衡。
總結(jié)流程圖示:
[客戶(hù)端] | | (1. 發(fā)送搜索請(qǐng)求) V [協(xié)調(diào)節(jié)點(diǎn)] | | (2. 解析查詢(xún), 確定目標(biāo)分片) |-------------------------------------------------- | | V (3a. 發(fā)送查詢(xún)請(qǐng)求) V (3a. 發(fā)送查詢(xún)請(qǐng)求) [分片副本 A] [分片副本 B] | (執(zhí)行本地查詢(xún), 構(gòu)建優(yōu)先級(jí)隊(duì)列) | (執(zhí)行本地查詢(xún), 構(gòu)建優(yōu)先級(jí)隊(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請(qǐng)求獲取具體文檔) |-------------------------------------------------- | | V (5b. 返回文檔_source/高亮) V (5b. 返回文檔_source/高亮) [分片副本 A] (持有Doc X) [分片副本 N] (持有Doc Y) | | |<-------------------------------------------------| | V (6. 組裝最終響應(yīng)) [協(xié)調(diào)節(jié)點(diǎn)] | | (返回搜索結(jié)果給客戶(hù)端) V [客戶(hù)端]
理解這個(gè)分散/聚集流程對(duì)于診斷 Elasticsearch 搜索性能問(wèn)題、優(yōu)化查詢(xún) DSL 和配置集群至關(guān)重要。
總結(jié)
到此這篇關(guān)于Elasticsearch搜索原理及詳細(xì)過(guò)程的文章就介紹到這了,更多相關(guān)Elasticsearch搜索原理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java編程中獲取JDK路徑的實(shí)現(xiàn)方式
本文介紹通過(guò)系統(tǒng)屬性、環(huán)境變量、正則表達(dá)式及第三方庫(kù)獲取Java JDK路徑的方法,強(qiáng)調(diào)跨平臺(tái)兼容性,適用于自動(dòng)化部署和構(gòu)建工具配置2025-09-09
SpringBoot @ConfigurationProperties使用詳解
這篇文章主要介紹了SpringBoot @ConfigurationProperties使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
SpringBoot詳細(xì)講解靜態(tài)資源導(dǎo)入的實(shí)現(xiàn)
在Web開(kāi)發(fā)過(guò)程中,我們需要接觸許多靜態(tài)資源,如CSS、JS、圖片等;在之前的開(kāi)發(fā)中,這些資源都放在Web目錄下,用到的時(shí)候按照對(duì)應(yīng)路徑訪問(wèn)即可。不過(guò)在SpringBoot項(xiàng)目中,沒(méi)有了Web目錄,那這些靜態(tài)資源該放到哪里去,又要如何訪問(wèn)呢?這就是我們要講的靜態(tài)資源導(dǎo)入2022-05-05
Java布隆過(guò)濾器的應(yīng)用實(shí)例
這篇文章主要介紹了Java布隆過(guò)濾器的應(yīng)用實(shí)例,在程序的世界中,布隆過(guò)濾器是程序員的一把利器,利用它可以快速地解決項(xiàng)目中一些比較棘手的問(wèn)題,如網(wǎng)頁(yè)?URL?去重、垃圾郵件識(shí)別、大集合中重復(fù)元素的判斷和緩存穿透等問(wèn)題,需要的朋友可以參考下2023-11-11
Java?OpenCV學(xué)習(xí)之Mat的基本操作詳解
OpenCV用來(lái)存儲(chǔ)圖像,很多時(shí)候都會(huì)用到這個(gè)Mat方法。數(shù)字圖像可看做一個(gè)數(shù)值矩陣,?其中的每一個(gè)元素表明一個(gè)像素點(diǎn)。Mat在?OpenCV?中表示的是?N?維稠密矩陣,與稠密矩陣相對(duì)的是稀疏矩陣。本文將重點(diǎn)介紹OpenCV中Mat的一些基本操作,需要的可以參考一下2022-03-03
Java easyExcel實(shí)現(xiàn)導(dǎo)入多sheet的Excel
這篇文章主要為大家詳細(xì)介紹了如何使用Java easyExcel實(shí)現(xiàn)導(dǎo)入多sheet的Excel,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2025-06-06
Java實(shí)現(xiàn)簡(jiǎn)單的銀行管理系統(tǒng)的示例代碼
這篇文章主要介紹了如何利用Java實(shí)現(xiàn)簡(jiǎn)單的銀行管理系統(tǒng),可以實(shí)現(xiàn)存款,取款,查詢(xún)等功能,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-09-09
springboot vue完成編輯頁(yè)面發(fā)送接口請(qǐng)求功能
這篇文章主要為大家介紹了springboot+vue完成編輯頁(yè)發(fā)送接口請(qǐng)求功能,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
JAVA異常處理機(jī)制之throws/throw使用情況
這篇文章主要介紹了JAVA異常處理機(jī)制之throws/throw使用情況的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
springboot+maven多環(huán)境動(dòng)態(tài)配置及編譯失敗的解決方案(步驟詳解)
這篇文章主要介紹了springboot+maven多環(huán)境動(dòng)態(tài)配置及編譯失敗的解決方案,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-11-11

