Elasticsearch 是一款分散式,RESTful 風格的搜尋和資料分析引擎,可以從海量的資料中高效的找到相關資訊。如 wiki 用 ES 進行全文檢索及其高亮,Github 用其檢索程式碼,電商平臺用其做一些商品推薦等,具有豐富的使用場景。
在本篇文章中,主要涉及以下內容:
- ES 的核心功能及其應用場景的介紹
- ES 邏輯架構(文件,索引)的介紹
- ES 物理架構(叢集,節點,shard 等)的介紹
- ES 環境安裝
- ES 倒排索引
基礎介紹
ES 介紹
Elasticsearch 核心功能:
- 海量資料分散式儲存及其叢集管理
- 服務高可用 - 允許有節點停止服務,但叢集可正常服務
- 資料高可用 - 允許節點丟失,但不會丟失資料
- 可擴充性 - 很好的面對請求量的提升,和資料的不斷增長。
- 大資料實時搜尋引擎
- 結構化資料
- 全文資料
- 地理位置
- 近實時分析
- 聚合
Elasticsearch 核心特性:
- 高效能,非 T +1
- 相較於傳統關係型資料庫,在搜尋,算分,模糊查詢上有非常好的體驗。
- 相較於大資料分析 Hadoop,具有更高效率的統計和分析能力。
- 容易擴充套件
- 本身分散式架構
- 豐富的社群生態
ES 起源歷史
Lucene 是由 Java 開發的一款搜尋引擎類庫,具有高效能,易擴充的優點,但由於其介面只能為 Java ,並且不支援水平擴充的侷限性。
2004 年 Shay Banon 基於 Lucene 開發了 Compass,2010 年 重寫了 Compass,取名 Elasticsearch,使其支援分散式,可水平擴充,並提供 restful 介面,讓任何程式語言進行使用。
ES 生態圈
ES 常常搭配一些產品提供一些解決方案,如常提到的 ELK 就是,ES,Logstash 和 Kibana 的統稱,下圖很好的描述了 ES 家族及其生態。
其中 Beat 相較於 Logstash 更加輕量和便攜。
ES 常用案例架構
ES 搜尋案例,ES 雖然可以單獨可以儲存引擎,但其無法滿足一些事務性的需要,所以常和關係型資料庫搭配,採用如下架構:
ES 日誌和指標分析案例,一般就是指資料收集,入庫,視覺化的過程,常採用如下的架構:
ES 環境搭建
ES 有正常安裝和 docker 安裝兩種方式。考慮的安裝的方便,推薦 docker 的方式,下面是對應的 compose 檔案,直接啟動即可。共有 5 個元件,其中 3 個 ES 叢集,kibana 作為資料展示和操作 es 的重要工具,cerebro 為查詢叢集狀態的工具。
這裡使用的 ES 為 7.1 版本。
# docker-compose.yml
version: '2.2'
services:
cerebro:
image: lmenezes/cerebro:0.8.3
container_name: cerebro
ports:
- "9001:9000"
command:
- -Dhosts.0.host=http://elasticsearch:9200
networks:
- es7net
kibana:
image: docker.elastic.co/kibana/kibana:7.1.0
container_name: kibana7
environment:
- I18N_LOCALE=zh-CN
- XPACK_GRAPH_ENABLED=true
- TIMELION_ENABLED=true
- XPACK_MONITORING_COLLECTION_ENABLED="true"
ports:
- "5601:5601"
networks:
- es7net
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.1.0
container_name: es7_01
environment:
- cluster.name=esdemo
- node.name=es7_01
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- discovery.seed_hosts=es7_01,es7_02,es_03
- cluster.initial_master_nodes=es7_01,es7_02,es_03
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- es7data1:/usr/share/elasticsearch/data
ports:
- 9201:9200
networks:
- es7net
elasticsearch2:
image: docker.elastic.co/elasticsearch/elasticsearch:7.1.0
container_name: es7_02
environment:
- cluster.name=esdemo
- node.name=es7_02
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- discovery.seed_hosts=es7_01,es7_02,es_03
- cluster.initial_master_nodes=es7_01,es7_02,es_03
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- es7data2:/usr/share/elasticsearch/data
networks:
- es7net
elasticsearch3:
image: docker.elastic.co/elasticsearch/elasticsearch:7.1.0
container_name: es7_03
environment:
- cluster.name=esdemo
- node.name=es7_03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- discovery.seed_hosts=es7_01,es7_02,es_03
- cluster.initial_master_nodes=es7_01,es7_02,es_03
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- es7data3:/usr/share/elasticsearch/data
networks:
- es7net
volumes:
es7data1:
driver: local
es7data2:
driver: local
es7data3:
driver: local
networks:
es7net:
driver: bridge
使用 dockr-compose up 命令建立即可:
這裡訪問 http://10.124.207.150:5601/ 即可進入,kibana 管理頁面。
其中開發者工具是學習 ES 非常好的工具,其自動補全功能,可以很好的熟悉 ES 提供的各種 API.
ES 架構
在討論 ES 架構前,我們先來區分兩種型別的架構:
- 一種偏向於開發人員的視角 - 邏輯架構,其中對應索引,文件等概念。
- 一種偏向於運維人員的視角 - 物理架構,如 節點,叢集,分片等。
ES 邏輯架構
文件
ES 中最小的單位為 doc,並且是搜尋資料的最小單位。文件以 JSON 的格式,儲存在 ES 中。每個文件可有不同的欄位型別組成。
下面為一個常見文件的舉例:
其中:
index 可以理解成所在的索引
_type 表示是文件型別,將來該欄位會被廢棄,預設都是 doc 型別。
_id 表示唯一標識文件的指示符。
_seq_no 在併發控制會用到,表示併發更新的序列號。
found 表示該 doc 存在。
_source 是我們真正儲存到 ES 的資訊。
索引
Index - 索引,是多個文件的集合,其體現了邏輯空間的概念,每個索引都有自己的 Mapping 定義,表示文件的欄位名和型別。
其中索引較為重要的設定分為:
- Mapping 設定:定義了文件欄位的型別
- Setting 設定:定義了不同的資料分佈。
同樣看一個索引的例子:
這裡的 mapping 定義了 company,user 兩個屬性。
settings 定義了對應資料以幾個分片和副本分佈在 ES 中,對應物理架構中的概念。
文件和索引的類比
為了方便理解,這裡以我們熟悉的關係型資料庫進行類比。
其中索引的概念,可以理解成資料庫中的一張表,其中 mapping 和 setting 對應表結構和 scheme 的定義。
文件,可以理解成表中的一行記錄。
文件中的 field 可以理解成一行記錄中的某一列內容。
拿實際情況舉例,文件的內容可以想象成日誌檔案的一條日誌記錄,一本電影的具體資訊,一篇 PDF 文件的內容,一本書的內容等等。
ES 物理架構
ES 作為分散式的系統,可以很好的滿足可用性和擴充性。叢集是分散式系統中一個常見的概念,在 ES 叢集中,是由多個 ES 節點組成。而每個節點具有不同的角色。
在最新 ES8 中角色如下:
這裡先著重一些常用節點型別:
節點名稱 | 節點角色 | 節點描述 |
---|---|---|
Master-eligible node | master | 參加叢集的選舉,可以成為 master 節點,進而控制整個叢集,修改叢集的狀態 |
Data Node | data | 儲存資料的節點,負責儲存分片資料,同時執行相關 CRUD,search,agg 操作 |
coordinating node | 預設每個節點都是 coordinating node 節點,接收 client 請求,然後把結果聚合在一起。(實際上分為兩個階段,scatter 節點,會去 data node 請求資料,gather 階段,把資料組合到一起。) | |
Hot & Warm node | data_warm/data_cold | 不同硬體配置的 Data Node,用於降低成本。 |
下圖很好的描述了,ES 水平擴充的過程。
每個 ES 節點,其實就是一個 java 程式,當 ES 叢集中只有一個節點時,本身預設就是一個 master eligible 節點。
master 節點會維護叢集的狀態資訊:
- 所有節點的資訊
- 所有索引和其相關 Mapping 和 Setting 資訊
- 分片的路由資訊
分片與副本
ES 在儲存資料時,會將資料儲存到 Shard 中。Shard 共有兩種型別:
- Primary Shard:將資料分佈在整個叢集內,解決資料水平擴充套件的問題
- 每個 shard 是一個 lucene 例項
- 資料如何分佈在 shard,通過在建立索引時,指定 shard 數量,建立後不允許修改
- Replica Shard:解決資料可用性的問題,是 Primary Shard 的副本
- 副本分片數:可以為 Primary Shard 設定副本的資料,可以動態調整
- 副本可以增加一定的吞吐量
ES 資料結構
我們知道,ES 在搜尋方面有著非常好的效能體驗,這很大就取決於 ES 本身使用了倒排索引作為儲存的資料結構。
wiki 上對倒排索引的定義是這樣:
被用來儲存在全文搜尋下某個單詞在一個文件或者一組文件中的儲存位置的對映。
理解起來很抽象是不是,看一個具體的例子:
假設有這樣三句話,我們想要被搜尋:
I Love Java.
PHP is the best programming language.
Java awesome.
先來看下正排索引的方式,就是常見關係型資料 MySQL 那類的搜尋方式。
正排索引:從 id 到內容的查詢過程
這裡有一行用一個 id 標識對應內容,然後儲存
倒排索引:從內容反向查 id 的過程
將每一句話分詞後,採用 id 加 位置的形式標識。
比如這裡的 java 在文件 1 和 文件 3 都出現了,所以記錄了對應的 id 及其 java 在每句話中的位置。
這時我們想搜尋 java 的相關文件資訊,採用正排索引就需要逐行的遍歷,可以想象效率很差。但通過倒排索引,可以很快的找到相關的文件資訊。
倒排索引有兩部分內容組成:
- 單詞詞典(Term Dictionary),記錄所有文件的單詞,以及單詞到倒排列表的關係
- 一般具體有 B+ 和雜湊拉鍊發實現
- 倒排列表(Posting List),記錄到此對應的文件集合,由倒排索引項組成。
- 倒排索引項:
- 文件 ID
- 詞頻 TF:該單詞在文件中出現的次數,相關性評分
- 位置 - 單詞在文件中分詞的位置,用於語句搜尋。
- 偏移 - 記錄單詞的開始和結束位置,高亮顯示。
- 倒排索引項:
比如上面的 Java 就組成的倒排索引就是這個樣子:
單詞 ID | 詞項內容 | 倒排列表(doc_id/TF/POS/Offset) |
---|---|---|
1 | java | [(1/1/2/4), (3/1/1/4)] |
當想要搜尋 java 時,會查詢由 B+ 或者雜湊拉鍊法構成的單詞詞典,然後根據詞典記錄的倒排列表關係,獲取相應的倒排列表。
總結
本篇文章是 ES 部分的第一篇文章,主要對 ES 的基本概念,安裝方式,整體架構,資料結構做了整體的入門介紹,便於對 ES 有一定初步的認識,後續的文章對某些部分進入深入的講解。
最後分享功夫熊貓中的一段話:
昨天已成過去,明天還沒有到來,但今天是一個禮物。?