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