Elasticsearch
全文檢索的復(fù)雜性
為了理解為什么全文搜索是一個(gè)很難解決的問題,讓我們想一個(gè)例子。 假設(shè)你正在托管一個(gè)博客發(fā)布網(wǎng)站,其中包含數(shù)億甚至數(shù)十億的博客文章,每個(gè)博客文章包含數(shù)百個(gè)單詞,類似于 CSDN。
執(zhí)行全文搜索意味著任何用戶都可以搜索 “java” 或 “學(xué)習(xí)編程” 之類的內(nèi)容,并且你需要在幾毫秒內(nèi)找出出現(xiàn)這些單詞的所有博客文章。 不僅如此,你還需要根據(jù)多種因素對(duì)這些博客文章進(jìn)行評(píng)分,例如,這些單詞在這些帖子中出現(xiàn)的頻率,或者每個(gè)帖子有多少拍手或評(píng)論,或者你可能想在頂部顯示最近寫的帖子,或者你可能想突出顯示某些頂級(jí)內(nèi)容創(chuàng)建者,或者你可能想將這些單詞出現(xiàn)在標(biāo)題中的帖子放在更高的位置,等等。
另外,你知道用戶可能會(huì)意外地犯錯(cuò),因此你需要處理這個(gè)問題。 你還需要考慮單詞的順序,“學(xué)習(xí) Java” 應(yīng)該與 “Java 學(xué)習(xí)” 具有相似的含義,但有時(shí)順序會(huì)更重要,例如 “二氧化碳” 可能與 “化碳二氧” 有很大不同 ”(這只是一個(gè)例子,我不知道這是不是一個(gè)詞,我不懂化學(xué))。
僅僅匹配單詞也是行不通的。 有些詞比其他詞為帖子提供了更多的上下文。 例如,當(dāng)用戶搜索 “Java” 時(shí),標(biāo)題為 “學(xué)習(xí) Java” 的博客文章是相關(guān)結(jié)果,但當(dāng)用戶僅搜索 “學(xué)習(xí)” 時(shí),相關(guān)性就不那么高了。 當(dāng)用戶搜索 “編程” 時(shí),這也是一篇相關(guān)的博客文章,即使該詞從未出現(xiàn)在博客文章中!
這些挑戰(zhàn)極其復(fù)雜,乍一看,它們似乎幾乎無法搜索,但你打開一個(gè)訂餐應(yīng)用程序,在數(shù)千家餐廳的數(shù)萬種菜肴中進(jìn)行搜索,或者搜索執(zhí)行特定工作的人員 每天在 Linkedin 上數(shù)億用戶中發(fā)揮作用,或在數(shù)十億博客文章中搜索特定主題。
Elasticsearch 是一個(gè)旨在解決這個(gè)問題的數(shù)據(jù)庫。 讓我們看看它是如何工作的。
理解術(shù)語
在開始使用 Elasticsearch 之前,我們應(yīng)該先熟悉一下術(shù)語。 為了更好地理解事情,讓我們舉個(gè)例子。 假設(shè)你在 Elasticsearch 上存儲(chǔ)博客文章。
Nodes
節(jié)點(diǎn)只是單獨(dú)的 Elasticsearch 進(jìn)程。
通常,你會(huì)在每臺(tái)機(jī)器上運(yùn)行一個(gè) Elasticsearch 進(jìn)程,因此更容易將它們視為單獨(dú)的服務(wù)器。 這些進(jìn)程中的每一個(gè)都獨(dú)立于其他進(jìn)程運(yùn)行,并且僅通過公共網(wǎng)絡(luò)連接。 Elasticsearch 通常作為大型分布式系統(tǒng)運(yùn)行,這意味著你通常會(huì)運(yùn)行多臺(tái)機(jī)器(或節(jié)點(diǎn))。
一旦所有這些節(jié)點(diǎn)一起運(yùn)行,它們就可以形成一個(gè)“集群 (cluster)”。 集群不僅僅是各個(gè)部分的總和; 它不僅僅是一定數(shù)量的孤立運(yùn)行的節(jié)點(diǎn)。 相反,節(jié)點(diǎn)知道它們是集群的一部分,并在執(zhí)行不同操作時(shí)相互通信。 在某種程度上,Elasticsearch 集群是一個(gè)全新的實(shí)體。
Elasticsearch 集群有大量的職責(zé),例如存儲(chǔ)文檔、搜索這些文檔、執(zhí)行不同的分析和聚合任務(wù)、備份數(shù)據(jù)等。它還必須進(jìn)行自我管理,例如確保哪些節(jié)點(diǎn)是健康的,哪些節(jié)點(diǎn)是健康的 因此,在任何大型集群中,為不同的操作域提供不同的節(jié)點(diǎn)非常重要。
雖然可能存在許多這樣的區(qū)別,但其中一個(gè)明顯的區(qū)別是存儲(chǔ)數(shù)據(jù)并執(zhí)行繁重的數(shù)據(jù)密集型任務(wù)的節(jié)點(diǎn),例如搜索和擁有管理集群的專用節(jié)點(diǎn)、確保節(jié)點(diǎn)健康、決定將哪個(gè)文檔發(fā)送到哪個(gè)節(jié)點(diǎn)等。創(chuàng)建這種區(qū)別很重要,因?yàn)檫@些節(jié)點(diǎn)甚至可能需要不同的硬件資源。 數(shù)據(jù)節(jié)點(diǎn)可能需要更大的機(jī)器,具有更高性能的網(wǎng)絡(luò)和磁盤以及大量?jī)?nèi)存,而執(zhí)行更多管理任務(wù)的節(jié)點(diǎn)可能有完全不同的要求。
存儲(chǔ)數(shù)據(jù)和搜索的節(jié)點(diǎn)可以是 “數(shù)據(jù) (data)” 節(jié)點(diǎn),執(zhí)行更多管理任務(wù)的節(jié)點(diǎn)可以稱為 “主 (master)” 節(jié)點(diǎn)。
有關(guān)節(jié)點(diǎn)的更多描述,請(qǐng)閱讀文章 “Elasticsearch 中的一些重要概念: cluster, node, index, document, shards 及 replica”。事實(shí)上,除了 data 及 master 節(jié)點(diǎn)之外,Elasticsearch 還有其它類型的節(jié)點(diǎn)。
索引和文檔
文檔是你存儲(chǔ)在 Elasticsearch 中的簡(jiǎn)單 JSON 對(duì)象。 它們與關(guān)系數(shù)據(jù)庫中的行或 MongoDB 中的單個(gè)文檔同義。
對(duì)于我們的示例,單個(gè)文檔可能如下所示 -
{
"_id": "9a91473c-522e-4174-bf7f-f55293b8e526",
"post_title": "Learning about Elasticsearch",
"author_name": "Zhang san",
.....
}
索引是相似文檔的集合。 它們與關(guān)系數(shù)據(jù)庫中的表(其中每一行都是單個(gè)項(xiàng)目)和 MongoDB 中的集合同義。
因此,對(duì)于我們的示例,我們將有一個(gè)存儲(chǔ)博客文章的索引。 我們稱之為 blog_posts。 如果我們想存儲(chǔ)一些其他數(shù)據(jù),比如說用戶,我們可以創(chuàng)建另一個(gè)索引,用戶。 blog_posts 索引存儲(chǔ)各種博客文章文檔,每個(gè)文檔都包含與博客文章相關(guān)的字段,而 users 索引存儲(chǔ)包含 user_name、email 等字段的用戶文檔。
Shards - 分片
索引中的文檔被分為多個(gè)分片。 每個(gè)分片存儲(chǔ)索引文檔的某個(gè)子集。 稍后我們會(huì)理解為什么將文檔劃分為多個(gè)分片很重要,但現(xiàn)在我們先關(guān)注分片的工作原理。
例如,假設(shè)我們有一些 blog_posts 文檔。
如果我們?yōu)榇怂饕齽?chuàng)建三個(gè)分片(例如分片 A、分片 B、分片 C),那么我們所有的文檔都將分為這三個(gè)分片。
然后,這些分片將駐留在集群中的不同數(shù)據(jù)節(jié)點(diǎn)中。
這很重要,因?yàn)閷⑦@些文檔分布到多個(gè)分片中可以為你帶來多種優(yōu)勢(shì),
- 搜索可以并行化。 當(dāng)用戶想要執(zhí)行搜索時(shí),將搜索所有文檔。 如果在單個(gè)服務(wù)器上搜索所有文檔,這將非常耗時(shí)。 分片允許你將文檔分布在多個(gè)服務(wù)器上,從而允許在不同的硬件上并行執(zhí)行單個(gè)搜索。
- 其他查詢,例如插入文檔(在 Elasticsearch 中稱為索引)或通過特定 ID 檢索文檔,將分布在所有節(jié)點(diǎn)之間。
然而,我們的架構(gòu)仍然不完整。 如果一個(gè)節(jié)點(diǎn)死亡,它存儲(chǔ)的分片(以及這些分片上的數(shù)據(jù))將永遠(yuǎn)丟失。
讓我們看看主分片 (primary shard) 和副本分片 (replica shard) 以更好地理解這一點(diǎn)。
主分片、副本分片和不同分片(distinct shards)
只是對(duì)到目前為止我們已經(jīng)介紹過的內(nèi)容的快速修訂:?jiǎn)蝹€(gè)分片包含多個(gè)文檔。 例如,
每個(gè)分片都位于一個(gè)特定的節(jié)點(diǎn)上,
到目前為止,我們架構(gòu)的一個(gè)問題是,如果某個(gè)特定節(jié)點(diǎn)(假設(shè) 10.192.0.3)掛掉或變得不可用,“分片 A”中的數(shù)據(jù)將永遠(yuǎn)丟失。 為了解決這個(gè)問題,我們引入 “副本分片” 和 “主分片” 的概念。 主分片是我們到目前為止一直在討論的分片(現(xiàn)在將它們標(biāo)記為“主(Primary)”),
副本分片 (replica shards) 是僅存儲(chǔ)主分片與存儲(chǔ)關(guān)聯(lián)的相同文檔的分片。 因此,副本分片只是 “復(fù)制” 或復(fù)制特定的主分片。
在上圖中,你可以看到每個(gè)主分片都有一個(gè)關(guān)聯(lián)的副本分片,并且每個(gè)副本分片存儲(chǔ)與主分片相同的文檔。 在這里,我們每個(gè)主分片有一個(gè)副本分片,但我們也可以將這個(gè)數(shù)字修改為更大 —— 每個(gè)主分片可以有兩個(gè)副本。 現(xiàn)在,我們繼續(xù)每個(gè)主分片一個(gè)副本。
這些副本分片不需要與主分片位于同一節(jié)點(diǎn)上(每個(gè)副本位于與其主分片不同的節(jié)點(diǎn)上是有意義的)。 主分片和副本分片都分布在集群的所有節(jié)點(diǎn)上。
在上圖中,每個(gè)分片的主分片和副本分片存在于不同的節(jié)點(diǎn)上。 單節(jié)點(diǎn)故障不會(huì)導(dǎo)致數(shù)據(jù)不可用。 例如,如果節(jié)點(diǎn) 10.192.0.3 不可用,則分片 A 和分片 B 的數(shù)據(jù)都不會(huì)丟失。 分片 A 的數(shù)據(jù)在節(jié)點(diǎn) 10.192.0.2 上仍然可用,同樣,分片 B 的數(shù)據(jù)在節(jié)點(diǎn) 10.192.0.1 上仍然可用。
這意味著我們的集群可以在單個(gè)節(jié)點(diǎn)丟失的情況下幸存下來。 然而,我們的集群可能無法在失去兩個(gè)節(jié)點(diǎn)的情況下幸存下來。 例如,10.192.0.3 和10.192.0.2 節(jié)點(diǎn)同時(shí)丟失將導(dǎo)致分片 A 的文檔完全不可用。 我們可以配置更高的復(fù)制,例如,每個(gè)主分片使用兩個(gè)副本來緩解這種情況。 但現(xiàn)在,我們繼續(xù)每個(gè)主分片一個(gè)副本。
最后,我們來看看 “不同分片(distinct shards)”。 不同分片只是一個(gè)術(shù)語,用于將相同的主分片和副本分組在一起。 因此,在我們當(dāng)前的示例中,我們有三個(gè)主分片、三個(gè)副本分片(每個(gè)主分片 1 個(gè)副本)、六個(gè)總分片(三個(gè)主分片 + 三個(gè)副本)和三個(gè)不同的分片,
將主分片及其相應(yīng)的副本分片分組為單個(gè) “不同分片” 如此重要的原因?qū)?huì)變得清晰。 重申一下,“不同分片” 只是分片的邏輯分組,并且確實(shí)影響了我們到目前為止所繪制的架構(gòu)。
我們來看幾個(gè)真實(shí)的查詢示例
為了結(jié)束架構(gòu)討論,讓我們看看搜索查詢和獲取查詢?cè)谖覀兊氖纠褐腥绾喂ぷ鳌?/p>
第一步…
讓我們看看執(zhí)行搜索或獲取查詢時(shí)會(huì)發(fā)生什么。
這就是我們集群現(xiàn)在的樣子,
客戶端 API 向這些節(jié)點(diǎn)中的任何一個(gè)發(fā)送搜索或獲取查詢。 它發(fā)送查詢的節(jié)點(diǎn)成為 “協(xié)調(diào)器(coordinator)” 節(jié)點(diǎn)。 更大的集群甚至可能有專用的協(xié)調(diào)器節(jié)點(diǎn)(專用協(xié)調(diào)器節(jié)點(diǎn)是不具有任何節(jié)點(diǎn)角色的節(jié)點(diǎn),它只可以接收客戶端的請(qǐng)求),但我們現(xiàn)在不需要這樣做。在文章的開始部分,我們可以看到一個(gè)更為詳細(xì)的架構(gòu)圖。
該協(xié)調(diào)器節(jié)點(diǎn)負(fù)責(zé)接收請(qǐng)求、與其他節(jié)點(diǎn)通信(如果需要)、組合從多個(gè)節(jié)點(diǎn)接收到的結(jié)果并返回結(jié)果。
搜索
搜索時(shí),搜索查詢必須命中所有不同的分片。 這是因?yàn)樗蟹制际褂盟鼈兯4娴奈臋n單獨(dú)在本地執(zhí)行搜索。
然后,協(xié)調(diào)器節(jié)點(diǎn)將與多個(gè)節(jié)點(diǎn)通信,以從每個(gè)不同的分片獲取數(shù)據(jù)。 回想一下,在我們的示例中,每個(gè)主分片有一個(gè)副本,因此查詢僅命中集群中的一半分片(主分片或副本分片)。
有關(guān)詳細(xì)的如何完成一個(gè)請(qǐng)求,請(qǐng)閱讀文章 “Elasticsearch:數(shù)據(jù)是如何被讀取的?”。
根據(jù) id 來進(jìn)行查詢
當(dāng)通過 ID 對(duì)特定文檔執(zhí)行查詢時(shí),協(xié)調(diào)器節(jié)點(diǎn)已經(jīng)知道哪個(gè)分片將保存該文檔,因此無需命中所有節(jié)點(diǎn)。 它只是將請(qǐng)求轉(zhuǎn)發(fā)到存儲(chǔ)數(shù)據(jù)的節(jié)點(diǎn)并將響應(yīng)發(fā)送回客戶端。這是因?yàn)槊慨?dāng)一個(gè)文檔進(jìn)來后,根據(jù)文檔的 id 會(huì)自動(dòng)進(jìn)行 hash 計(jì)算,并存放于計(jì)算出來的 shard 實(shí)例中,這樣的結(jié)果可以使得所有的 shard 都比較有均衡的存儲(chǔ),而不至于有的 shard 很忙。
shard_num = hash(_routing) % num_primary_shards
我們可以根據(jù)文檔的 id 來計(jì)算出來是哪一個(gè) shard。
文章來源:http://www.zghlxwxcb.cn/news/detail-764031.html
結(jié)論
這是對(duì) Elasticsearch 架構(gòu)的非常簡(jiǎn)單的介紹。希望大家能對(duì) Elasticsearch 的集群架構(gòu)有一個(gè)比較清楚的認(rèn)識(shí)。更多關(guān)于 Elasticsearch 的術(shù)語及概念介紹,請(qǐng)?jiān)敿?xì)閱讀文章 “Elasticsearch 中的一些重要概念: cluster, node, index, document, shards 及 replica”。文章來源地址http://www.zghlxwxcb.cn/news/detail-764031.html
到了這里,關(guān)于Elasticsearch:搜索架構(gòu)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!