# ElasticSearch從入門到大牛
ElasticSearch從入門到大牛
#一. ElasticSearch介紹 為什麼要使用ElasticSearch ?在全文搜尋領域,Lucene可以被認為是迄今為止最先進、效能最好的、功能最全的搜尋引擎庫。 但是,Lucene只是一個庫,想要使用它,那麼就必須使用Java來作為開發語言並將其直接整合到你的應用中,然而Lucene的配置及使用非常複雜,你需要深入瞭解檢索的相關知識來理解它是如何工作的。 在實際專案中,我們建立一個網站或應用程式,並要新增搜尋功能,令我困難的是:搜尋工作是很難的。我們希望我們的搜尋解決方案要快,我們希望有一個零配置和一個完全免費的搜尋模式,我們希望能夠簡單地使用JSON/XML通過HTTP的索引資料,我們希望我們的搜尋伺服器始終可用,我們希望能夠從一臺開始並在需要擴容時方便地擴充套件到數百,我們要實時搜尋,我們要簡單的多租戶,我們希望建立一個雲的解決方案;那麼我們的 ElasticSearch就因此誕生了。 ES即為了解決原生Lucene使用的不足,優化Lucene的呼叫方式,並實現了高可用的分散式叢集的搜尋方案,其第一個版本於2010年2月出現在GitHub上並迅速成為最受歡迎的專案之一。 首先,ES的索引庫管理支援依然是基於Apache Lucene™的開源搜尋引擎。 ES也使用Java開發並使用Lucene作為其核心來實現所有索引和搜尋的功能,但是它的目的是通過簡單的 RESTful API來隱藏Lucene的複雜性,從而讓全文搜尋變得簡單。 但是,ES的核心不在於Lucene,其特點更多的體現為:分散式的實時檔案儲存,每個欄位都被索引並可被搜尋;分散式的實時分析搜尋引擎;可以擴充套件到上百臺伺服器,處理PB級結構化或非結構化資料;高度整合化的服務,你的應用可以通過簡單的 RESTful API、各種語言的客戶端甚至命令列與之互動。 上手Elasticsearch非常容易。它提供了許多合理的預設值,並對初學者隱藏了複雜的搜尋引擎理論。它擁有開瓶即飲的效果(安裝即可使用),只需很少的學習既可在生產環境中使用。
2.1.ES的使用者及類似框架
1.github 1300億程式碼查詢 2.地圖 5000w 地理資訊 3.婚戀網 2億中國人找物件 4.京東商城
3.1類似框架
1.Solr(重量級對手) Apache Lucene專案的開源企業搜尋平臺。其主要功能包括全文檢索、命中標示、分面搜尋、動態聚類、資料庫整合,以及富文字(如Word、PDF)的處理。Solr是高度可擴充套件的,並提供了分散式搜尋和索引複製。Solr是最流行的企業級搜尋引擎,Solr4 還增加了NoSQL支援。 2.Solr和ES比較: Solr 利用 Zookeeper 進行分散式管理,支援更多格式的資料(HTML/PDF/CSV),官方提供的功能更多在傳統的搜尋應用中表現好於 ES,但實時搜尋效率低。 ES自身帶有分散式協調管理功能,但僅支援json檔案格式,本身更注重於核心功能,高階功能多有第三方外掛提供,在處理實時搜尋應用時效率明顯高於 ES。 3. Katta 基於 Lucene 的,支援分散式,可擴充套件,具有容錯功能,準實時的搜尋方案。 優點:開箱即用,可以與 Hadoop 配合實現分散式。具備擴充套件和容錯機制。 缺點:只是搜尋方案,建索引部分還是需要自己實現。在搜尋功能上,只實現了最基本的需求。成功案例較少,專案的成熟度稍微差一些。 4. HadoopContrib Map/Reduce 模式的,分散式建索引方案,可以跟 Katta 配合使用。 優點:分散式建索引,具備可擴充套件性。 缺點:只是建索引方案,不包括搜尋實現。工作在批處理模式,對實時搜尋的支援不佳。 總之:就是ElasticSearch簡化了全文檢索lucene的使用,同時增加了分散式的特性,使得構建大規模分散式全文檢索變得非常容易。
二.ES安裝及使用
2.1包含的內容 ES的安裝比較簡單,只需要官方下載ES的執行包,然後啟動ES服務即可。 ES的使用主要是通過能夠發起HTTP請求的終端來接入,比如Poster外掛、CURL、kibana5等。 2.2下載es 下載地址:https://www.elastic.co/downloads/elasticsearch 下載好了只需要解壓出來,只需要執行elasticsearch.bat即可; 能夠訪問:http://localhost:9200/ 就成功。 2.3ES互動方式 ES和所有客戶端的互動都是使用JSON格式的資料; 都是基於RESETful API。 Restful是一種面向資源的架構風格,可以簡單理解為:使用URL定位資源,用HTTP動詞(GET,POST,DELETE,PUT)操作。 GET 用來獲取資源, POST 用來新建資源(也可以用於更新資源); PUT 用來更新資源; DELETE 用來刪除資源。
三.ES資料管理
3.1什麼是ES中的文件
ES是面向文件(document oriented)的,這意味著它可以儲存整個物件或文件(document)。然而它不僅僅是儲存,還會索引(index)每個文件的內容使之可以被搜尋。在ES中,你可以對文件(而非成行成列的資料)進行索引、搜尋、排序、過濾。 ES使用Javascript物件符號(JavaScript Object Notation),也就是JSON,作為文件序列化格式。JSON現在已經被大多語言所支援,而且已經成為NoSQL領域的標準格式。 3.2ES的使用
_index:索引庫,類似於關係型資料庫裡的“資料庫”—它是我們儲存和索引關聯資料的地方。 _type:在應用中,我們使用物件表示一些“事物”,例如一個使用者、一篇部落格、一個評論,或者一封郵件。可以是大寫或小寫,不能包含下劃線或逗號。我們將使用 employee 做為型別名。 _id:與 _index 和 _type 組合時,就可以在ELasticsearch中唯一標識一個文件。當建立一個文件,你可以自定義 _id ,也可以讓Elasticsearch幫你自動生成。 另外還包括:_uid文件唯一標識(_type#_id); _source:文件原始資料; _all:所有欄位的連線字串;
3.3ES文件的增刪改 3.3.1增加 PUT {index} 比如 PUT B2c 注意:post也有新增的效果 post和put都有同樣的效果 不過在建立索引庫的時候,必須使用put。 其原理是先刪除在新增 3.3.2改 使用自己的ID建立: PUT {index}/{type}/{id} { “field”: “value”, … } ES內建ID建立: POST {index}/{type}/ { “field”: “value”, … } 注意:post和put也由修改的效果 如果在修改只要有資料的,就會修改 只需要看result的值 created 標識為 false 因為同索引、同類型下已經存在同ID的文件 3.3.3指令碼更新文件 也可以通過使用簡單的指令碼來進行。這個例子使用一個指令碼將age加5: POST itsource/emploee/123/_update { “script” : “ctx._source.age += 5” } 在上面的例子中, ctx._source指向當前被更新的文件。 注意,目前的更新操作只能一次應用在一個文件上。 3.3.4刪除 DELETE {index}/{type}/{id} 刪除成功 “found” : true 失敗 “found” :false 注意:儘管文件不存在,但_version依舊增加了。這是內部記錄的一部分,它確保在多節點間不同操作可以有正確的順序。 3.3.5批量操作bulk API 使用單一請求來實現多個文件的create、index、update 或 delete。 Bulk請求體格式: { action: { metadata }}\n { request body }\n { action: { metadata }}\n { request body }\n 每行必須以 “\n” 符號結尾,包括最後一行。這些都是作為每行有效的分離而做的標記。 create當文件不存在時建立之。 index建立新文件或替換已有文件。 update區域性更新文件。 delete刪除一個文件。
3.4文件的簡單查詢
3.4.1批量查取 mget API引數是一個 docs陣列,陣列的每個節點定義一個文件的 _index 、 _type 、 _id 元資料。如果你只想檢索一個或幾個確定的欄位,也可以定義一個 _source 引數; 方式1:GET _mget { “docs” : [ { “_index” : “itsource”, “_type” : “blog”, “_id” : 2 }, { “_index” : “itsource”, “_type” : “employee”, “_id” : 1, “_source”: [“name”,“age”] } ] } 方式2:同一個索引庫的同一個型別下 GET itsource/blog/_mget { “ids” : [ “2”, “1” ] } 3.4.2分頁搜尋 和SQL使用 LIMIT 關鍵字返回只有一頁的結果一樣,Elasticsearch接受 from 和 size 引數: size : 每頁條數,預設 10 from : 跳過開始的結果數,預設 0 如果你想每頁顯示5個結果,頁碼從1到3,那請求如下: GET _search?size=5 GET _search?size=5&from=5 GET _search?size=5&from=10 3.4.3排序搜尋 使用sort 3.4.4DSL查詢與過濾 3.4.4.1什麼是DSL查詢 由ES提供豐富且靈活的查詢語言叫做DSL查詢(Query DSL),它允許你構建更加複雜、強大的查詢。 3.4.5 DSL模式: GET Microsoft/employee/_search { “query” : { “match” : { “fullName” : “你是個菜鳥” } } } 3.4.5DSL查詢 DSL是以json請求體的形式出現。 query:查詢組 bool:相遇where match:關鍵字匹配 must:必須有 filter:過濾條件 match_all:匹配所有 使用DSL查詢,必須要傳遞query引數給ES。 GET _search {“query”: YOUR_QUERY_HERE} 一個常用的相對完整的DSL查詢: GET itsource/employee/_search { “query”: { “match”: {“sex”:“男”} }, “from”: 20, “size”: 5, " _source": [“fullName”, “age”, “email”], “sort”: [{“join_date”: “desc”},{“age”: “asc”}] } 3.4.6DSL過濾 列如: { “query”: { “bool”: { “must”: [ {“match”: {“description”: “search” }} ], “filter”: { “term”: {“tags”: “lucene”} } } } }
3.5分詞與對映
3.5.1為什麼要使用分詞與對映尼? 因為在全文檢索理論中,文件的查詢是通過關鍵字查詢文件索引來進行匹配,因此將文字拆分為有意義的單詞,對於搜尋結果的準確性至關重要,因此,在建立索引的過程中和分析搜尋語句的過程中都需要對文字串分詞。 ES中分詞需要對具體欄位指定分詞器等細節,因此需要在文件的對映中明確指出。 3.5.1IK分詞器 3.5.1.1 Maven打包IK外掛; 3.5.1.2 解壓target/releases/elasticsearch-analysis-ik-5.2.2.zip檔案;並將其內容放置於ES根目錄/plugins/ik; 3.5.1.3 配置外掛:(可預設不改) 外掛配置:plugin-descriptor.properties 3.5.1.4 分詞器(可預設不改) 詞典配置:config/IKAnalyzer.cfg.xml 3.5.1.5 重啟ES 3.5.1.6測試分詞器 POST _analyze { “analyzer”:“ik_smart”, “text”:“微軟,是一家美國跨國科技公司,” } 注意:IK分詞器有兩種型別,分別是ik_smart分詞器和ik_max_word分詞器。 ik_smart: 會做最粗粒度的拆分; ik_max_word: 會將文字做最細粒度的拆分;
3.6.文件對映Mapper
3.6.1ES的文件對映(mapping)機制用於進行欄位型別確認,將每個欄位匹配為一種確定的資料型別。 3.6.2ES欄位型別
- 基本欄位型別 字串:text,keyword text預設為全文文字,keyword預設為非全文文字 數字:long,integer,short,double,float 日期:date 邏輯:boolean
- 複雜資料型別 物件型別:object 陣列型別:array 地理位置:geo_point,geo_shape 3.6.3預設對映 3.6.3.1檢視索引型別的對映配置:GET {indexName}/{typeName}/_mapping Boolean: true or false “boolean” Whole number: 123 “long” Floating point: 123.45 “float” String, valid date:“2018-09-15” “date” String: “as r” “text” 3.6.4簡單型別對映 type 型別:基本資料型別,integer,long,date,boolean,keyword,text… include_in_all 是否將該欄位值組合到_all中。 _all : 虛擬欄位,每個文件都有該欄位,代表所有欄位的組合資訊,作用方便直接對整個文件的所有資訊進行搜尋。{id:1,name:zs,age:20,_all:1,zs,20} store 是否儲存:預設為false。true意義不大,因為_source中已有資料 index 索引模式:analyzed (索引並分詞,text預設模式), not_analyzed (索引不分詞,keyword預設模式),no(不索引) analyzer 索引分詞器:索引建立時使用的分詞器,如ik_smart,ik_max_word,standard search_analyzer 搜尋分詞器:搜尋該欄位的值時,傳入的查詢內容的分詞器。 3.6.5物件及陣列型別對映 物件的對映與索引 { “id” : 1, “girl” : { “name” : “狂戰士”, “age” : 22 } } 對應的mapping配置: { “properties”: { “id”: {“type”: “long”}, “girl”: { “properties”:{ “name”: {“type”: “keyword”}, “age”: {“type”: “long”} } } } } 注意:Lucene不理解內建物件,一個lucene文件包含鍵值對的一個扁平化列表,以便於ES索引內建物件,它把文件轉換為類似這樣: { “id”: 1, “girl.name”:“狂戰士”, “girl.age”:26 } 內建欄位與名字相關,區分兩個欄位中相同的名字,可以使用全路徑,例如user.girl.name 3.6.6全域性對映 全域性對映可以通過動態模板和預設設定兩種方式實現。 預設方式:default 索引下所有的型別對映配置會繼承_default_的配置 PUT {indexName} { “mappings”: { “default”: { “_all”: { “enabled”: false } }, “user”: {}, “dept”: { “_all”: { “enabled”: true } } } } 動態模板:dynamic_templates 注意:ES會預設把string型別的欄位對映為text型別(預設使用標準分詞器)和對應的keyword型別,如: “name”: { “type”: “text”, “fields”: { “keyword”: { “type”: “keyword”, “ignore_above”: 256 } } } 說明:上例中動態對映模板sstring_as_keyword. 在實際的型別欄位對映時,會依次匹配: ①欄位自定義配置、②全域性dynamic_templates[string_as_keyword]、 ③索引dynamic_templates[…]、④ES自帶的型別對映。 以最先匹配上的為準。 注意:索引庫在建立的時候會繼承當前最新的dynamic_templates,索引庫建立後,修改動態模板,無法應用到已存在的索引庫。 3.6.7最佳實踐 對映的配置會影響到後續資料的索引過程,因此,在實際專案中應遵循如下順序規則: 1.配置全域性動態模板對映(覆蓋預設的string對映)
- 配置自定義欄位對映(由於基本型別主要用於過濾和普通查詢,因此,欄位對映主要對需要全文檢索的欄位進行配置) 3.建立、更新和刪除文件 4.搜尋
總之:分詞器和對映是ES中的重要內容,一般這部分工作會在進行文件索引和搜尋前完成。
四.Java API
4.1.什麼是Java API ES對Java提供一套操作索引庫的工具包,即Java API。所有的ES操作都使用Client物件執行。 ES的Maven引入 org.elasticsearch.client transport 5.2.2 org.apache.logging.log4j log4j-api 2.7 org.apache.logging.log4j log4j-core 2.7 junit junit 4.12 test 4.2.連線ES獲取Client物件 TransportClient 利用transport模組遠端連線一個ES叢集。它並不加入到叢集中,只是簡單的獲得一個或者多個初始化的transport地址,並以輪詢的方式與這些地址進行通訊。
public TransportClient getClient() throws Exception {
// 啟動客戶端
TransportClient client = new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300));
return client; }
4.3索引API 4.3.1.建立文件索引
import static org.elasticsearch.common.xcontent.XContentFactory.*;
IndexResponse response = client.prepareIndex("B2c", "vip", "10")
.setSource(jsonDataText).get();
或使用ES自動ID,不提供ID值1也OK。
返回的response物件可以獲取到_index,_type,_version,_id等元資料。
4.3.2獲取文件
GetResponse response = client.prepareGet("B2c", "vip", "1").get();
4.3.3.更新文件
client.prepareUpdate("B2c", "vip", "1").setDoc("{\"sex\":0}").get();
4.3.4刪除文件
DeleteResponse response = client.prepareDelete("B2c", "vip", "1").get();
4.3.5批量操作
BulkRequestBuilder bulkRequest = client.prepareBulk();
bulkRequest.add(client.prepareIndex("B2c", "vip", "5")
.setSource(vip1JsonData));
bulkRequest.add(client.prepareIndex("B2c", "vip", "6")
.setSource(vip2JsonData));
BulkResponse bulkResponse = bulkRequest.get();
if (bulkResponse.hasFailures()) {
//處理錯誤
}
4.3.6搜尋
SearchResponse response = client.prepareSearch("index1", "index2")
.setTypes("type1", "type2")
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(QueryBuilders.termQuery("sex", "0")) //① Query and Filter
.setFrom(0).setSize(60).setExplain(true)
.get();
注意:新版中已取消FiltersBuilders的設定方式,統一採用BoolQueryBuilder.filter()新增
Eg. 標記①中改為過濾+查詢的模式
總之:JavaAPI難點在於對ES的高階搜尋與過濾。 **
希望對大家有幫助!
**