ElasticSearch入門之彼行我釋(四)

1d928eea-8562-3f0c-b31c-22c0d9c02b8b.jpg

散仙在上篇文章中,介紹了關於ElasticSearch基本的增刪改查的基本粒子,本篇呢,我們來學下稍微高級一點的知識: 


(1)如何在ElasticSearch中批量提交索引 ? 
(2)如何使用高級查詢(包括,檢索,排序,過濾,分頁) ? 
(3)如何組合多個查詢 ? 
(4)如何使用翻頁深度查詢 ? 
(5)如何使用基本的聚合查詢 ? 



(一)首先,我們思考下,爲什麼要使用批量添加,這個毫無疑問,因爲效率問題,舉個在生活中的例子,假如我們有50個人,要去美國旅遊,不使用批處理的方式是,給每一個人派一架飛機送到美國,那麼這就需要50次飛機的來回往來,假如使用了批處理,現在的情況就是一個飛機坐50個人,只需一次即可把所有人都送到美國,效率可想而知,生活也有很多實際的例子,大家可以自己想想。 

在原生的lucene中,以及solr中,這個批處理方式,實質是控制commit的時機,比如多少個提交一次,或者超過ranbuffersize的大小後自動提交,es封裝了lucene的api提供bulk的方式來批量添加,原理也是,聚集一定的數量doc,然後發送一次添加請求。 


(二)只要我們使用了全文檢索,我們的業務就會有各種各樣的api操作,包括,任意維度的字段查詢,過濾掉某些無效的信息,然後根據某個字段排序,再取topN的結果集返回,使用數據庫的小夥伴們,相信大家都不陌生,在es中,這些操作都是支持的,而且還非常高效,它能滿足我們大部分的需求 


(三)在es中,我們可以查詢多個index,以及多個type,這一點是非常靈活地,我們,我們可以一次組裝兩個毫無關係的查詢,發送到es服務端進行檢索,然後獲取結果。 


(四)es中,通過了scorll的方式,支持深度分頁查詢,在數據庫裏,我們使用的是一個cursor遊標來記錄讀取的偏移量,同樣的在es中也支持,這樣的查詢方式,它通過一個scrollid記錄了上一次查詢的狀態,能輕而易舉的實現深度翻頁,本質上是對了Lucene的SearchAfter的封裝。 

(五)es中,也提供了對聚合函數的支持,比如一些max,min,avg,count,sum等支持,除此之外還支持group,facet等操作,這些功能,在電商中應用非常廣泛,基於lucene的solr和es都有很好的支持。 

下面截圖看下散仙的測試數據值: 


b918454c-3138-3309-aca6-e35e2f59114a.jpg
源碼demo如下: 

Java代碼  收藏代碼

  1. package com.dongliang.es;  

  2.   

  3. import java.util.Date;  

  4. import java.util.Map;  

  5. import java.util.Map.Entry;  

  6.   

  7. import org.apache.lucene.index.Terms;  

  8. import org.elasticsearch.action.bulk.BulkRequestBuilder;  

  9. import org.elasticsearch.action.bulk.BulkResponse;  

  10. import org.elasticsearch.action.search.MultiSearchResponse;  

  11. import org.elasticsearch.action.search.SearchRequestBuilder;  

  12. import org.elasticsearch.action.search.SearchResponse;  

  13. import org.elasticsearch.action.search.SearchType;  

  14. import org.elasticsearch.client.Client;  

  15. import org.elasticsearch.client.transport.TransportClient;  

  16. import org.elasticsearch.common.transport.InetSocketTransportAddress;  

  17. import org.elasticsearch.common.unit.TimeValue;  

  18. import org.elasticsearch.common.xcontent.XContentBuilder;  

  19. import org.elasticsearch.common.xcontent.XContentFactory;  

  20. import org.elasticsearch.index.query.FilterBuilders;  

  21. import org.elasticsearch.index.query.QueryBuilders;  

  22. import org.elasticsearch.index.query.QueryStringQueryBuilder;  

  23. import org.elasticsearch.search.SearchHit;  

  24. import org.elasticsearch.search.aggregations.AggregationBuilders;  

  25. import org.elasticsearch.search.aggregations.bucket.filters.InternalFilters.Bucket;  

  26. import org.elasticsearch.search.sort.SortOrder;  

  27.   

  28. /** 

  29.  * @author 三劫散仙 

  30.  * 搜索技術交流羣:324714439  

  31.  * 一個關於elasticsearch批量提交 

  32.  * 和search query的的例子 

  33.  * **/  

  34. public class ElasticSearchDao {  

  35.       

  36.       

  37.     //es的客戶端實例  

  38.     Client client=null;  

  39.     {  

  40.         //連接單臺機器,注意ip和端口號,不能寫錯  

  41.         client=new TransportClient().  

  42.                 addTransportAddress(new InetSocketTransportAddress("192.168.46.16"9300));  

  43.           

  44.     }  

  45.       

  46.       

  47.     public static void main(String[] args)throws Exception {  

  48.         ElasticSearchDao es=new ElasticSearchDao();  

  49.         //es.indexdata();//索引數據  

  50.         //es.queryComplex();  

  51.         es.querySimple();  

  52.         //es.scorllQuery();  

  53.         //es.mutilCombineQuery();  

  54.         //es.aggregationQuery();  

  55.     }  

  56.       

  57.       

  58.     /**組合分組查詢*/  

  59.     public void aggregationQuery()throws Exception{  

  60.         SearchResponse sr = client.prepareSearch()  

  61.                 .setQuery(QueryBuilders.matchAllQuery())  

  62.                 .addAggregation(  

  63.                         AggregationBuilders.terms("1").field("type")  

  64.                 )  

  65. //              .addAggregation(  

  66. //                      AggregationBuilders.dateHistogram("agg2")  

  67. //                              .field("birth")  

  68. //                              .interval(DateHistogram.Interval.YEAR)  

  69. //              )  

  70.                 .execute().actionGet();  

  71.   

  72.             // Get your facet results  

  73.             org.elasticsearch.search.aggregations.bucket.terms.Terms a = sr.getAggregations().get("1");  

  74.               

  75.             for(org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket bk:a.getBuckets()){  

  76.                 System.out.println("類型: "+bk.getKey()+"  分組統計數量 "+bk.getDocCount()+"  ");  

  77.             }  

  78.               

  79.             System.out.println("聚合數量:"+a.getBuckets().size());  

  80.             //DateHistogram agg2 = sr.getAggregations().get("agg2");  

  81.             //結果:  

  82. //          類型: 1  分組數量 2    

  83. //          類型: 2  分組數量 1    

  84. //          類型: 3  分組數量 1    

  85. //          聚合數量:3  

  86.     }  

  87.       

  88.       

  89.       

  90.       

  91.     /**多個不一樣的請求組裝*/  

  92.     public void mutilCombineQuery(){  

  93.           

  94.         //查詢請求1  

  95.         SearchRequestBuilder srb1 =client.prepareSearch().setQuery(QueryBuilders.queryString("eng").field("address")).setSize(1);  

  96.         //查詢請求2//matchQuery  

  97.         SearchRequestBuilder srb2 = client.prepareSearch().setQuery(QueryBuilders.matchQuery("title""標題")).setSize(1);  

  98.         //組裝查詢  

  99.         MultiSearchResponse sr = client.prepareMultiSearch().add(srb1).add(srb2).execute().actionGet();  

  100.   

  101.             // You will get all individual responses from MultiSearchResponse#getResponses()  

  102.             long nbHits = 0;  

  103.             for (MultiSearchResponse.Item item : sr.getResponses()) {  

  104.                 SearchResponse response = item.getResponse();  

  105.                 for(SearchHit hits:response.getHits().getHits()){  

  106.                     String sourceAsString = hits.sourceAsString();//以字符串方式打印  

  107.                     System.out.println(sourceAsString);  

  108.                 }  

  109.                 nbHits += response.getHits().getTotalHits();  

  110.             }  

  111.         System.out.println("命中數據量:"+nbHits);  

  112.         //輸出:  

  113. //      {"title":"我是標題","price":25.65,"type":1,"status":true,"address":"血落星域風陽星","createDate":"2015-03-16T09:56:20.440Z"}  

  114. //      命中數據量:2  

  115.   

  116.         client.close();  

  117.     }  

  118.       

  119.       

  120.     /** 

  121.      * 翻頁查詢 

  122.      * */  

  123.     public void scorllQuery()throws Exception{  

  124.         QueryStringQueryBuilder queryString = QueryBuilders.queryString("標題").field("title");  

  125.         //TermQueryBuilder qb=QueryBuilders.termQuery("title", "我是標題");  

  126.         SearchResponse scrollResp = client.prepareSearch("collection1")  

  127.                  .setSearchType(SearchType.SCAN)  

  128.                  .setScroll(new TimeValue(60000))  

  129.                  .setQuery(queryString)  

  130.                  .setSize(100).execute().actionGet(); //100 hits per shard will be returned for each scroll  

  131.            

  132.           

  133.         while (true) {  

  134.             for (SearchHit hit : scrollResp.getHits().getHits()) {  

  135.                 //Handle the hit...  

  136.                 String sourceAsString = hit.sourceAsString();//以字符串方式打印  

  137.                 System.out.println(sourceAsString);  

  138.             }  

  139.             //通過scrollid來實現深度翻頁  

  140.             scrollResp = client.prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();  

  141.             //Break condition: No hits are returned  

  142.             if (scrollResp.getHits().getHits().length == 0) {  

  143.                 break;  

  144.             }  

  145.         }  

  146.         //輸出  

  147. //      {"title":"我是標題","price":25.65,"type":1,"status":true,"address":"血落星域風陽星","createDate":"2015-03-16T09:56:20.440Z"}  

  148. //      {"title":"標題","price":251.65,"type":1,"status":true,"address":"美國東部","createDate":"2015-03-16T10:33:58.743Z"}  

  149.         client.close();  

  150.           

  151.     }  

  152.       

  153.     /**簡單查詢*/  

  154.     public void querySimple()throws Exception{  

  155.           

  156.         SearchResponse sp = client.prepareSearch("collection1").execute().actionGet();  

  157.         for(SearchHit hits:sp.getHits().getHits()){  

  158.             String sourceAsString = hits.sourceAsString();//以字符串方式打印  

  159.             System.out.println(sourceAsString);  

  160.         }  

  161.           

  162.           

  163.     //結果  

  164. //              {"title":"我是標題","price":25.65,"type":1,"status":true,"address":"血落星域風陽星","createDate":"2015-03-16T09:56:20.440Z"}  

  165. //              {"title":"中國","price":205.65,"type":2,"status":true,"address":"河南洛陽","createDate":"2015-03-16T10:33:58.740Z"}  

  166. //              {"title":"標題","price":251.65,"type":1,"status":true,"address":"美國東部","createDate":"2015-03-16T10:33:58.743Z"}  

  167. //              {"title":"elasticsearch是一個搜索引擎","price":25.65,"type":3,"status":true,"address":"china","createDate":"2015-03-16T10:33:58.743Z"}  

  168.   

  169.           

  170.     }  

  171.     /**組合查詢**/  

  172.     public void queryComplex()throws Exception{  

  173.         SearchResponse sp=client.prepareSearch("collection1")//檢索的目錄  

  174.                 .setTypes("core1")//檢索的索引  

  175.                 .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)//Query type  

  176.                 .setQuery(QueryBuilders.termQuery("type""1"))//查詢--Query   

  177.                 .setPostFilter(FilterBuilders.rangeFilter("price").from(10).to(550.23))//過濾 --Filter  

  178.                 .addSort("price",SortOrder.DESC) //排序 -- sort  

  179.                 .setFrom(0).setSize(20).setExplain(true)//topN方式  

  180.                 .execute().actionGet();//執行  

  181.                 System.out.println("本次查詢命中條數: "+sp.getHits().getTotalHits());  

  182.                 for(SearchHit hits:sp.getHits().getHits()){  

  183.                     //String sourceAsString = hits.sourceAsString();//以字符串方式打印  

  184.                     //System.out.println(sourceAsString);  

  185.                     Map<String, Object> sourceAsMap = hits.sourceAsMap();  

  186.                     for(Entry<String, Object> k:sourceAsMap.entrySet()){  

  187.                         System.out.println("name: "+k.getKey()+"     value: "+k.getValue());  

  188.                     }  

  189.                       

  190.                     System.out.println("=============================================");  

  191.                       

  192.                 }  

  193.           

  194.                 //結果  

  195. //              本次查詢命中條數: 2  

  196. //              name: title     value: 標題  

  197. //              name: price     value: 251.65  

  198. //              name: address     value: 美國東部  

  199. //              name: status     value: true  

  200. //              name: createDate     value: 2015-03-16T10:33:58.743Z  

  201. //              name: type     value: 1  

  202. //              =============================================  

  203. //              name: title     value: 我是標題  

  204. //              name: price     value: 25.65  

  205. //              name: address     value: 血落星域風陽星  

  206. //              name: status     value: true  

  207. //              name: createDate     value: 2015-03-16T09:56:20.440Z  

  208. //              name: type     value: 1  

  209. //              =============================================  

  210.           

  211.         client.close();  

  212.     }  

  213.       

  214.       

  215.       

  216.     /**索引數據*/  

  217.     public void indexdata()throws Exception{  

  218.           

  219.         BulkRequestBuilder bulk=client.prepareBulk();  

  220.           

  221.         XContentBuilder doc=XContentFactory.jsonBuilder()  

  222.                 .startObject()  

  223.                 .field("title","中國")  

  224.                 .field("price",205.65)  

  225.                 .field("type",2)  

  226.                 .field("status",true)  

  227.                 .field("address""河南洛陽")  

  228.                 .field("createDate"new Date()).endObject();  

  229.         //collection爲索引庫名,類似一個數據庫,索引名爲core,類似一個表  

  230. //       client.prepareIndex("collection1", "core1").setSource(doc).execute().actionGet();  

  231.           

  232.         //批處理添加  

  233.         bulk.add(client.prepareIndex("collection1""core1").setSource(doc));  

  234.           

  235.         doc=XContentFactory.jsonBuilder()  

  236.                 .startObject()  

  237.                 .field("title","標題")  

  238.                 .field("price",251.65)  

  239.                 .field("type",1)  

  240.                 .field("status",true)  

  241.                 .field("address""美國東部")  

  242.                 .field("createDate"new Date()).endObject();  

  243.         //collection爲索引庫名,類似一個數據庫,索引名爲core,類似一個表  

  244. //      client.prepareIndex("collection1", "core1").setSource(doc).execute().actionGet();  

  245.         //批處理添加  

  246.         bulk.add(client.prepareIndex("collection1""core1").setSource(doc));  

  247.           

  248.         doc=XContentFactory.jsonBuilder()  

  249.                 .startObject()  

  250.                 .field("title","elasticsearch是一個搜索引擎")  

  251.                 .field("price",25.65)  

  252.                 .field("type",3)  

  253.                 .field("status",true)  

  254.                 .field("address""china")  

  255.                 .field("createDate"new Date()).endObject();  

  256.         //collection爲索引庫名,類似一個數據庫,索引名爲core,類似一個表  

  257.         //client.prepareIndex("collection1", "core1").setSource(doc).execute().actionGet();  

  258.         //批處理添加  

  259.         bulk.add(client.prepareIndex("collection1""core1").setSource(doc));         

  260.           

  261.           

  262.         //發一次請求,提交所有數據  

  263.           BulkResponse bulkResponse = bulk.execute().actionGet();  

  264.           if (!bulkResponse.hasFailures()) {  

  265.               System.out.println("創建索引success!");  

  266.           } else {  

  267.               System.out.println("創建索引異常:"+bulkResponse.buildFailureMessage());  

  268.           }  

  269.           

  270.           

  271.           

  272.         client.close();//釋放資源  

  273. //      System.out.println("索引成功!");  

  274.                   

  275.           

  276.           

  277.           

  278.     }  

  279.       

  280.       

  281.       

  282.       

  283.   

  284. }  





想了解更多有關電商互聯網公司的搜索技術和大數據技術的使用,請歡迎掃碼關注微信公衆號:我是攻城師(woshigcs) 
本公衆號的內容是有關搜索和大數據技術和互聯網等方面內容的分享,也是一個溫馨的技術互動交流的小家園,有什麼問題隨時都可以留言,歡迎大家來訪! 



3214000f-5633-3c17-a3d7-83ebda9aebff.jpg 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章