ElasticSearch 入門

jrh_2333發表於2021-06-23

Elasticsearch 簡介

Elasticsearch 是什麼

在探究 Elasticsearch(簡稱ES)是什麼之前,我希望你能搞清楚,ES 是如何誕生的,或者說,ES 的誕生解決了什麼樣的問題。

假設我們的系統資料量達到了十億,百億的級別,在這樣的大規模海量級資料下,我們如何檢索?

  • 傳統關係型資料庫

對於關係型資料庫,我們通常採用以下的架構去解決查詢瓶頸:

解決要點:

  1. 通過主從備份解決資料安全性的問題

  2. 通過資料庫代理中介軟體心跳監測,解決單點故障問題

  3. 通過資料庫代理中介軟體將查詢語句分發到各個 slave 節點進行查詢,並彙總結果,減輕主庫的訪問壓力

  • 非關係型資料庫

對於非關係型資料庫,例如 MongoDB

解決要點:

  1. 通過副本備份保證資料安全性

  2. 通過節點競選機制來解決單點故障問題

  3. 先從配置庫檢索分片資訊,然後將請求分發到各個節點,最後由路由節點合併彙總結果

我們看到,無論是關係型資料庫方案,還是非關係型資料庫方案,我們都需要考慮各種各樣的問題:單點故障,資料安全等等,是否有將上述問題一網打盡的解決方案?

於是,Elasticsearch 誕生了。

Elasticsearch 是一個分散式的開源搜尋和分析引擎;在 Apache Lucene 基礎上開發而成,Elasticsearch 使用 Lucene 作為核心來實現所有索引和搜尋的功能。Elasticsearch 以其簡單的 RESTful API 隱藏了 Lucene 的複雜性,使得讓全文搜尋變得簡單。Elasticsearch 以其分散式特性,速度和可擴充套件性聞名。Elasticsearch 每秒可以處理 PB 級海量資料

Elasticsearch 的用途

  • 應用程式搜尋

  • 網站搜尋

  • 企業搜尋

  • 日誌處理和分析

  • 基礎設施指標和容器監測

  • 應用程式效能測試

  • 地理空間資料分析和視覺化

  • 安全分析

  • 業務分析

Elasticsearch 的核心概念

Cluster

Cluster :叢集,一個 ES 叢集由一個或多個節點(Node)組成,每個叢集都有一個 cluster-name 作為標識。

ES 叢集的健康狀態有三種:green,yellow,red

  • green 為健康狀態; 表示所有的 Primary Shard 以及 Replica Shard 都可以用

  • yellow 為部分故障狀態;表示所有的 Primary Shard 可用,但不是所有的 Replica Shard 都可用

  • red 為嚴重故障狀態;表示不是所有的 Primary Shard 都可用

Node

Node:節點,一個節點就是一個執行的 ES 例項;所謂的執行例項就是一個 ES 的程式,節點可以在同一臺機器上,也可以在不同的機器上,生產環境中建議,每臺伺服器只設定一個節點,執行一個伺服器程式。

在一個分散式系統中,可以通過多個節點組成一個 ES 叢集,這個叢集中有一個節點作為主節點(Master),ES 是去中心化的,如果主節點(Master)掛掉,那麼 Master-eligible 節點可以參加選主流程,成為 Master 節點,所以 ES 不存在所謂的單點故障問題。當第一個節點啟動時,它會將自己選舉成 Master 節點。

Master Node & Master eligible Node

每個節點啟動後,預設就是一個 Master eligible 節點(可以設定 node.master:false 來禁止),Master eligible 節點可以參與選主流程,成為 Master 節點。當第一個節點啟動時,它會將自己選舉成 Master 節點

Master 節點負責管理叢集的狀態,當叢集的拓撲結構改變時,將索引分片分派到相應的節點上。

從使用者的角度來看,主節點在 ElasticSearch 中並沒有佔據著重要的地位,這與其它的系統(比如資料庫系統)是不同的。實際上使用者並不需要知道哪個節點是主節點;所有的操作需求可以分發到任意的節點,ElasticSearch 內部會完成這些讓使用者感到不明覺歷的工作。在必要的情況下,任何節點都可以併發地把查詢子句分發到其它的節點,然後合併各個節點返回的查詢結果。最後返回給使用者一個完整的資料集。所有的這些工作都不需要經過主節點轉發(節點之間通過 P2P 的方式通訊)。

除了 Master Node,Master eligible Node 外,節點還可以分為很多型別,例如 Data NodeIngest NodeTribe Node 等等,在這裡我們就不逐一解釋了。

Shard

Shard:分片;當有大量的文件(Document)時,由於記憶體的限制,磁碟處理能力不足,無法足夠快響應客戶端的請求,ES 的處理機制是將資料分為較小的分片,每個分片分放到不同的伺服器上。當你查詢的索引分佈在多個分片上時,ES 會把查詢傳送給每個相關的分片,並將結果組合在一起,而應用程式是不知道分片的存在的,這個過程對於使用者來說是透明的。

分片分為主分片(primary shard) 以及 從分片(replica shard)。

從分片是主分片的一個副本,當硬體故障或其他因素導致節點伺服器當機,儲存在該節點的主分片失效,其他的節點儲存的從分片會提供備份的作用以防止資料丟失。

Index/Type/Document/Field

ES6 以前

Index/Type/Document/Field 的概念等同於關係型資料庫(例如:MySQL)的資料庫/資料表/行/列

MySQL Elasticsearch
DB Index
Table Type
Row Document
Column Field

不過從 ES7 開始,Type 這個概念正式被廢棄了。

為什麼?因為在 Elasticsearch 設計的初期,是直接參考了關係型資料庫的設計模式,從而設計了 Type(資料表)的概念。但是 ES 本質上是基於 Lucene 的,Lucene 的全文檢索功能之所以這麼快是因為其採用了倒排索引演算法,而倒排索引的生成本身是基於 Index 的,而並非 Type,多個 Type 反而會減慢搜尋的速度。所以,從 ES7 開始,便正式捨棄了 Type

Elasticsearch 基本原理

ES 搜尋引擎的原理

ES 搜尋引擎的原理為:倒排索引。

我們知道 MySQL 的索引使用了 B+樹 這種資料結構。但是如果對於文字而言,B+樹 很顯然就不適用了。

在這裡,我們不會深入探究倒排索引這個演算法,我們只是簡單涉獵,瞭解究竟什麼是倒排索引?

倒排索引是一種使用 “單詞 -> 文件” 儲存格式的演算法,通過倒排索引,我們可以根據單詞快速獲取包含這個單詞的文件列表。

我來舉個例子:

假設我們的文件庫中儲存兩個文件,分別是李白的《靜夜思》和 蘇東坡的《卜運算元》

《卜運算元》
缺月掛疏桐,漏斷人初靜。誰見幽人獨往來,縹緲孤鴻影。
驚起卻回頭,有恨無人省。揀盡寒枝不肯棲,寂寞沙洲冷。
《靜夜思》
床前明月光,疑是地上霜。
舉頭望明月,低頭思故鄉。

所謂的倒序索引,就是單詞到文件的對映,假設我們要檢索的單詞是 “月”

那麼對於這個示例,倒排索引的示意圖大概就是這個樣子的:

ES 節點的通訊

首先,我們能夠與叢集中的任何節點進行通訊,包括主節點。任何一個節點都互相知道文件(Document)存在於哪個節點上,它們可以轉發請求到我們需要資料所在的節點上。我們通訊的節點負責收集各節點返回的資料,最後一起返回給客戶端。這一切都由 Elasticsearch 透明的管理。

Elasticsearch 啟動後,它會利用多播(Multicast)或者單播(Unicast)(使用單播模式通訊需要使用者手動設定)尋找叢集中的其他節點,並與之建立連線:

ES 資料的備份

假設我們當前的叢集只有一個節點,該節點中有三個主分片:p0,p1,p2

為了防止 Node1 掛掉致使整個 Cluster 不可用,我們選擇新增一個 ES 例項。

在我們新增一個節點時,ES 內部會將 Node1 所有的 Primary Shard 備份到新的節點中。

如果主節點掛掉,那麼 Node2 會自動變成主節點,並且 Node2 中的 Repica Shard 會升級為 Primary Shard。

如果我們再新增一個節點呢?

ES 對於分片(Shard)的分配遵循一個原則:Scale horizontally 即:水平擴充套件。所謂的水平擴充套件就是將併發訪問的壓力分散到各個節點上,來減輕每個節點的壓力;至於主分片( Primary Shard)與備份( Repica Shard) 是如何被分配到各個節點的,這是 ES 內部的演算法邏輯來實現的,我們無需關心。

ES 失效節點的處理

在正常工作時,主節點會監控所有的節點,檢視各個節點是否工作正常。如果在指定的時間段,節點無法訪問,那麼該節點就會被視為出現故障,接下來錯誤處理程式就會啟動;如果主節點失效,那麼所有的 Master eligible Node 會通過選舉機制選出一個新的 Master Node。由於該節點出現了故障,那麼分配到該節點的分片丟失,叢集需要重新均衡分片到有效的節點上:

如果 Node3 失效,那麼 Node3 會從 ES Cluster 中被移除,並且 Node2 中備份的 R0 會升級為 P0,各個節點之間會檢測將沒有備份的 Primary Shard 備份好。

Elasticsearch 的安裝

Elasticsearch

版本:Elasticsearch 6.4.3

下載地址:www.elastic.co/cn/downloads/past-r...

下載完畢後,進入到 elasticsearch-6.4.3 /config 目錄下,修改 elasticsearch.yml 檔案

  • cluster.name: 叢集名稱
  • path.data: 存放資料的路徑
  • path.logs: 存放日誌的路徑

配置環境變數,因為我是用的是 Maczsh ,所以需要在 .zshrc 檔案中配置環境變數

  • vi ~/.zshrc

  • export PATH=/Users/macbook/Downloads/elasticsearch-6.4.3/bin:$PATH

  • source .zshrc

配置完畢後,輸入命令

elasticsearch --version

成功返回 ES 的版本號,說明配置成功

➜  bin elasticsearch --version
Java HotSpot(TM) 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
Version: 6.4.3, Build: default/tar/fe40335/2018-10-30T23:17:19.084789Z, JVM: 11.0.8

Elasticsearch ik

推薦下載 ES 中文分詞外掛:elasticsearch ik

版本:elasticsearch-analysis-ik 6.4.3

下載地址:github.com/medcl/elasticsearch-ana...

我們下載好外掛後,需要將該壓縮包解壓到 elasticsearch/plugins/ik 目錄下。

Elasticsearch 的基本使用

在我們安裝好 Elasticsearch 後,進入到 bin 目錄下,執行命令:(double-click elasticsearch.bat on Windows)

elasticsearch

ES 服務就開啟了

  • 檢視叢集的健康狀態

    curl -X GET "localhost:9200/_cat/health?v"

    返回結果:

    ~ curl -X GET "localhost:9200/_cat/health?v"
    epoch      timestamp cluster  status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
    1624379527 00:32:07  test     green           1         1      0   0    0    0        0             0                  -                100.0%

    可以看到,我們的叢集名稱為 test,叢集的健康狀態為 green。

  • 檢視叢集的所有節點

    curl -X GET "localhost:9200/_cat/nodes?v"
  • 獲取所有索引

    curl -X GET "localhost:9200/_cat/indices?v"

    返回結果:

    ~ curl -X GET "localhost:9200/_cat/indices?v"
    health status index uuid pri rep docs.count docs.deleted store.size pri.store.size

    當前我們沒有建立任何索引。

  • 建立索引 “test

    curl -X PUT "localhost:9200/test"

    返回結果:

    ~ curl -X PUT "localhost:9200/test"
    {"acknowledged":true,"shards_acknowledged":true,"index":"test"}%

    再次檢視所有的索引:

    ~ curl -X GET "localhost:9200/_cat/indices?v"
    health status index uuid                   pri rep docs.count docs.deleted store.size pri.store.size
    yellow open   test  5lIDUy-8QcironBi2m8Auw   5   1          0            0      1.1kb          1.1kb

    我們看到,test 索引的健康狀況為 yellow,這是因為,我們在建立該索引時,沒有為這個索引建立任何分片,ES 認為該索引是沒有任何備份的,所以其健康狀況為 yellow

  • 刪除索引 “test

    curl -X DELETE "localhost:9200/test"

    返回結果:

    ~ curl -X DELETE "localhost:9200/test"
    {"acknowledged":true}%

    說明 “test“ 索引刪除成功,再次查詢所有節點:

    ~ curl -X GET "localhost:9200/_cat/indices?v"
    health status index uuid pri rep docs.count docs.deleted store.size pri.store.size

    可以看到,”test“ 索引已被刪除。

  • ES 中 插入/修改 資料(向 test 索引中插入一條 id1 的資料,資料內容見 JSON

  • 查詢資料(查詢索引為 testid1 的資料)

  • 刪除資料 (刪除索引為 testid1 的資料)

  • 搜尋

搜尋是 ES 的重點,我們先向 test 索引中插入三條資料;

搜尋全部內容:

GET: localhost:9200/test/_search

返回結果:

{
    "took": 118,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 3,
        "max_score": 1.0,
        "hits": [
            {
                "_index": "test",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.0,
                "_source": {
                    "title": "網際網路招聘",
                    "content": "招聘一名資深程式設計師"
                }
            },
            {
                "_index": "test",
                "_type": "_doc",
                "_id": "1",
                "_score": 1.0,
                "_source": {
                    "title": "網際網路求職",
                    "content": "尋求一份運營的崗位"
                }
            },
            {
                "_index": "test",
                "_type": "_doc",
                "_id": "3",
                "_score": 1.0,
                "_source": {
                    "title": "實習生推薦",
                    "content": "本人資深Java開發,0薪酬免費給各大公司實習"
                }
            }
        ]
    }
}

title 作為條件進行搜尋,搜尋 title 中包含 “網際網路” 的所有命中結果

GET: localhost:9200/test/_search?q=title:網際網路

返回結果:

{
    "took": 87,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 2,
        "max_score": 0.8630463,
        "hits": [
            {
                "_index": "test",
                "_type": "_doc",
                "_id": "2",
                "_score": 0.8630463,
                "_source": {
                    "title": "網際網路招聘",
                    "content": "招聘一名資深程式設計師"
                }
            },
            {
                "_index": "test",
                "_type": "_doc",
                "_id": "1",
                "_score": 0.8630463,
                "_source": {
                    "title": "網際網路求職",
                    "content": "尋求一份運營的崗位"
                }
            }
        ]
    }
}

content 作為條件進行搜尋,搜尋 content 中包含 “Java” 的所有命中結果

GET localhost:9200/test/_search?q=content:Java

返回結果:

{
    "took": 7,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 1,
        "max_score": 0.2876821,
        "hits": [
            {
                "_index": "test",
                "_type": "_doc",
                "_id": "3",
                "_score": 0.2876821,
                "_source": {
                    "title": "實習生推薦",
                    "content": "本人資深Java開發,0薪酬免費給各大公司實習"
                }
            }
        ]
    }
}

搜尋 titlecontent 中包含 “網際網路” 的所有命中結果

GET: localhost:9200/test/_search

請求頭:

{
    "query":{
        "multi_match":{
            "query":"網際網路",
            "fields":["title","content"]
        }
    }
}

返回結果:

{
    "took": 35,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 3,
        "max_score": 2.1307154,
        "hits": [
            {
                "_index": "test",
                "_type": "_doc",
                "_id": "4",
                "_score": 2.1307154,
                "_source": {
                    "title": "吹水帖子",
                    "content": "網際網路大牛就是我"
                }
            },
            {
                "_index": "test",
                "_type": "_doc",
                "_id": "2",
                "_score": 1.9890311,
                "_source": {
                    "title": "網際網路招聘",
                    "content": "招聘一名資深程式設計師"
                }
            },
            {
                "_index": "test",
                "_type": "_doc",
                "_id": "1",
                "_score": 0.8630463,
                "_source": {
                    "title": "網際網路求職",
                    "content": "尋求一份運營的崗位"
                }
            }
        ]
    }
}

Spring 整合 Elasticsearch

Maven dependency

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

在這裡提供我的 demo 示例,我使用的 Spring Boot version2.1.3.RELEASE

Elasticsearch 版本為 6.4.3

原始碼地址:github.com/jinrunheng/low-version-...

參考文章

www.cnblogs.com/ottll/p/9470732.ht...

www.cnblogs.com/jpfss/p/11505845.h...

blog.csdn.net/duanduanpeng/article...

www.cnblogs.com/dennisit/p/4133131...

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章