ES:全文檢索的框架,專門作搜索,支持分佈式、集羣。封裝的Lucene。java
特色:node
Lucene:全文檢索,api比較麻煩,操做全文檢索的最底層技術。apache
核心:建立索引,搜索索引npm
Solr和ES的區別:json
(1) Solr重量級,支持不少種類型操做,支持分佈式,它裏面有不少功能,可是在實時領域上沒有ES好。windows
(2) ES輕量級,支持json的操做格式,在實時搜索領域裏面作得不錯,若是想使用其餘的功能,須要額外安裝插件。api
ES服務只依賴於JDK,推薦使用JDK1.7+。
(1)下載ES安裝包:ES官方下載地址
(2)運行ES (雙擊bin目錄下的elasticsearch.bat)
(3)驗證是否運行成功,訪問:http://localhost:9200/
若是看到以下信息,則說明ES集羣已經啓動而且正常運行。跨域
(1)基於RESTful API
ES和全部客戶端的交互都是使用JSON格式的數據.
其餘全部程序語言均可以使用RESTful API,經過9200端口的與ES進行通訊,在開發測試階段,你可使用你喜歡的WEB客戶端, curl命令以及火狐的POSTER插件方式和ES通訊。
Curl命令方式:
默認windows下不支持curl命令,在資料中有curl的工具及簡單使用說明。數組
火狐的POSTER插件界面:
相似於Firebug,在火狐的「擴展」中搜索「POSTER」,並安裝改擴展工具。緩存
使用POSTER模擬請求的效果
(2)Java API
ES爲Java用戶提供了兩種內置客戶端:
節點客戶端(node client):
節點客戶端以無數據節點(none data node)身份加入集羣,換言之,它本身不存儲任何數據,可是它知道數據在集羣中的具體位置,而且可以直接轉發請求到對應的節點上。
傳輸客戶端(Transport client):
這個更輕量的傳輸客戶端可以發送請求到遠程集羣。它本身不加入集羣,只是簡單轉發請求給集羣中的節點。
兩個Java客戶端都經過9300端口與集羣交互,使用ES傳輸協議(ES Transport Protocol)。集羣中的節點
之間也經過9300端口進行通訊。若是此端口未開放,你的節點將不能組成集羣。
注意:
Java客戶端所在的ES版本必須與集羣中其餘節點一致,不然,它們可能互相沒法識別。
(1)Kibana5.2.2下載地址:Kibana官方下載地址
(2)解壓並編輯config/kibana.yml,設置elasticsearch.url的值爲已啓動的ES
(3)啓動Kibana5 (在bin目錄下雙擊kibana.bat)
(4)驗證是否成功,默認訪問地址:http://localhost:5601
(1)進入head文件中,輸入cmd,打開控制檯,輸入npm install進行安裝。
(2)安裝完成,輸入命令npm run start啓動服務
(3)配置容許跨域訪問,在elasticsearch/config/elasticsearch.yml文件末尾加上
http.cors.enabled: true
http.cors.allow-origin: 「*」
(4)重啓elasticsearch服務,訪問http://localhost:9100
#新增 PUT crm/employee/1 { "name":"xxxx", "age":18 } #查詢 GET crm/employee/1 #修改 POST crm/employee/1 { "name":"yyyy", "age":28 } #刪除 DELETE crm/employee/1 #沒有指定id 字段生成id POST crm/employee { "name":"yyyy", "age":28 } # AW8iLW-mRN4d1HhhqMMJ GET crm/employee/AW8iLW-mRN4d1HhhqMMJ GET _search
# 查詢全部 GET _search #漂亮格式 GET crm/employee/AW8iLW-mRN4d1HhhqMMJ?pretty #指定返回的列 GET crm/employee/AW8iLW-mRN4d1HhhqMMJ?_source=name,age #不要元數據 只返回具體數據 GET crm/employee/AW8iLW-mRN4d1HhhqMMJ/_source
#修改 --覆蓋之前json POST crm/employee/AW8iLW-mRN4d1HhhqMMJ { "name":"yyyy888" } #局部更新 POST crm/employee/AW8iLW-mRN4d1HhhqMMJ/_update { "doc":{ "name":"baocheng" } }
POST _bulk { "delete": { "_index": "xlj", "_type": "department", "_id": "123" }} { "create": { "_index": "xlj", "_type": "book", "_id": "123" }} { "title": "我發行的第一本書" } { "index": { "_index": "itsource", "_type": "book" }} { "title": "我發行的第二本書" } # 普通查詢: GET crm/department/id # 批量查詢: GET xlj/book/_mget { "ids" : [ "123", "AH8ht-oSqTn8hjKcHo2i" ] }
# 從第0條開始查詢3條student信息 GET crm/student/_search?size=3 # 從第2條開始查詢2條student信息 GET crm/student/_search?from=2&size=2 # 表示查詢age=15的人 GET crm/student/_search?q=age:15 # 查詢3條student的信息,他們的age範圍到10到20 GET crm/student/_search?size=3&q=age[10 TO 20]
若是上面的查詢涉及條件比較多,就不適合使用
由ES提供豐富且靈活的查詢語言叫作DSL查詢(Query DSL),它容許你構建更加複雜、強大的查詢。
DSL(Domain Specific Language特定領域語言)以JSON請求體的形式出現。
DSL分紅兩部分:
DSL查詢
DSL過濾
(1)過濾結果能夠緩存並應用到後續請求。
(2)查詢語句同時匹配文檔,計算相關性,因此更耗時,且不緩存。
(3)過濾語句可有效地配合查詢語句完成文檔過濾。
總之在原則上,使用DSL查詢作全文本搜索或其餘須要進行相關性評分的場景,其它全用DSL過濾。
GET crm/student/_search { "query": { "match_all": {} }, "from": 0, "size": 3, "_source": ["name", "age"], "sort": [{"age": "asc"}] }
#DSL過濾 --> name = 'tangtang' --支持緩存 #select * from student where name=tangtang and age = 500 GET crm/student/_search { "query": { "bool": { "must": [ {"match": { "name": "tangtang" }} ], "filter": { "term":{"age":500} } } }, "from": 0, "size": 3, "_source": ["name", "age"], "sort": [{"age": "asc"}] } #select * from student where age = 500 and name != 'tangtang' GET crm/student/_search { "query": { "bool": { "must_not": [ {"match": { "name": "tangtang" }} ], "filter": { "term":{"age":500} } } }, "from": 0, "size": 3, "_source": ["name", "age"], "sort": [{"age": "asc"}] }
什麼叫分詞:把一段話按照必定規則拆分開
爲何要分詞:便於檢索
分詞器放入ES:
解壓ik分詞器 -->在es 在plugins目錄 -->建立一個IK文件夾 -->把ik插件拷貝到ik文件下面
測試ES怎麼使用分詞:
POST _analyze { "analyzer":"ik_smart", "text":"中國駐洛杉磯領事館遭亞裔男子槍擊 嫌犯已自首" }
分片::存儲內容,主分片和從分片
node:節點,有不少類型的節點
節點屬性的配置:
四種組合配置方式:
(1)node.master: true node.data: true
這種組合表示這個節點即有成爲主節點的資格,又存儲數據。
若是某個節點被選舉成爲了真正的主節點,那麼他還要存儲數據,這樣對於這個節點的壓力就比較大了。ElasticSearch默認每一個節點都是這樣的配置,在測試環境下這樣作沒問題。實際工做中建議不要這樣設置,由於這樣至關於主節點和數據節點的角色混合到一塊了。
(2)node.master: false node.data: true
這種組合表示這個節點沒有成爲主節點的資格,也就不參與選舉,只會存儲數據。
這個節點咱們稱爲data(數據)節點。在集羣中須要單獨設置幾個這樣的節點負責存儲數據,後期提供存儲和查詢服務。
(3)node.master: true node.data: false
這種組合表示這個節點不會存儲數據,有成爲主節點的資格,能夠參與選舉,有可能成爲真正的主節點,這個節點咱們稱爲master節點。
(4)node.master: false node.data: false
這種組合表示這個節點即不會成爲主節點,也不會存儲數據,這個節點的意義是做爲一個client(客戶端)節點,主要是針對海量請求的時候能夠進行負載均衡。
搭建三個節點的集羣
(1) 拷貝三個ES 分別取名爲node1 node2 node3
(2) 修改配置
修改內存配置 xms xmx
配置 elasticsearch.yml
# 統一的集羣名 cluster.name: my-ealsticsearch # 當前節點名 node.name: node-1 # 對外暴露端口使外網訪問 network.host: 127.0.0.1 # 對外暴露端口 http.port: 9201 #集羣間通信端口號 transport.tcp.port: 9301 #集羣的ip集合,可指定端口,默認爲9300 discovery.zen.ping.unicast.hosts: [「127.0.0.1:9301」,」127.0.0.1:9302」,」127.0.0.1:9303」]
(3) 配置跨域
(4) 啓動 node1 node2 node3
(5) 啓動head
建立索引,指定分片(若是沒有分配從分片,磁盤佔用率過高,能夠設置:cluster.routing.allocation.disk.threshold_enabled: false)
ES對Java提供一套操做索引庫的工具包,即Java API。全部的ES操做都使用Client對象執行。
ES的Maven引入:
<dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>5.2.2</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.7</version> </dependency>
import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.transport.client.PreBuiltTransportClient; import org.junit.Test; import java.net.InetAddress; import java.util.HashMap; import java.util.List; import java.util.Map; public class EsTest { /** * 鏈接es服務方法 嗅探方式 */ private TransportClient getClient() throws Exception { Settings settings = Settings.builder() .put("client.transport.sniff", true).build(); TransportClient client = new PreBuiltTransportClient(settings). addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"), 9300)); return client; } /** * 新增 */ @Test public void testAdd() throws Exception { TransportClient client = getClient(); IndexRequestBuilder builder = client.prepareIndex("crm", "user", "1"); Map map = new HashMap(); map.put("name", "james"); map.put("age", 35); System.out.println(builder.setSource(map).get()); client.close(); } /** * 查詢 */ @Test public void testGet() throws Exception { TransportClient client = getClient(); System.out.println(client.prepareGet("crm", "user", "1").get().getSource()); client.close(); } /** * 修改 */ @Test public void testUpdate() throws Exception { TransportClient client = getClient(); IndexRequest indexRequest = new IndexRequest("crm", "user", "1"); Map map = new HashMap(); map.put("name", "kobe"); map.put("age", 18); //不存在就新增,存在就更新 UpdateRequest upsert = new UpdateRequest("crm", "user", "1").doc(map).upsert(indexRequest); client.update(upsert).get(); client.close(); } /** * 刪除 */ @Test public void testDelete() throws Exception { TransportClient client = getClient(); client.prepareDelete("crm","user","1").get(); client.close(); } /** * 批量操做 */ @Test public void testBulk() throws Exception { TransportClient client = getClient(); BulkRequestBuilder bulk = client.prepareBulk(); for (int i = 1; i < 51; i++) { Map map = new HashMap(); map.put("name", "xx" + i); map.put("age", i); bulk.add(client.prepareIndex("crm", "user", "" + i).setSource(map)); } BulkResponse response = bulk.get(); if (response.hasFailures()) { System.out.println("插入失敗!"); } client.close(); } /** * DSL過濾(分頁,過濾,排序) */ @Test public void testDsl() throws Exception { TransportClient client = getClient(); //獲得builder SearchRequestBuilder builder = client.prepareSearch("crm").setTypes("user"); //獲得boolQuery對象 BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //獲得must List<QueryBuilder> must = boolQuery.must(); must.add(QueryBuilders.matchAllQuery()); //添加filter過濾器 boolQuery.filter(QueryBuilders.rangeQuery("age").gte(18).lte(48)); builder.setQuery(boolQuery); //添加分頁 builder.setFrom(0); builder.setSize(10); //設置排序 builder.addSort("age", SortOrder.ASC); //設置查詢字段 builder.setFetchSource(new String[]{"name","age"}, null); //取值 SearchResponse searchResponse = builder.get(); //獲得查詢內容 SearchHits hits = searchResponse.getHits(); //獲得命中數據,返回數組 SearchHit[] hitsHits = hits.getHits(); //循環數組,打印獲取值 for (SearchHit hitsHit : hitsHits) { System.out.println(hitsHit.getSource()); } client.close(); } }