【轉】SpringBoot ElasticSearch 各種查詢彙總

原文連接:https://www.cnblogs.com/jelly12345/p/14765477.html

 

一:文檔對象如下

複製代碼
@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);
    }
複製代碼
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章