Elasticsearch 使用 Java High Level REST Client 聚合查詢

聚合查詢不是直接查詢文檔數(shù)據(jù)系羞,而是對文檔數(shù)據(jù)按照某些維度進(jìn)行統(tǒng)計(jì)柑肴,如果你熟悉 MySql 的聚合查詢灼芭,這個也就好理解了废膘。之前我們已經(jīng)學(xué)習(xí)了使用 RESTful API 聚合查詢竹海,現(xiàn)在學(xué) Java High Level REST Client 的聚合查詢也就很簡單了,

我們還是使用上一篇的文檔數(shù)據(jù)學(xué)習(xí)聚合查詢:


我們一般可以使用AggregationBuilders類的靜態(tài)方法來構(gòu)建需要的聚合方式丐黄。它會返回一個 Builder 類斋配,當(dāng)然你也可以直接new一個指定聚合方式的 Builder 類。

1、avg

public void avg() throws IOException {
    SearchRequest request = new SearchRequest("user");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 統(tǒng)計(jì)文檔中age字段的平均值艰争,avgAge相當(dāng)于統(tǒng)計(jì)結(jié)果的名稱
    AvgAggregationBuilder avgBuilder = AggregationBuilders.avg("avgAge").field("age");
    // 設(shè)置聚合查詢
    searchSourceBuilder.aggregation(avgBuilder);
    request.source(searchSourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 取出統(tǒng)計(jì)結(jié)果
    Avg avg = response.getAggregations().get("avgAge");
    double value = avg.getValue();
    System.out.println(value);
}

上邊是統(tǒng)計(jì)age的平均值坏瞄,注意,由于沒有添加其它查詢條件甩卓,則會統(tǒng)計(jì)索引中所有文檔鸠匀。

2、max

統(tǒng)計(jì)age的最大值:

public void max() throws IOException {
    SearchRequest request = new SearchRequest("user");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 統(tǒng)計(jì)文檔中age字段的最大值
    MaxAggregationBuilder maxBuilder = AggregationBuilders.max("maxAge").field("age");
    searchSourceBuilder.aggregation(maxBuilder);
    request.source(searchSourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 取出統(tǒng)計(jì)結(jié)果
    Max max = response.getAggregations().get("maxAge");
    double value = max.getValue();
    System.out.println(value);
}

3逾柿、min缀棍、sum

統(tǒng)計(jì)最小值以及求和的實(shí)現(xiàn)上邊的類似,就不詳細(xì)說了:

MinAggregationBuilder minBuilder = AggregationBuilders.min("minAge").field("age");
SumAggregationBuilder sumBuilder = AggregationBuilders.sum("sumAge").field("age");

4机错、range

range表示按區(qū)間統(tǒng)計(jì)爬范,比如指定時間范圍,指定大小區(qū)間等弱匪。如下統(tǒng)計(jì)age在(-∞, 30)青瀑、[30,40]、(40,+∞)三個區(qū)間的人數(shù):

public void range() throws IOException {
    SearchRequest request = new SearchRequest("user");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 統(tǒng)計(jì)文檔中age字段的最大值
    RangeAggregationBuilder rangeBuilder = AggregationBuilders.range("rangeAge")
            .field("age")
            .addUnboundedTo(30)
            .addRange(30, 40)
            .addUnboundedFrom(40);
    searchSourceBuilder.aggregation(rangeBuilder);
    request.source(searchSourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 取出統(tǒng)計(jì)結(jié)果
    Range range = response.getAggregations().get("rangeAge");
    for (Range.Bucket bucket : range.getBuckets()) {
        // 打印每個區(qū)間的人數(shù)
        System.out.println("age區(qū)間 " + bucket.getKeyAsString() + " 的人數(shù):" + bucket.getDocCount());
    }

統(tǒng)計(jì)的結(jié)果如下:


5萧诫、filter

filter可以按指定的查詢條件過濾數(shù)據(jù)狱窘,如下統(tǒng)計(jì)姓school北大的人數(shù):

public void filter() throws IOException {
    SearchRequest request = new SearchRequest("user");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 統(tǒng)計(jì)文檔中school是北大的人數(shù)
    // 先構(gòu)建查詢條件
    TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("school.keyword", "北大");
    // 設(shè)置過濾統(tǒng)計(jì)的查詢條件
    FilterAggregationBuilder filterBuilder = AggregationBuilders.filter("count", termQueryBuilder);
    searchSourceBuilder.aggregation(filterBuilder);
    request.source(searchSourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 取出統(tǒng)計(jì)結(jié)果
    Filter filter = response.getAggregations().get("count");
    double value = filter.getDocCount();
    System.out.println(value);
}

6、count

count是統(tǒng)計(jì)數(shù)量的财搁,如下根據(jù)文檔 id 統(tǒng)計(jì)索引中的文檔數(shù):

public void valueCount() throws IOException {
    SearchRequest request = new SearchRequest("user");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 根據(jù)文檔id統(tǒng)計(jì)索引的文檔數(shù)
    ValueCountAggregationBuilder valueCountBuilder = AggregationBuilders.count("count").field("_id");
    searchSourceBuilder.aggregation(valueCountBuilder);
    request.source(searchSourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 取出統(tǒng)計(jì)結(jié)果
    ValueCount valueCount = response.getAggregations().get("count");
    double value = valueCount.getValue();
    System.out.println(value);
}

7蘸炸、terms

terms是按指定字段對文檔數(shù)據(jù)進(jìn)行分組,如下按school字段進(jìn)行分組尖奔,統(tǒng)計(jì)出前20組(默認(rèn)10組)搭儒,并按每組的數(shù)據(jù)量升序排列(默認(rèn)降序):

public void terms() throws IOException {
    SearchRequest request = new SearchRequest("user");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 按照school分組
    TermsAggregationBuilder termsBuilder = AggregationBuilders.terms("schoolGroup")
            .field("school.keyword")
            // 按每組的數(shù)據(jù)量升序排列
            .order(BucketOrder.aggregation("_count", true))
            // 最多統(tǒng)計(jì)出20組數(shù)據(jù)
            .size(20);
    searchSourceBuilder.aggregation(termsBuilder);
    request.source(searchSourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 取出統(tǒng)計(jì)結(jié)果
    Terms terms = response.getAggregations().get("schoolGroup");
    for (Terms.Bucket bucket : terms.getBuckets()) {
        System.out.println(bucket.getKeyAsString() + " 的人數(shù):" + bucket.getDocCount());
    }
}

8、子統(tǒng)計(jì)

上邊我們使用terms對文檔數(shù)據(jù)按照school字段進(jìn)行了分組提茁,我們還可以對組內(nèi)的數(shù)據(jù)進(jìn)行其它統(tǒng)計(jì)淹禾,例如統(tǒng)計(jì)age的最小值,這就是子統(tǒng)計(jì)茴扁。代碼如下:

public void sub() throws IOException {
    SearchRequest request = new SearchRequest("user");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 按照school分組
    TermsAggregationBuilder termsBuilder = AggregationBuilders.terms("schoolGroup")
            .field("school.keyword")
            // 按每組的數(shù)據(jù)量升序排列
            .order(BucketOrder.aggregation("_count", true))
            // 最多統(tǒng)計(jì)出20組數(shù)據(jù)
            .size(20)
            // 添加子統(tǒng)計(jì)
            .subAggregation(AggregationBuilders.min("minAge").field("age"));
    searchSourceBuilder.aggregation(termsBuilder);
    request.source(searchSourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 取出統(tǒng)計(jì)結(jié)果
    Terms terms = response.getAggregations().get("schoolGroup");
    for (Terms.Bucket bucket : terms.getBuckets()) {
        // 取出子統(tǒng)計(jì)的結(jié)果
        Min min = bucket.getAggregations().get("minAge");
        System.out.println(bucket.getKeyAsString() + " 的人數(shù):" + bucket.getDocCount() + "铃岔,age的最小值:" + min.getValue());
    }
}

9、topHits

前邊的各種聚合查詢只能統(tǒng)計(jì)出最終的結(jié)果峭火,我們并不能知道那些文檔數(shù)據(jù)參與了統(tǒng)計(jì)毁习,topHits可以用來跟蹤正在參與分組聚合統(tǒng)計(jì)的文檔數(shù)據(jù),我在前邊terms例子的基礎(chǔ)上繼續(xù)修改卖丸,來跟蹤每組內(nèi)的前20條數(shù)據(jù)(默認(rèn)10條數(shù)據(jù))纺且,并按age升序排列:

public void topHits() throws IOException {
    SearchRequest request = new SearchRequest("user");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // 跟蹤正在參與分組聚合統(tǒng)計(jì)的文檔數(shù)據(jù)
    TopHitsAggregationBuilder topHitsBuilder = AggregationBuilders.topHits("groupData")
            // 跟蹤前20條數(shù)據(jù)
            .size(20)
            // 按age升序排列
            .sort("age", SortOrder.ASC);
    // 按照school分組
    TermsAggregationBuilder termsBuilder = AggregationBuilders.terms("schoolGroup")
            .field("school.keyword")
            // 按每組的數(shù)據(jù)量升序排列
            .order(BucketOrder.aggregation("_count", true))
            // 最多統(tǒng)計(jì)出20組數(shù)據(jù)
            .size(20)
            // 添加文檔數(shù)據(jù)跟蹤
            .subAggregation(topHitsBuilder);
    searchSourceBuilder.aggregation(termsBuilder);
    request.source(searchSourceBuilder);
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    // 取出統(tǒng)計(jì)結(jié)果
    Terms terms = response.getAggregations().get("schoolGroup");
    for (Terms.Bucket bucket : terms.getBuckets()) {
        System.out.println(bucket.getKeyAsString() + " 的人數(shù):" + bucket.getDocCount());
        // 取出topHits跟蹤的文檔數(shù)據(jù)
        TopHits groupData = bucket.getAggregations().get("groupData");
        for (SearchHit hit : groupData.getHits()) {
            System.out.println(hit.getSourceAsString());
        }
        System.out.println("---------------------------------------------------------------------------");
    }
}

聚合查詢的相關(guān)內(nèi)容就介紹這么多了,更多的可以查看官方文檔稍浆。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末载碌,一起剝皮案震驚了整個濱河市猜嘱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嫁艇,老刑警劉巖朗伶,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異步咪,居然都是意外死亡腕让,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門歧斟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纯丸,“玉大人,你說我怎么就攤上這事静袖【醣牵” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵队橙,是天一觀的道長坠陈。 經(jīng)常有香客問我,道長捐康,這世上最難降的妖魔是什么仇矾? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮解总,結(jié)果婚禮上贮匕,老公的妹妹穿的比我還像新娘。我一直安慰自己花枫,他們只是感情好刻盐,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著劳翰,像睡著了一般敦锌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上佳簸,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天乙墙,我揣著相機(jī)與錄音,去河邊找鬼生均。 笑死听想,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的疯特。 我是一名探鬼主播哗魂,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼肛走,長吁一口氣:“原來是場噩夢啊……” “哼漓雅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤邻吞,失蹤者是張志新(化名)和其女友劉穎组题,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抱冷,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡崔列,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了旺遮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赵讯。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖耿眉,靈堂內(nèi)的尸體忽然破棺而出边翼,到底是詐尸還是另有隱情,我是刑警寧澤鸣剪,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布组底,位于F島的核電站,受9級特大地震影響筐骇,放射性物質(zhì)發(fā)生泄漏债鸡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一铛纬、第九天 我趴在偏房一處隱蔽的房頂上張望厌均。 院中可真熱鬧,春花似錦告唆、人聲如沸莫秆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镊屎。三九已至,卻和暖如春茄螃,著一層夾襖步出監(jiān)牢的瞬間缝驳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工归苍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留用狱,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓拼弃,卻偏偏與公主長得像夏伊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吻氧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容