散仙在上篇文章中,介紹了關於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都有很好的支持。
下面截圖看下散仙的測試數據值:
源碼demo以下:
java
package com.dongliang.es; apache
import java.util.Date; json
import java.util.Map; api
import java.util.Map.Entry; 微信
import org.apache.lucene.index.Terms; elasticsearch
import org.elasticsearch.action.bulk.BulkRequestBuilder; ide
import org.elasticsearch.action.bulk.BulkResponse; 函數
import org.elasticsearch.action.search.MultiSearchResponse; 測試
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.FilterBuilders;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.filters.InternalFilters.Bucket;
import org.elasticsearch.search.sort.SortOrder;
/**
* @author 三劫散仙
* 搜索技術交流羣:324714439
* 一個關於elasticsearch批量提交
* 和search query的的例子
* **/
public class ElasticSearchDao {
//es的客戶端實例
Client client=null;
{
//鏈接單臺機器,注意ip和端口號,不能寫錯
client=new TransportClient().
addTransportAddress(new InetSocketTransportAddress("192.168.46.16", 9300));
}
public static void main(String[] args)throws Exception {
ElasticSearchDao es=new ElasticSearchDao();
//es.indexdata();//索引數據
//es.queryComplex();
es.querySimple();
//es.scorllQuery();
//es.mutilCombineQuery();
//es.aggregationQuery();
}
/**組合分組查詢*/
public void aggregationQuery()throws Exception{
SearchResponse sr = client.prepareSearch()
.setQuery(QueryBuilders.matchAllQuery())
.addAggregation(
AggregationBuilders.terms("1").field("type")
)
// .addAggregation(
// AggregationBuilders.dateHistogram("agg2")
// .field("birth")
// .interval(DateHistogram.Interval.YEAR)
// )
.execute().actionGet();
// Get your facet results
org.elasticsearch.search.aggregations.bucket.terms.Terms a = sr.getAggregations().get("1");
for(org.elasticsearch.search.aggregations.bucket.terms.Terms.Bucket bk:a.getBuckets()){
System.out.println("類型: "+bk.getKey()+" 分組統計數量 "+bk.getDocCount()+" ");
}
System.out.println("聚合數量:"+a.getBuckets().size());
//DateHistogram agg2 = sr.getAggregations().get("agg2");
//結果:
// 類型: 1 分組數量 2
// 類型: 2 分組數量 1
// 類型: 3 分組數量 1
// 聚合數量:3
}
/**多個不同的請求組裝*/
public void mutilCombineQuery(){
//查詢請求1
SearchRequestBuilder srb1 =client.prepareSearch().setQuery(QueryBuilders.queryString("eng").field("address")).setSize(1);
//查詢請求2//matchQuery
SearchRequestBuilder srb2 = client.prepareSearch().setQuery(QueryBuilders.matchQuery("title", "標題")).setSize(1);
//組裝查詢
MultiSearchResponse sr = client.prepareMultiSearch().add(srb1).add(srb2).execute().actionGet();
// You will get all individual responses from MultiSearchResponse#getResponses()
long nbHits = 0;
for (MultiSearchResponse.Item item : sr.getResponses()) {
SearchResponse response = item.getResponse();
for(SearchHit hits:response.getHits().getHits()){
String sourceAsString = hits.sourceAsString();//以字符串方式打印
System.out.println(sourceAsString);
}
nbHits += response.getHits().getTotalHits();
}
System.out.println("命中數據量:"+nbHits);
//輸出:
// {"title":"我是標題","price":25.65,"type":1,"status":true,"address":"血落星域風陽星","createDate":"2015-03-16T09:56:20.440Z"}
// 命中數據量:2
client.close();
}
/**
* 翻頁查詢
* */
public void scorllQuery()throws Exception{
QueryStringQueryBuilder queryString = QueryBuilders.queryString("標題").field("title");
//TermQueryBuilder qb=QueryBuilders.termQuery("title", "我是標題");
SearchResponse scrollResp = client.prepareSearch("collection1")
.setSearchType(SearchType.SCAN)
.setScroll(new TimeValue(60000))
.setQuery(queryString)
.setSize(100).execute().actionGet(); //100 hits per shard will be returned for each scroll
while (true) {
for (SearchHit hit : scrollResp.getHits().getHits()) {
//Handle the hit...
String sourceAsString = hit.sourceAsString();//以字符串方式打印
System.out.println(sourceAsString);
}
//經過scrollid來實現深度翻頁
scrollResp = client.prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(600000)).execute().actionGet();
//Break condition: No hits are returned
if (scrollResp.getHits().getHits().length == 0) {
break;
}
}
//輸出
// {"title":"我是標題","price":25.65,"type":1,"status":true,"address":"血落星域風陽星","createDate":"2015-03-16T09:56:20.440Z"}
// {"title":"標題","price":251.65,"type":1,"status":true,"address":"美國東部","createDate":"2015-03-16T10:33:58.743Z"}
client.close();
}
/**簡單查詢*/
public void querySimple()throws Exception{
SearchResponse sp = client.prepareSearch("collection1").execute().actionGet();
for(SearchHit hits:sp.getHits().getHits()){
String sourceAsString = hits.sourceAsString();//以字符串方式打印
System.out.println(sourceAsString);
}
//結果
// {"title":"我是標題","price":25.65,"type":1,"status":true,"address":"血落星域風陽星","createDate":"2015-03-16T09:56:20.440Z"}
// {"title":"中國","price":205.65,"type":2,"status":true,"address":"河南洛陽","createDate":"2015-03-16T10:33:58.740Z"}
// {"title":"標題","price":251.65,"type":1,"status":true,"address":"美國東部","createDate":"2015-03-16T10:33:58.743Z"}
// {"title":"elasticsearch是一個搜索引擎","price":25.65,"type":3,"status":true,"address":"china","createDate":"2015-03-16T10:33:58.743Z"}
}
/**組合查詢**/
public void queryComplex()throws Exception{
SearchResponse sp=client.prepareSearch("collection1")//檢索的目錄
.setTypes("core1")//檢索的索引
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)//Query type
.setQuery(QueryBuilders.termQuery("type", "1"))//查詢--Query
.setPostFilter(FilterBuilders.rangeFilter("price").from(10).to(550.23))//過濾 --Filter
.addSort("price",SortOrder.DESC) //排序 -- sort
.setFrom(0).setSize(20).setExplain(true)//topN方式
.execute().actionGet();//執行
System.out.println("本次查詢命中條數: "+sp.getHits().getTotalHits());
for(SearchHit hits:sp.getHits().getHits()){
//String sourceAsString = hits.sourceAsString();//以字符串方式打印
//System.out.println(sourceAsString);
Map<String, Object> sourceAsMap = hits.sourceAsMap();
for(Entry<String, Object> k:sourceAsMap.entrySet()){
System.out.println("name: "+k.getKey()+" value: "+k.getValue());
}
System.out.println("=============================================");
}
//結果
// 本次查詢命中條數: 2
// name: title value: 標題
// name: price value: 251.65
// name: address value: 美國東部
// name: status value: true
// name: createDate value: 2015-03-16T10:33:58.743Z
// name: type value: 1
// =============================================
// name: title value: 我是標題
// name: price value: 25.65
// name: address value: 血落星域風陽星
// name: status value: true
// name: createDate value: 2015-03-16T09:56:20.440Z
// name: type value: 1
// =============================================
client.close();
}
/**索引數據*/
public void indexdata()throws Exception{
BulkRequestBuilder bulk=client.prepareBulk();
XContentBuilder doc=XContentFactory.jsonBuilder()
.startObject()
.field("title","中國")
.field("price",205.65)
.field("type",2)
.field("status",true)
.field("address", "河南洛陽")
.field("createDate", new Date()).endObject();
//collection爲索引庫名,相似一個數據庫,索引名爲core,相似一個表
// client.prepareIndex("collection1", "core1").setSource(doc).execute().actionGet();
//批處理添加
bulk.add(client.prepareIndex("collection1", "core1").setSource(doc));
doc=XContentFactory.jsonBuilder()
.startObject()
.field("title","標題")
.field("price",251.65)
.field("type",1)
.field("status",true)
.field("address", "美國東部")
.field("createDate", new Date()).endObject();
//collection爲索引庫名,相似一個數據庫,索引名爲core,相似一個表
// client.prepareIndex("collection1", "core1").setSource(doc).execute().actionGet();
//批處理添加
bulk.add(client.prepareIndex("collection1", "core1").setSource(doc));
doc=XContentFactory.jsonBuilder()
.startObject()
.field("title","elasticsearch是一個搜索引擎")
.field("price",25.65)
.field("type",3)
.field("status",true)
.field("address", "china")
.field("createDate", new Date()).endObject();
//collection爲索引庫名,相似一個數據庫,索引名爲core,相似一個表
//client.prepareIndex("collection1", "core1").setSource(doc).execute().actionGet();
//批處理添加
bulk.add(client.prepareIndex("collection1", "core1").setSource(doc));
//發一次請求,提交全部數據
BulkResponse bulkResponse = bulk.execute().actionGet();
if (!bulkResponse.hasFailures()) {
System.out.println("建立索引success!");
} else {
System.out.println("建立索引異常:"+bulkResponse.buildFailureMessage());
}
client.close();//釋放資源
// System.out.println("索引成功!");
}
}
想了解更多有關電商互聯網公司的搜索技術和大數據技術的使用,請歡迎掃碼關注微信公衆號:我是攻城師(woshigcs)
本公衆號的內容是有關搜索和大數據技術和互聯網等方面內容的分享,也是一個舒適的技術互動交流的小家園,有什麼問題隨時均可以留言,歡迎你們來訪!