ElasticSearch簡介和快速實戰
ElasticSearch與Lucene
Lucene可以被認為是迄今為止最先進、效能最好的、功能最全的搜尋引擎庫(框架)
但是想要使用Lucene,必須使用Java來作為開發語言並將其直接整合到你的應用中,並且Lucene的配置及使用非常複雜,你需要深入瞭解檢索的相關知識來理解它是如何工作的。
Lucene缺點:
1)只能在Java專案中使用,並且要以jar包的方式直接整合專案中.
2)使用非常複雜-建立索引和搜尋索引程式碼繁雜
3)不支援叢集環境-索引資料不同步(不支援大型專案)
4)索引資料如果太多就不行,索引庫和應用所在同一個伺服器,共同佔用硬碟.共用空間少.
上述Lucene框架中的缺點,ES全部都能解決.
ES vs Solr比較
當單純的對已有資料進行搜尋時,Solr更快。當實時建立索引時, Solr會產生io阻塞,查詢效能較差, Elasticsearch具有明顯的優勢。二者安裝都很簡單。
1、Solr 利用 Zookeeper 進行分散式管理,而Elasticsearch 自身帶有分散式協調管理功能。
2、Solr 支援更多格式的資料,比如JSON、XML、CSV,而 Elasticsearch 僅支援json檔案格式。
3、Solr 在傳統的搜尋應用中表現好於 Elasticsearch,但在處理實時搜尋應用時效率明顯低於 Elasticsearch。
4、Solr 是傳統搜尋應用的有力解決方案,但 Elasticsearch更適用於新興的實時搜尋應用。
ES vs 關係型資料庫
什麼是全文檢索
全文檢索是指:
- 通過一個程式掃描文字中的每一個單詞,針對單詞建立索引,並儲存該單詞在文字中的位置、以及出現的次數
- 使用者查詢時,通過之前建立好的索引來查詢,將索引中單詞對應的文字位置、出現的次數返回給使用者,因為有了具體文字的位置,所以就可以將具體內容讀取出來了
分詞原理之倒排索引
倒排索引總結:
索引就類似於目錄,平時我們使用的都是索引,都是通過主鍵定位到某條資料,那麼倒排索引呢,剛好相反,資料對應到主鍵.這裡以一個部落格文章的內容為例:
1.索引
文章ID | 文章標題 | 文章內容 |
---|---|---|
1 | 淺析JAVA設計模式 | JAVA設計模式是每一個JAVA程式設計師都應該掌握的進階知識 |
2 | JAVA多執行緒設計模式 | JAVA多執行緒與設計模式結合 |
2.倒排索引
假如,我們有一個站內搜尋的功能,通過某個關鍵詞來搜尋相關的文章,那麼這個關鍵詞可能出現在標題中,也可能出現在文章內容中,那我們將會在建立或修改文章的時候,建立一個關鍵詞與文章的對應關係表,這種,我們可以稱之為倒排索引,因此倒排索引,也可稱之為反向索引.如:
關鍵詞 | 文章ID |
---|---|
JAVA | 1 |
設計模式 | 1,2 |
多執行緒 | 2 |
注:這裡涉及中文分詞的問題
Elasticsearch中的核心概念
1 索引 index
一個索引就是一個擁有幾分相似特徵的文件的集合。比如說,可以有一個客戶資料的索引,另一個產品目錄的索引,還有一個訂單資料的索引
一個索引由一個名字來標識(必須全部是小寫字母的),並且當我們要對對應於這個索引中的文件進行索引、搜尋、更新和刪除的時候,都要使用到這個名字
2 對映 mapping
ElasticSearch中的對映(Mapping)用來定義一個文件
mapping是處理資料的方式和規則方面做一些限制,如某個欄位的資料型別、預設值、分詞器、是否被索引等等,這些都是對映裡面可以設定的
3 欄位Field
相當於是資料表的欄位|列
4 欄位型別 Type
每一個欄位都應該有一個對應的型別,例如:Text、Keyword、Byte等
5 文件 document
一個文件是一個可被索引的基礎資訊單元,類似一條記錄。文件以JSON(Javascript Object Notation)格式來表示;
6 叢集 cluster
一個叢集就是由一個或多個節點組織在一起,它們共同持有整個的資料,並一起提供索引和搜尋功能
7 節點 node
一個節點是叢集中的一個伺服器,作為叢集的一部分,它儲存資料,參與叢集的索引和搜尋功能
一個節點可以通過配置叢集名稱的方式來加入一個指定的叢集。預設情況下,每個節點都會被安排加入到一個叫做“elasticsearch”的叢集中
這意味著,如果在網路中啟動了若干個節點,並假定它們能夠相互發現彼此,它們將會自動地形成並加入到一個叫做“elasticsearch”的叢集中
在一個叢集裡,可以擁有任意多個節點。而且,如果當前網路中沒有執行任何Elasticsearch節點,這時啟動一個節點,會預設建立並加入一個叫做“elasticsearch”的叢集。
3.8 分片和副本 shards&replicas
3.8.1 分片
一個索引可以儲存超出單個結點硬體限制的大量資料。比如,一個具有10億文件的索引佔據1TB的磁碟空間,而任一節點都沒有這樣大的磁碟空間;或者單個節點處理搜尋請求,響應太慢
為了解決這個問題,Elasticsearch提供了將索引劃分成多份的能力,這些份就叫做分片
當建立一個索引的時候,可以指定你想要的分片的數量
每個分片本身也是一個功能完善並且獨立的“索引”,這個“索引”可以被放置到叢集中的任何節點上
分片很重要,主要有兩方面的原因
允許水平分割/擴充套件你的內容容量
允許在分片之上進行分散式的、並行的操作,進而提高效能/吞吐量
- 至於一個分片怎樣分佈,它的文件怎樣聚合回搜尋請求,是完全由Elasticsearch管理的,對於作為使用者來說,這些都是透明的
3.8.2 副本
在一個網路/雲的環境裡,失敗隨時都可能發生,在某個分片/節點不知怎麼的就處於離線狀態,或者由於任何原因消失了,這種情況下,有一個故障轉移機制是非常有用並且是強烈推薦的。為此目的,Elasticsearch允許你建立分片的一份或多份拷貝,這些拷貝叫做副本分片,或者直接叫副本
副本之所以重要,有兩個主要原因
1) 在分片/節點失敗的情況下,提供了高可用性。
注意到複製分片從不與原/主要(original/primary)分片置於同一節點上是非常重要的
2) 擴充套件搜尋量/吞吐量,因為搜尋可以在所有的副本上並行執行
每個索引可以被分成多個分片。一個索引有0個或者多個副本
一旦設定了副本,每個索引就有了主分片和副本分片,分片和副本的數量可以在索引
建立的時候指定
在索引建立之後,可以在任何時候動態地改變副本的數量,但是不能改變分片的數量
測試分詞效果
單字分詞器
POST _analyze
{
"analyzer":"standard",
"text":"我愛你中國"
}
ik分詞器
最粗力度拆分
POST _analyze
{
"analyzer": "ik_smart",
"text": "中華人民共和國人民大會堂"
}
最細力度拆分
POST _analyze
{
"analyzer": "ik_max_word",
"text": "中華人民共和國人民大會堂"
}
指定IK分詞器作為預設分詞器
修改預設分詞方法(這裡修改school_index索引的預設分詞為:ik_max_word):
PUT /school_index
{
"settings" : {
"index" : {
"analysis.analyzer.default.type": "ik_max_word"
}
}
}
ES資料管理
ES是面向文件(document oriented)的,這意味著它可以儲存整個物件或文件(document)。
然而它不僅僅是儲存,還會索引(index)每個文件的內容使之可以被搜尋。
在ES中,你可以對文件(而非成行成列的資料)進行索引、搜尋、排序、過濾。
ES使用JSON作為文件序列化格式。
JSON現在已經被大多語言所支援,而且已經成為NoSQL領域的標準格式。
ES儲存的一個員工文件的格式示例:
{
"email": "[email protected]",
"name": "張三",
"age": 30,
"interests": [ "籃球", "健身" ]
}
基本操作
1) 建立索引
格式: PUT /索引名稱
PUT /es_db
2) 查詢索引
格式: GET /索引名稱
GET /es_db
3) 刪除索引
格式: DELETE /索引名稱
DELETE /es_db
4) 新增文件
格式: PUT /索引名稱/型別/id
PUT /es_db/_doc/1{"name": "張三","sex": 1,"age": 25,"address": "廣州天河公園","remark": "java developer"}PUT /es_db/_doc/2{"name": "李四","sex": 1,"age": 28,"address": "廣州荔灣大廈","remark": "java assistant"}PUT /es_db/_doc/3{"name": "rod","sex": 0,"age": 26,"address": "廣州白雲山公園","remark": "php developer"}PUT /es_db/_doc/4{"name": "admin","sex": 0,"age": 22,"address": "長沙橘子洲頭","remark": "python assistant"}PUT /es_db/_doc/5{"name": "小明","sex": 0,"age": 19,"address": "長沙嶽麓山","remark": "java architect assistant"}
5) 修改文件
格式: PUT /索引名稱/型別/id
PUT /es_db/_doc/1{"name": "白起老師","sex": 1,"age": 25,"address": "張家界森林公園","remark": "php developer assistant" }
注意:
POST和PUT都能起到建立/更新的作用
1、需要注意的是PUT需要對一個具體的資源進行操作也就是要確定id才能進行更新/建立,而POST是可以針對整個資源集合進行操作的,如果不寫id就由ES生成一個唯一id進行建立新文件,如果填了id那就針對這個id的文件進行建立/更新
2、PUT只會將json資料都進行替換, POST只會更新相同欄位的值
3、PUT與DELETE都是冪等性操作, 即不論操作多少次, 結果都一樣
6) 查詢文件
格式: GET /索引名稱/型別/id
GET /es_db/_doc/1
7) 刪除文件
格式: DELETE /索引名稱/型別/id
DELETE /es_db/_doc/1
Restful風格
Restful是一種面向資源的架構風格,可以簡單理解為:使用URL定位資源,用HTTP動詞(GET,POST,DELETE,PUT)描述操作。 基於Restful API ES和所有客戶端的互動都是使用JSON格式的資料.
其他所有程式語言都可以使用RESTful API,通過9200埠的與ES進行通訊
GET查詢
PUT新增
POST修改
DELE刪除
使用Restful的好處:
透明性,暴露資源存在。
充分利用 HTTP 協議本身語義,不同請求方式進行不同的操作
查詢操作
1 查詢當前型別中的所有文件
格式: GET /索引名稱/型別/_search
GET /es_db/_doc/_search
SQL: select * from student
2 條件查詢
如要查詢age等於28歲的
格式: GET /索引名稱/型別/_search?q=age:28
GET /es_db/_doc/_search?q=age:28
SQL: select * from student where age = 28
3 範圍查詢
如要查詢age在25至26歲之間的
格式: GET /索引名稱/型別/_search?q=age[25 TO 26] 注意: TO 必須為大寫
GET /es_db/_doc/_search?q=age[25 TO 26]
SQL: select * from student where age between 25 and 26
4 根據多個ID進行批量查詢 _mget
格式: GET /索引名稱/型別/_mget
GET /es_db/_doc/_mget{ "ids":["2","3"] }
select * from student where id in (2,3)
5 查詢年齡小於等於28歲的 :<=
格式: GET /索引名稱/型別/_search?q=age:<=28
GET /es_db/_doc/_search?q=age:<=28
SQL: select * from student where age <= 28
6 查詢年齡大於28前的 :>
格式: GET /索引名稱/型別/_search?q=age:>26
GET /es_db/_doc/_search?q=age:>26
SQL: select * from student where age > 28
7 分頁查詢
格式: GET /索引名稱/型別/_search?q=age[25 TO 26]&from=0&size=1
GET /es_db/_doc/_search?q=age[25 TO 26]&from=0&size=1
SQL: select * from student where age between 25 and 26 limit 0, 1
8 對查詢結果只輸出某些欄位**
格式: GET /索引名稱/型別/_search?__source=欄位,欄位
GET /es_db/_doc/_search?_source=name,age
SQL: select name,age from student
9 對查詢結果排序**
格式: GET /索引名稱/型別/_search?sort=欄位 desc
GET /es_db/_doc/_search?sort=age:desc
SQL: select * from student order by age desc
文件批量操作
1.批量獲取文件資料
批量獲取文件資料是通過_mget的API來實現的
(1)在URL中不指定index和type
請求方式:GET
請求地址:_mget
功能說明 : 可以通過ID批量獲取不同index和type的資料
請求引數:
- docs : 文件陣列引數
- _index : 指定index
- _type : 指定type
- _id : 指定id
- _source : 指定要查詢的欄位
GET _mget{ "docs": [ { "_index": "es_db", "_id": 3 }, { "_index": "es_db", "_id": 2 } ]}
(2)在URL中指定index
請求方式:GET
請求地址:/{{indexName}}/_mget
功能說明 : 可以通過ID批量獲取不同index和type的資料
請求引數:
- docs : 文件陣列引數
- _index : 指定index
- _type : 指定type
- _id : 指定id
- _source : 指定要查詢的欄位
GET /es_db/_mget{ "docs": [ { "_type":"_doc", "_id": 3 }, { "_type":"_doc", "_id": 4 } ]}
(3)在URL中指定index和type
請求方式:GET
請求地址:/{{indexName}}/{{typeName}}/_mget
功能說明 : 可以通過ID批量獲取不同index和type的資料
請求引數:
- docs : 文件陣列引數
- _index : 指定index
- _type : 指定type
- _id : 指定id
- _source : 指定要查詢的欄位
GET /es_db/_doc/_mget{ "docs": [ { "_id": 3 }, { "_id": 2 } ]}
2.批量操作文件資料
批量對文件進行寫操作是通過_bulk的API來實現的
請求方式:POST
請求地址:_bulk
請求引數:通過_bulk操作文件,一般至少有兩行引數(或偶數行引數)
- 第一行引數為指定操作的型別及操作的物件(index,type和id)
- 第二行引數才是操作的資料
引數類似於:
{"actionName":{"_index":"indexName", "_type":"typeName","_id":"id"}}{"field1":"value1", "field2":"value2"}
- actionName:表示操作型別,主要有create,index,delete和update
(1)批量建立文件create
POST _bulk{"create":{"_index":"article", "_id":3}}{"id":3,"title":"白起老師1","content":"白起老師666","tags":["java", "面向物件"],"create_time":1554015482530}{"create":{"_index":"article", "_id":4}}{"id":4,"title":"白起老師2","content":"白起老師NB","tags":["java", "面向物件"],"create_time":1554015482530}
(2)普通建立或全量替換index
POST _bulk{"index":{"_index":"article", "_id":3}}{"id":3,"title":"圖靈徐庶老師(一)","content":"圖靈學院徐庶老師666","tags":["java", "面向物件"],"create_time":1554015482530}{"index":{"_index":"article", "_id":4}}{"id":4,"title":"圖靈諸葛老師(二)","content":"圖靈學院諸葛老師NB","tags":["java", "面向物件"],"create_time":1554015482530}
(3)批量刪除delete
POST _bulk{"delete":{"_index":"article", "_id":3}}{"delete":{"_index":"article", "_id":4}}
(4)批量修改update
POST _bulk{"update":{"_index":"article", "_id":3}}{"doc":{"title":"ES大法必修內功"}}{"update":{"_index":"article", "_id":4}}{"doc":{"create_time":1554018421008}}