一:文檔對象如下
@Data @AllArgsConstructor @NoArgsConstructor @Document(indexName = "items", type = "item",shards = 5, replicas = 1) public class Item implements Serializable { @Id private Long id; /**標題*/ @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word") private String title; /**分類*/ @Field(type = FieldType.Keyword) private String category; /**品牌*/ @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_max_word") private String brand; /**價格*/ @Field(type = FieldType.Double) private Double price; /**圖片地址*/ @Field(index = false, type = FieldType.Keyword) private String images; }
二:非聚合復雜查詢(這兒展示了非聚合復雜查詢的常用流程)
public void listPage(){ //1.創建QueryBuilder(即設置查詢條件)這兒創建的是組合查詢(也叫多條件查詢),后面會介紹更多的查詢方法 /*組合查詢BoolQueryBuilder * must(QueryBuilders) :AND * mustNot(QueryBuilders):NOT * should: :OR */ BoolQueryBuilder builder = QueryBuilders.boolQuery(); //builder下有must、should以及mustNot 相當於sql中的and、or以及not //設置模糊搜索,博客的簡訴中有學習兩個字 builder.must(QueryBuilders.fuzzyQuery("category", "一級")); //設置要查詢博客的標題中含有關鍵字 // builder.must(new QueryStringQueryBuilder("title").field("阿迪達斯褲子")); //按照博客的評論數的排序是依次降低 FieldSortBuilder sort = SortBuilders.fieldSort("price").order(SortOrder.DESC); //設置分頁(從第一頁開始,一頁顯示10條) //注意開始是從0開始,有點類似sql中的方法limit 的查詢 PageRequest page = new PageRequest(0, 10); //2.構建查詢 NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); //將搜索條件設置到構建中 nativeSearchQueryBuilder.withQuery(builder); //將分頁設置到構建中 nativeSearchQueryBuilder.withPageable(page); //將排序設置到構建中 nativeSearchQueryBuilder.withSort(sort); //生產NativeSearchQuery NativeSearchQuery query = nativeSearchQueryBuilder.build(); //3.執行方法1 Page<Item> itemPage = itemRespository.search(query); //執行方法2:注意,這兒執行的時候還有個方法那就是使用elasticsearchTemplate //執行方法2的時候需要加上注解 //@Autowired //private ElasticsearchTemplate elasticsearchTemplate; List<Item> blogList = elasticsearchTemplate.queryForList(query, Item.class); //4.獲取總條數(用於前端分頁) int total = (int) itemPage.getTotalElements(); //5.獲取查詢到的數據內容(返回給前端) List<Item> content = itemPage.getContent(); System.out.println(total); System.out.println(content); }
三:精確查詢(必須完全匹配上)
單個匹配termQuery
//不分詞查詢 參數1: 字段名,參數2:字段查詢值,因為不分詞,所以漢字只能查詢一個字,英語是一個單詞. QueryBuilder queryBuilder=QueryBuilders.termQuery("fieldName", "fieldlValue"); //分詞查詢,采用默認的分詞器 QueryBuilder queryBuilder2 = QueryBuilders.matchQuery("fieldName", "fieldlValue");
多個匹配
//不分詞查詢,參數1: 字段名,參數2:多個字段查詢值,因為不分詞,所以漢字只能查詢一個字,英語是一個單詞. QueryBuilder queryBuilder=QueryBuilders.termsQuery("fieldName", "fieldlValue1","fieldlValue2..."); //分詞查詢,采用默認的分詞器 QueryBuilder queryBuilder= QueryBuilders.multiMatchQuery("fieldlValue", "fieldName1", "fieldName2", "fieldName3"); //匹配所有文件,相當於就沒有設置查詢條件 QueryBuilder queryBuilder=QueryBuilders.matchAllQuery();
四:模糊查詢(只要包含即可)
//模糊查詢常見的5個方法如下 //1.常用的字符串查詢 QueryBuilders.queryStringQuery("fieldValue").field("fieldName");//左右模糊 //2.常用的用於推薦相似內容的查詢 QueryBuilders.moreLikeThisQuery(new String[] {"fieldName"}).addLikeText("pipeidhua");//如果不指定filedName,則默認全部,常用在相似內容的推薦上 //3.前綴查詢 如果字段沒分詞,就匹配整個字段前綴 QueryBuilders.prefixQuery("fieldName","fieldValue"); //4.fuzzy query:分詞模糊查詢,通過增加fuzziness模糊屬性來查詢,如能夠匹配hotelName為tel前或后加一個字母的文檔,fuzziness 的含義是檢索的term 前后增加或減少n個單詞的匹配查詢 QueryBuilders.fuzzyQuery("hotelName", "tel").fuzziness(Fuzziness.ONE); //5.wildcard query:通配符查詢,支持* 任意字符串;?任意一個字符 QueryBuilders.wildcardQuery("fieldName","ctr*");//前面是fieldname,后面是帶匹配字符的字符串 QueryBuilders.wildcardQuery("fieldName","c?r?");
五:范圍查詢
//閉區間查詢 QueryBuilder queryBuilder0 = QueryBuilders.rangeQuery("fieldName").from("fieldValue1").to("fieldValue2"); //開區間查詢 QueryBuilder queryBuilder1 = QueryBuilders.rangeQuery("fieldName").from("fieldValue1").to("fieldValue2").includeUpper(false).includeLower(false);//默認是true,也就是包含 //大於 QueryBuilder queryBuilder2 = QueryBuilders.rangeQuery("fieldName").gt("fieldValue"); //大於等於 QueryBuilder queryBuilder3 = QueryBuilders.rangeQuery("fieldName").gte("fieldValue"); //小於 QueryBuilder queryBuilder4 = QueryBuilders.rangeQuery("fieldName").lt("fieldValue"); //小於等於 QueryBuilder queryBuilder5 = QueryBuilders.rangeQuery("fieldName").lte("fieldValue");
六:組合查詢/多條件查詢/布爾查詢
QueryBuilders.boolQuery() QueryBuilders.boolQuery().must();//文檔必須完全匹配條件,相當於and QueryBuilders.boolQuery().mustNot();//文檔必須不匹配條件,相當於not QueryBuilders.boolQuery().should();//至少滿足一個條件,這個文檔就符合should,相當於or
七:聚合查詢
Elasticsearch有一個功能叫做 聚合(aggregations) ,它允許你在數據上生成復雜的分析統計。它很像SQL中的 GROUP BY 但是功能更強大。
為了掌握聚合,你只需要了解兩個主要概念:(參考https://blog.csdn.net/dm_vincent/article/details/42387161)
Buckets(桶):滿足某個條件的文檔集合。
Metrics(指標):為某個桶中的文檔計算得到的統計信息。
就是這樣!每個聚合只是簡單地由一個或者多個桶,零個或者多個指標組合而成。可以將它粗略地轉換為SQL:
SELECT COUNT(color) FROM table GROUP BY color
以上的COUNT(color)就相當於一個指標。GROUP BY color則相當於一個桶。
桶和SQL中的組(Grouping)擁有相似的概念,而指標則與COUNT(),SUM(),MAX()等相似。
讓我們仔細看看這些概念。
桶(Buckets)
一個桶就是滿足特定條件的一個文檔集合:
一名員工要么屬於男性桶,或者女性桶。
城市Albany屬於New York州這個桶。
日期2014-10-28屬於十月份這個桶。
隨着聚合被執行,每份文檔中的值會被計算來決定它們是否匹配了桶的條件。如果匹配成功,那么該文檔會被置入該桶中,同時聚合會繼續執行。
桶也能夠嵌套在其它桶中,能讓你完成層次或者條件划分這些需求。比如,Cincinnati可以被放置在Ohio州這個桶中,而整個Ohio州則能夠被放置在美國這個桶中。
ES中有很多類型的桶,讓你可以將文檔通過多種方式進行划分(按小時,按最流行的詞條,按年齡區間,按地理位置,以及更多)。但是從根本上,它們都根據相同的原理運作:按照條件對文檔進行划分。
指標(Metrics)
桶能夠讓我們對文檔進行有意義的划分,但是最終我們還是需要對每個桶中的文檔進行某種指標計算。分桶是達到最終目的的手段:提供了對文檔進行划分的方法,從而讓你能夠計算需要的指標。
多數指標僅僅是簡單的數學運算(比如,min,mean,max以及sum),它們使用文檔中的值進行計算。在實際應用中,指標能夠讓你計算例如平均薪資,最高出售價格,或者百分之95的查詢延遲。
將兩者結合起來
一個聚合就是一些桶和指標的組合。一個聚合可以只有一個桶,或者一個指標,或者每樣一個。在桶中甚至可以有多個嵌套的桶。比如,我們可以將文檔按照其所屬國家進行分桶,然后對每個桶計算其平均薪資(一個指標)。
因為桶是可以嵌套的,我們能夠實現一個更加復雜的聚合操作:
①:將文檔按照國家進行分桶。(桶)
②:然后將每個國家的桶再按照性別分桶。(桶)
③:然后將每個性別的桶按照年齡區間進行分桶。(桶)
④:最后,為每個年齡區間計算平均薪資。(指標)
聚合查詢都是由AggregationBuilders創建的,一些常見的聚合查詢如下
(1)統計某個字段的數量 ValueCountBuilder vcb= AggregationBuilders.count("count_uid").field("uid"); (2)去重統計某個字段的數量(有少量誤差) CardinalityBuilder cb= AggregationBuilders.cardinality("distinct_count_uid").field("uid"); (3)聚合過濾 FilterAggregationBuilder fab= AggregationBuilders.filter("uid_filter").filter(QueryBuilders.queryStringQuery("uid:001")); (4)按某個字段分組 TermsBuilder tb= AggregationBuilders.terms("group_name").field("name"); (5)求和 SumBuilder sumBuilder= AggregationBuilders.sum("sum_price").field("price"); (6)求平均 AvgBuilder ab= AggregationBuilders.avg("avg_price").field("price"); (7)求最大值 MaxBuilder mb= AggregationBuilders.max("max_price").field("price"); (8)求最小值 MinBuilder min= AggregationBuilders.min("min_price").field("price"); (9)按日期間隔分組 DateHistogramBuilder dhb= AggregationBuilders.dateHistogram("dh").field("date"); (10)獲取聚合里面的結果 TopHitsBuilder thb= AggregationBuilders.topHits("top_result"); (11)嵌套的聚合 NestedBuilder nb= AggregationBuilders.nested("negsted_path").path("quests"); (12)反轉嵌套 AggregationBuilders.reverseNested("res_negsted").path("kps ");
聚合查詢的詳細使用步驟如下:
public void aggregation(){ //目標:搜索寫博客寫得最多的用戶(一個博客對應一個用戶),通過搜索博客中的用戶名的頻次來達到想要的結果 //首先新建一個用於存儲數據的集合 List<String> ueserNameList=new ArrayList<>(); //1.創建查詢條件,也就是QueryBuild QueryBuilder matchAllQuery = QueryBuilders.matchAllQuery();//設置查詢所有,相當於不設置查詢條件 //2.構建查詢 NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder(); //2.0 設置QueryBuilder nativeSearchQueryBuilder.withQuery(matchAllQuery); //2.1設置搜索類型,默認值就是QUERY_THEN_FETCH,參考https://blog.csdn.net/wulex/article/details/71081042 nativeSearchQueryBuilder.withSearchType(SearchType.QUERY_THEN_FETCH);//指定索引的類型,只先從各分片中查詢匹配的文檔,再重新排序和排名,取前size個文檔 //2.2指定索引庫和文檔類型 nativeSearchQueryBuilder.withIndices("items").withTypes("item");//指定要查詢的索引庫的名稱和類型,其實就是我們文檔@Document中設置的indexName和type //2.3重點來了!!!指定聚合函數,本例中以某個字段分組聚合為例(可根據你自己的聚合查詢需求設置) //該聚合函數解釋:計算該字段(假設為username)在所有文檔中的出現頻次,並按照降序排名(常用於某個字段的熱度排名) AbstractAggregationBuilder aggregation = AggregationBuilders.terms("給聚合查詢取的名").field("category"); AvgAggregationBuilder avgAggregationBuilder= AggregationBuilders.avg("avg_price").field("price"); nativeSearchQueryBuilder.addAggregation(avgAggregationBuilder); //2.4構建查詢對象 NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build(); //3.執行查詢 //3.1方法1,通過reporitory執行查詢,獲得有Page包裝了的結果集 Page<Item> search = itemRespository.search(nativeSearchQuery); List<Item> content = search.getContent(); for (Item esBlog : content) { ueserNameList.add(esBlog.getTitle()); } //獲得對應的文檔之后我就可以獲得該文檔的作者,那么就可以查出最熱門用戶了 //3.2方法2,通過elasticSearch模板elasticsearchTemplate.queryForList方法查詢 List<Item> queryForList = elasticsearchTemplate.queryForList(nativeSearchQuery, Item.class); //3.3方法3,通過elasticSearch模板elasticsearchTemplate.query()方法查詢,獲得聚合(常用) Aggregations aggregations = elasticsearchTemplate.query(nativeSearchQuery, new ResultsExtractor<Aggregations>() { @Override public Aggregations extract(SearchResponse response) { return response.getAggregations(); } }); //轉換成map集合 Map<String, Aggregation> aggregationMap = aggregations.asMap(); //獲得對應的聚合函數的聚合子類,該聚合子類也是個map集合,里面的value就是桶Bucket,我們要獲得Bucket StringTerms stringTerms = (StringTerms) aggregationMap.get("給聚合查詢取的名"); //獲得所有的桶 List<StringTerms.Bucket> buckets = stringTerms.getBuckets(); //將集合轉換成迭代器遍歷桶,當然如果你不刪除buckets中的元素,直接foreach遍歷就可以了 Iterator<StringTerms.Bucket> iterator = buckets.iterator(); while(iterator.hasNext()) { //bucket桶也是一個map對象,我們取它的key值就可以了 String username = iterator.next().getKeyAsString();//或者bucket.getKey().toString(); //根據username去結果中查詢即可對應的文檔,添加存儲數據的集合 ueserNameList.add(username); } System.out.println(ueserNameList); }