1、ElasticSearch簡介
Elasticsearch是一個基於Apache Lucene(TM)的開源搜索引擎。無論在開源還是專有領域,Lucene可以被認為是迄今為止最先進、性能最好的、功能最全的搜索引擎庫。 但是,Lucene只是一個庫。想要使用它,你必須使用Java來作為開發語言並將其直接集成到你的應用中,更糟糕的是,Lucene非常復雜,你需要深入了解檢索的相關知識來理解它是如何工作的。 Elasticsearch也使用Java開發並使用Lucene作為其核心來實現所有索引和搜索的功能,但是它的目的是通過簡單的 **RESTful API** 來隱藏Lucene的復雜性,從而讓全文搜索變得簡單。
2、同類產品比較solr
Solr 是Apache下的一個頂級開源項目,采用Java開發,它是基於Lucene的全文搜索服務器。Solr提供了比Lucene更為豐富的查詢語言,同時實現了可配置、可擴展,並對索引、搜索性能進行了優化 。並自帶了圖形管理界面。
- 數據相對少的請求下Solr的檢索效率更高
- 建立索引時,Solr會產生阻塞IO,查詢性能較差,ElasticSearch有優勢
- 數據量大時,Solr的搜索效率變低,而ElasticSearch沒有明顯變化
- 安裝使用方面ElasticSearch更為簡單
總結:
- solr查詢快,但更新索引時慢(即插入刪除慢),用於電商等查詢多的應用,比如商品搜索 。
- ES建立索引快(即查詢慢),即實時性查詢快,適用用於數據頻繁更新的應用,比如facebook新浪等搜索。
- Solr 是傳統搜索應用的有力解決方案,但 Elasticsearch 更適用於新興的實時搜索應用。
- ES沒有Solr成熟,學習成本相對較高。
二、ElasticSearch安裝和可視化界面Elasticsearch-Head
1、ElasticSearch安裝
下載Es安裝包:
ElasticSearch的官方地址:https://www.elastic.co/guide/en/elasticsearch/reference/master/index.html
安裝(如Mac OS):
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.9.3-darwin-x86_64.tar.gz wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.9.3-darwin-x86_64.tar.gz.sha512 shasum -a 512 -c elasticsearch-7.9.3-darwin-x86_64.tar.gz.sha512 tar -xzf elasticsearch-7.9.3-darwin-x86_64.tar.gz cd elasticsearch-7.9.3/
啟動命令如下(-d以進程的形式啟動elasticsearch,-p表示進程號記錄到pid文件中):
./bin/elasticsearch -d -p pid
2、ES圖形化管理界面安裝
2.1、安裝elasticsearch-head和Node.js
- 下載head:https://github.com/mobz/elasticsearch-head
- 下載Node.js:https://nodejs.org/en/download
注意elasticsearch和elasticsearch-head版本是對應的,否則會出現head無法支持elasticsearch的顯示。
安裝完成 在cmd窗口執行node -v查看node.js的版本號 檢查是否安裝成功。
2.2、安裝grunt
通過node.js的包管理器npm安裝grunt為全局,grunt是基於Node.js的項目構建工具
npm install -g grunt-cli
2.3、執行 npm install
注:不執行該命寧 使用grunt server命令會報錯。
npm install
2.4、啟動elasticsearch-head
打開命寧窗口在elasticsearch-head解壓目錄下執行 grunt server 啟動服務:
HoudeMacBook-Pro:elasticsearch-head houjing$ grunt server Running "connect:server" (connect) task Waiting forever... Started connect web server on http://localhost:9100
然后訪問 http://localhost:9100 (elasticsearch-head服務端口)。
2.5、配置ElasticSearch跨域訪問
修改 config/elasticsearch.yml 文件
http.cors.enabled: true http.cors.allow-origin: "*"
注:需要重啟ES服務。
2.6、head訪問
在head頁面輸入鏈接的ElasticSearch地址,點擊連接按鈕。
三、 ElasticSearch的相關概念
1、概述
Elasticsearch是面向文檔(document oriented)的,這意味着它可以存儲整個對象或文檔(ducoment)。然而它不僅僅是存儲,還會索引(index)每個文檔的內容使之能搜索。在Elasticsearch中,你可以對文檔(而非成行成列的數據 )進行索引、排序、過濾。Elasticsearch比傳統關系型數據庫如下。
關系型數據庫 -> Databases -> Tables -> Rows -> Colums
ElasticSearch -> Indices -> Types(7版本已經沒有此概念,相當於一個Database只有一張table) ->Documents -> Fields
2、ElasticSearch的核心概念
2.1、索引 index
一個索引就是有相似特征的文檔集合,比如用戶數據索引、訂單數據索引、商品數據索引。
一個索引由一個全為小寫字母的名字標識,我們在對應這個索引文檔中進行索引、搜索、更新和刪除的時候,都要使用到這個名字。在一個群集中可以定義任意多個索引。
2.2、類型type
在一個索引中,你可以定義一個或多個類型,一個類型是你的索引的一個邏輯上的分類,其語義完全由你來定。通常,會為具有一組共同字段的文檔定義一個類型,比如說,我們訂單數據索引中我們把訂單信息作為一個類型,訂單相關的物流信息做為一個類型。但在6.0開始建議index只包含一個type,在7.0之后開始去除(也並不是完全去除,而是默認為了_doc)。
2.3、字段field
相當於是數據表的字段,對文檔根據不同的屬性進行的分類標識。
2.4、映射 mapping (表結構)
mapping是處理數據的方式和規則方面做一些限制,如某個字段的數據類型、默認值、分析器、是否被索引等等,這些都是映射里面可以設置的,其他的就是處理es里面的數據的一些使用規則設置也叫做映射,按着最優規則處理數據對性能提高很大,因此才需要建立映射,並且需要思考如何建立隱射才能對性能更好。
3.2.5、文檔 document
一個文檔是一個可被索引的基礎單元。文檔以JSON格式來表示,而JSON是一個到處存在的互聯網數據交互格式。
在一個index/type里面,你可以存儲任意多的文檔。
2.6、ElasticSearch版本問題說明
Elasticsearch 官網提出的近期版本對 type 概念的演變情況如下:
- 在 5.X 版本中,一個 index 下可以創建多個 type;
- 在 6.X 版本中,一個 index 下只能存在一個 type;
- 在 7.X 版本中,直接去除了 type的概念,就是說 index 不再會有 type。
去除type的原因 :
因為 Elasticsearch 設計初期,是直接查考了關系型數據庫的設計模式,存在了 type(數據表)的概念。但是,其搜索引擎是基於 Lucene的,這種 “基因”決定了 type 是多余的。Lucene 的全文檢索功能之所以快,是因為倒序索引的存在。而這種倒序索引的生成是基於 index 的,而並非 type。
四、 ElasticSearch基本操作
基本操作在學習過程中可以使用單測工具進行,可以使用postman、jmeter,因為是使用http請求操作Es, 必須對RESTful 風格有所了解,所以在學習基本操作前,對RESTful 知識進行補充:
RESTful 在兩方面做了相應規范:
- 服務數據交互格式使用json、xml。
- 采用HTTP協議規定的GET、POST、PUT、DELETE動作處理資源的增刪該查操作。
1、ElasticSearch語法
mapping字段詳解:
type 可選類型:
2、通過HTTP請求創建
2.1、僅創建索引
請求方式選擇Put;請求鏈接如:http://127.0.0.1:9200/news 。結果:
{ "acknowledged": true, "shards_acknowledged": true, "index": "news" }
2.2、創建索引的同時創建mapping 以及分片復制參數
{ "settings": { "number_of_shards": 5, "number_of_replicas": 1, "refresh_interval": "30s", "index.analysis.analyzer.default.type": "ik_max_word" //分詞器,未指定默認elastic自帶的分詞器,對中文支持差。 }, "mappings": { "properties": { "newsid": { "type": "text", "store": false, "index": true, "analyzer": "standard" }, "newsname": { "type": "text", "store": false, "index": true }, "newsdesc": { "type": "text", "store": false, "index": true } } } }
2.3、刪除索引庫
請求方式選擇Delete,請求鏈接如:http://127.0.0.1:9200/news 刪除news索引:
{ "acknowledged": true }
2.4、向索引庫中添加文檔
請求方式選 POST,單條插入請求url:
- http://127.0.0.1:9200/news/_doc/1 (索引/"**_doc**"/文檔id)
- http://127.0.0.1:9200/news/_doc
文檔id為Es中的文檔主鍵id,不指定的情況下Es會給我們生成一個唯一的隨機字符串,如 BU7pG24Bm2YrPBUaN0wD
{ "newsid":"1234", "newsname":"你猜不到的名字", "newsdesc":"這是一條新聞描述" }
如結果:
{ "_index": "news", "_type": "_doc", "_id": "1", "_version": 1, "result": "created", "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1 }
批量添加,請求url: http://127.0.0.1:9200/news/_bulk
{ "index":{} } { "newsid":"1234656","newsname":"miumiu" ,"newsdesc":"親承5為自己生下5個孩子 此前12個" } { "index":{} } { "newsid":"1234657","newsname":"乒聯" ,"newsdesc":"國際乒聯奧地利公開賽正賽展開" } { "index":{"_id":"iikdjsd"} } { "newsid":"1234658","newsname":"紛紛兩連敗" ,"newsdesc":"兩連敗+二當家傷停再遭困境 考驗歐文.." } { "index":{"_id":"iik3325"} } { "newsid":"1234659","newsname":"紛紛返回" ,"newsdesc":"33+9+4+5誤!這是最喬治!黑貝最.." }
index可以指定參數,比如指定id,不指定則默認生成id。
2.5、刪除文檔
請求方式選擇Delete,請求url : http://127.0.0.1:9200/news/_doc/1 (索引/"**_doc**"/文檔id)
2.6、查詢文檔
請求方式選擇Get,請求url : http://127.0.0.1:9200/news/_doc/1 (索引/"**_doc**"/文檔id)
2.7、修改文檔
請求方式選擇POST,請求url : http://127.0.0.1:9200/news/_doc/1 (索引/"**_doc**"/文檔id)
{ "newsname":"the new news name" }
注意修改跟Mysql修改不一樣,如上值提供了newsname時,修改后其余字段均為空:
2.8、根據關鍵詞查詢
請求方式選擇Get:請求url http://127.0.0.1:9200/shop/_doc/_search (索引/"_doc"/"_search")
請求參數query、term為固定命名,newsdesc為指定在哪個字段查詢什么關鍵字(支持什么樣的關鍵字查詢取決於mapping里指定的分析器,比如單個字為索引、分詞索引,之前測試的語句都是標准分詞,以單個字為索引,所以查詢的時候只支持一個漢字,如果輸入多個則查詢不到數據)
基本查詢:
{ "query": { "term": { "newsdesc": "國際" } } }
可以看出並未命中:
{ "took": 1, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 0, "relation": "eq" }, "max_score": null, "hits": [] } }
queryString是講輸入參數進行分詞然后去索引庫中檢索:
{ "query": { "query_string": { "default_field": "newsdesc", "query": "國際" } } }
可以看到查詢命中了:
{ "took": 20, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": { "value": 1, "relation": "eq" }, "max_score": 0.5753642, "hits": [ { "_index": "news", "_type": "_doc", "_id": "EZrseHUBe8Ie4tIUuaQ_", "_score": 0.5753642, "_source": { "newsid": "1234657", "newsname": "乒聯", "newsdesc": "國際乒聯奧地利公開賽正賽展開" } } ] } }
因為默認的分詞器,針對中文是按字分詞的,terms查詢是精確查詢,所以查不出來。
五、ElasticSearch IK中文分詞器
1、什么是分詞器?為什么要分詞器?
在上面的學習例子中我們使用的是Es默認的分詞器,在中文的分詞上並不友好,會將語句每個字進行分詞作為索引,所以在使用Term關鍵字查詢的時候多個漢字無法命中文檔。這個時候就需要一個合理的分詞規則,將一個完整的語句划分為多個比較復合表達邏輯的獨立的詞條。
分詞器包含三個部分:
- character filter:分詞之前的預處理,過濾掉HTML標簽、特殊符號轉換(例如,將&符號轉換成and、將|符號轉換成or)等。
- tokenizer:分詞
- token filter:標准化
2、ElasticSeach內置分詞器
- standard分詞器:(默認的)它將詞匯單元轉換成小寫形式,並去掉停用詞(a、an、the等沒有實際意義的詞)和標點符號,支持中文采用的方法為單字切分(例如,‘你好’切分為‘你’和‘好’)。
- simple分詞器:首先通過非字母字符來分割文本信息,然后將詞匯單元同一為小寫形式。該分析器會去掉數字類型的字符。
- Whitespace分詞器:僅僅是去除空格,對字符沒有lowcase(大小寫轉換)化,不支持中文;並且不對生成的詞匯單元進行其他的標准化處理。
- language分詞器:特定語言的分詞器,不支持中文。
3、IK分詞器
3.1、IK分詞器簡介
IK分詞器在是一款 基於詞典和規則 的中文分詞器,提供了兩種分詞模式:ik_smart (智能模式)和ik_max_word (細粒度模式)
輸入數據:
IK Analyzer是一個結合詞典分詞和文法分詞的中文分詞開源工具包。它使用了全新的正向迭代最細粒度切分算法。
智能模式效果:
ik analyzer 是 一個 結合 詞典 分詞 和 文法 分詞 的 中文 分詞 開源 工具包 它 使 用了 全新 的 正向 迭代 最 細粒度 切分 算法
細粒度模式:
ik analyzer 是 一個 一 個 結合 詞典 分詞 和文 文法 分詞 的 中文 分詞 開源 工具包 工具 包 它 使用 用了 全新 的 正向 迭代 最 細粒度 細粒 粒度 切分 切 分 算法
3.2、ElasticSearch集成Ik分詞器
Ik分詞器下載:https://github.com/medcl/elasticsearch-analysis-ik/releases
不同版本的集成會有所區別,請下載ES版本對應的ik分詞器版本。
下載解壓后到你的 elasticsearch 插件目錄並重啟elasticsearch, 如: plugins/ik。
3.3、使用ElasticSearch中的 analyze 測試Ik分詞效果
請求方式post;請求url http://127.0.0.1:9200/_analyze
請求參數:
{ "analyzer": "ik_smart",//ik_max_word "text": "IK Analyzer是一個結合詞典分詞和文法分詞的中文分詞開源工具包。它使用了全新的正向迭代最細粒度切分算法。" }
3.4、Ik分詞器停用詞和擴展詞
在實際使用過程中Ik分詞算法的過程中,還有一些場景的分詞規則是Ik無法設計的,很多時候一個網絡用語沒有被解析成一個詞條,以及其中的“的”這樣的助詞往往在建立索引的時候是沒有必要的。所以IK支持停用詞和擴展詞的配置。
需要修改配置文件config/IKAnalyzer.cfg.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>IK Analyzer 擴展配置</comment> <!--用戶可以在這里配置自己的擴展字典 --> <entry key="ext_dict"></entry> <!--用戶可以在這里配置自己的擴展停止詞字典--> <entry key="ext_stopwords"></entry> <!--用戶可以在這里配置遠程擴展字典 --> <!-- <entry key="remote_ext_dict">words_location</entry> --> <!--用戶可以在這里配置遠程擴展停止詞字典--> <!-- <entry key="remote_ext_stopwords">words_location</entry> --> </properties>
- ext_dict填入擴展詞文件。
- ext_stopwords填入停用詞文件。
- 文件以dic后綴結尾,需要和IKAnalyzer.cfg在同級目錄。
- dic文件每個詞需要占一行。
六、ElasticSearch集群
在我們常見的項目中,很多時候都是分布式/集群部署的:對於不用的微服務通過Nginx負載或者注冊到APIGateway、Zuul網關,然后每個服務進行主從/集群部署,然后用到的數據存儲你產品也是基於分片+主從,保證可用性,如下圖所示:
而我們的ElasticSearch也是一樣的集群部署。
1、集群 cluster
一個集群就是一個或多個節點組織在一起,他們共同持有整個庫的數據,並在一起提供索引和搜索功能,一個集群由一個唯一的名字表示。所有節點通過這個集群名字,來進入這個集群。
2、節點node
一個節點是由集群中的一個服務器,作為集群的一部分,它存儲數據,參與集群的索引和搜索功能。和集群類似,一個節點也是由一個名字來標識的,默認情況下,這個名字是一個隨機的。
一個節點可以通過配置集群名稱的方式來加入一個指定的集群。
3、分片和復制 shard & replicas
3.1、分片
一個索引可以存儲超過單個節點硬件限制的大量數據,比如說一個索引具有10億文檔,占據1T的磁盤空間,而任意一個節點都沒有這樣大的一個磁盤空間;或者單個節點處理搜索請求,響應太慢了,為了解決這個問題,ElasticSearch提供了將索引划分為多份的能力,每一份就叫做一個分片。當建立一個索引的時候,可以指定想要分配的分片數量。每個分片本身也是一個功能完善並且獨立的“索引”,這個“索引”可以被放置到集群中的任何節點上。分片很重要,主要體現在兩方面:
- 允許你水平分割/擴展你的內容容量。
- 允許你在分片之上進行分布式並行操作,從而提高性能和吞吐量
至於分片怎么分布,查詢結果怎么聚合,完全由elasticsearch管理的。開發者不需要關心。
3.2、復制
在網絡環境或者說分布式環境中,通訊發生失敗是常有的事,所以當某個分片節點出現故障,故障轉移機制是非常有必要的。因此Elasticsearch允許你創建分片的一份或者多份拷貝,這些拷貝叫做復制分片,或者就叫復制。
復制的存在提高了節點出現故障時的集群高可用性。因為這個原因,復制分片應注意與主分片不能在同一個節點上。
總結的說,一個索引可以被分為多個分片,可以被復制0~N次,一旦復制了就有了主分片和復制分片之別。分片和復制的數量可以在索引創建的時候指定。在索引創建之后,復制的數量可以改變,但是分片數量不能改變。
分片和復制邏輯結構:
物理結構:
4、集群搭建
對於一個新建的節點需要保證安裝目錄的data目錄為空,修改 elasticsearch.yml 配置文件(注意冒號后面的空格)。
#集群名稱 cluster.name: my-elasticsearch #節點名稱,不同的節點名稱必須不一樣 node.name: node-1 # 是否可以成為master節點 node.master: true #必須為本機的ip地址 network.host: 127.0.0.1 #服務端口,在同一機器下必須不一樣 http.port: 9201 #集群間通訊端口號,在同一機器必須不一樣 transport.tcp.port: 9301 #集群節點 discovery.seed_hosts: - 127.0.0.1:9301 - 127.0.0.1:9302 - 127.0.0.1:9303 #集群中的主節點 cluster.initial_master_nodes: - 127.0.0.1:9301
不同節點注意修改節點名稱、服務端口、通訊端口、以及是否可以成為主節點屬性,修改完畢后依次啟動不同節點服務。
5、節點的3中類型
5.1、主節點
即 Master 節點。主節點的主要職責是和集群操作相關的內容,如創建或刪除索引,跟蹤哪些節點是群集的一部分,並決定哪些分片分配給相關的節點。穩定的主節點對集群的健康是非常重要的。默認情況下任何一個集群中的節點都有可能被選為主節點。索引數據和搜索查詢等操作會占用大量的cpu,內存,io資源,為了確保一個集群的穩定,分離主節點和數據節點是一個比較好的選擇。雖然主節點也可以協調節點,路由搜索和從客戶端新增數據到數據節點,但最好不要使用這些專用的主節點。一個重要的原則是,盡可能做盡量少的工作。
5.2、數據節點
即 Data 節點。數據節點主要是存儲索引數據的節點,主要對文檔進行增刪改查操作,聚合操作等。數據節點對 CPU、內存、IO 要求較高,在優化的時候需要監控數據節點的狀態,當資源不夠的時候,需要在集群中添加新的節點。
5.3、預處理節點
也稱作 Ingest 節點,在索引數據之前可以先對數據做預處理操作(如:函數運算、類型轉換等),所有節點其實默認都是支持 Ingest 操作的,也可以專門將某個節點配置為 Ingest 節點。
以上就是節點幾種類型,一個節點其實可以對應不同的類型,如一個節點可以同時成為主節點和數據節點和預處理節點,具體的類型可以通過具體的配置文件來設置。
6、分片交互
我們能夠發送請求給集群中任意一個節點。每個節點都有能力處理任意請求。每個節點都知道任意文檔所在的節點,所以也可以將請求轉發到需要的節點。下面的例子中,我們將發送所有請求給`Node 1`,這個節點我們將會稱之為請求節點(requesting node)。 當我們發送請求,最好的做法是循環通過所有節點請求,這樣可以平衡負載,或者借助nginx、apache等反向代理服務器進行負載。
6.1、新建、刪除索引和刪除文檔時
新建、索引和刪除請求都是寫(write)操作,它們必須在主分片上成功完成才能復制到相關的復制分片上。
6.2、單條檢索文檔集群交互流程
6.3、批量查詢文檔
請求拆成每個分片的請求,然后轉發每個參與的節點。
7、集群節點自動分片及重啟
我們先看啟動master,然后創建索引,再啟動剩余2個node節點,並在此創建一個索引,可以在elasticsearch-head看到索引的分片以及副本情況如下:
elasticsearch集群的高可用和自動平衡方案會在節點掛掉(重啟)后自動在別的節點上復制該節點的分片,這將導致大量的IO和網絡開銷。
如果離開的節點重新加入集群,elasticsearch為了對數據分片(shard)進行再平衡,會為重新加入的節點再次分配數據分片(shard),當一台ES因為壓力過大而掛掉以后,其他的ES服務器會備份本應那台ES保存的數據,造成更大的壓力,於是造成整個集群會發生雪崩。因此生產環境下建議關閉自動平衡:
cluster.routing.rebalance.ennable: none
可以設置延遲副本重新分配機制:
index.unassigned.node_left.delayed_timeout: 5m
還可以指定集群節點到達多少數量才開始平衡:
gateway.recover_after_nodes: 8