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}}