spring整合es后的查詢(普通查詢與聚合查詢)

內(nèi)容簡介


1.spring整合es
2.普通查詢的使用方法
3.聚合查詢的使用方法
4.普通查詢與聚合查詢的使用區(qū)別

spring整合es


1.service層的接口

public interface EsClient {

    public TransportClient getClient();


    public QueryBuilder getQueryCondition(final String name, final String value);
}

2.serviceimpl層的實現(xiàn)類

@Service("esClient")
public class EsClientImpl implements EsClient{

    @Value("${es.clustername}")
    private String clusterName;
    @Value("${es.port}")
    private String port;
    @Value("${es.hosts}")
    private String hosts;


    private TransportClient transportClient = null;

    /**
     * 條件分割器剧腻,多條件使用逗號分割
     *
     * @param name  屬性名
     * @param value 查詢值
     * @return
     */
    public QueryBuilder getQueryCondition(final String name, final String value) {
        if (value.contains(",")) {
            final BoolQueryBuilder boolQuery = QueryBuilders.boolQuery().minimumShouldMatch(1);
            for (final String v : value.split(",")) {
                boolQuery.should(QueryBuilders.termQuery(name, v));
            }
            return boolQuery;
        } else {
            return QueryBuilders.termQuery(name, value);
        }
    }


    @PostConstruct
    public void init() throws Exception {
        connectEs();
    }

    @PreDestroy
    public void destory() {
        disConnectEs();
    }

    private void disConnectEs() {
        if (null != transportClient) {
            transportClient.close();
        }
    }

    private void connectEs() throws Exception {
        Settings settings = Settings.builder().put("cluster.name", clusterName).build();
        transportClient = new PreBuiltTransportClient(settings);
        if (StringUtils.isNotBlank(hosts)) {
            String[] hostArray = hosts.split(",");
            for (String host : hostArray) {
                InetSocketTransportAddress ist = new InetSocketTransportAddress(InetAddress.getByName(host), Integer.parseInt(port));
                transportClient.addTransportAddress(ist);
            }
        }
    }

    public TransportClient getClient() {
        return this.transportClient;
    }
}

3.屬性注入(多種屬性文件剂桥,這里只是一種pom文件存放屬性的方式)

<!--es-->
                <sink.es.clustername>dolphin</sink.es.clustername>
                <sink.es.port>9300</sink.es.port>
                <sink.es.hosts>172.20.78.56,172.20.78.57,172.20.78.58</sink.es.hosts>
                <sink.es.index>sinkreport</sink.es.index>
                <sink.es.type>mg_sink_user_d</sink.es.type>

普通查詢


1.關(guān)于es模塊提供的查詢

public SearchResponse queryFlowInspireActiveChart(CommonQueryParam commonQueryParam) {
        
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (StringUtils.isNotEmpty(commonQueryParam.getProvince())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("province", commonQueryParam.getProvince()));
        }

        if (StringUtils.isNotEmpty(commonQueryParam.getCity())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("city", commonQueryParam.getCity()));
        }
        
        boolQueryBuilder.must(QueryBuilders.termQuery("content_id", "c0001"));
        
        if (StringUtils.isNotEmpty(commonQueryParam.getStart()) && StringUtils.isNotEmpty(commonQueryParam.getEnd())) {
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("dayid");
            rangeQuery.from(commonQueryParam.getStart());
            rangeQuery.to(commonQueryParam.getEnd());
            boolQueryBuilder.must(rangeQuery);
        }
        
        SearchRequestBuilder searchRequestBuilder = esClient.getClient().prepareSearch(index)
                .setTypes(typeName).setSize(10000)
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(boolQueryBuilder)
                .addSort("dayid",SortOrder.ASC);//普通查詢按照dayid升序排列
        
         //打印es語句
        LOGGER.debug(searchRequestBuilder.toString());
        SearchResponse response = searchRequestBuilder.execute().actionGet();
        return response;
    }

2.業(yè)務(wù)層得到es層返回的數(shù)據(jù)進行業(yè)務(wù)開發(fā)

SearchHits hits = response.getHits();
Iterator<SearchHit> it = hits.iterator();
while(it.hasNext()){
            Map<String,Object> map = it.next().getSource();
//日期
       String dayid = map.get("dayid").toString())
//日新增手機用戶數(shù)
       String userNewActive = map.get("user_new_active").toString());
//日存量手機用戶數(shù) = 日活躍手機用戶數(shù)減去日新增手機用戶數(shù)
int resultNumber = Integer.valueOf(map.get("user_active").toString()) - Integer.valueOf(map.get("user_new_active").toString());
        }

3.小總結(jié)
普通查詢很簡單擎颖,對于普通查詢的各種條件全谤,比如限定日期区转,限定省市衫樊,直接在boolQueryBuilder作用must即可零酪。
對于對數(shù)據(jù)進行限定size分頁届垫,直接跟在esClient.getClient().prepareSearch(index)
.setTypes(typeName).setSize(10000)即可茶鹃,這里就是設(shè)置返回最大1000條數(shù)據(jù)涣雕。

聚合查詢


es的聚合是聚合,普通查詢是普通查詢闭翩,取數(shù)據(jù)的方式不同挣郭,所以不能兩個同時使用,所以對數(shù)據(jù)進行限定的時候疗韵,應(yīng)該放到聚合語句里面限定兑障,關(guān)閉掉普通的size。
1.es聚合查詢

public SearchResponse queryFlowInspireTopTenDataByProvince(
            CommonQueryParam commonQueryParam) {
        
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        
        if (StringUtils.isNotEmpty(commonQueryParam.getProvince())) {
            boolQueryBuilder.must(QueryBuilders.termQuery("province", commonQueryParam.getProvince()));
        }
        //省數(shù)據(jù)內(nèi)容 排除city=0001
        if (StringUtils.isNotEmpty(commonQueryParam.getCity())) {
            if("0001".equals(commonQueryParam.getCity())){
                boolQueryBuilder.mustNot(QueryBuilders.termQuery("city", "0001"));
            }
        }
        
        boolQueryBuilder.mustNot(QueryBuilders.termQuery("content_id", "c0001"));
        boolQueryBuilder.mustNot(QueryBuilders.termQuery("content_name", "ignore"));
        boolQueryBuilder.mustNot(QueryBuilders.termQuery("level1_name", "ignore"));
        
        //排除掉-2異常數(shù)據(jù)
        boolQueryBuilder.mustNot(QueryBuilders.termQuery("flow", "-2"));
        boolQueryBuilder.mustNot(QueryBuilders.termQuery("flow_mobile", "-2"));
        boolQueryBuilder.mustNot(QueryBuilders.termQuery("flow_wifi", "-2"));
        boolQueryBuilder.mustNot(QueryBuilders.termQuery("avg_flow_mobile", "-2"));
        
        if (StringUtils.isNotEmpty(commonQueryParam.getStart()) && StringUtils.isNotEmpty(commonQueryParam.getEnd())) {
            RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery("dayid");
            rangeQuery.from(commonQueryParam.getEnd());
            rangeQuery.to(commonQueryParam.getEnd());
            boolQueryBuilder.must(rangeQuery);
        }
        
        SearchRequestBuilder searchRequestBuilder = esClient.getClient().prepareSearch(index)
                .setTypes(typeName).setSize(0)
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(boolQueryBuilder);
//order對別名為contentName的桶數(shù)據(jù)按照求和后的flow進行降序排序
//如果不對求和數(shù)據(jù)進行排序,僅針對桶排序流译,即僅對contentName排序逞怨,很簡單:將order的參數(shù)替換為Terms.Order.asc即可
        searchRequestBuilder.addAggregation(AggregationBuilders.terms("contentName").field("content_name").size(2147483647).order(Terms.Order.aggregation("flow", false))
                                .subAggregation(AggregationBuilders.sum("flow").field("flow"))
                                .subAggregation(AggregationBuilders.sum("flowMobile").field("flow_mobile"))
                                .subAggregation(AggregationBuilders.sum("flowWifi").field("flow_wifi"))
                                .subAggregation(AggregationBuilders.sum("avgFlowMobile").field("avg_flow_mobile"))
        );
         LOGGER.debug(searchRequestBuilder.toString());
         SearchResponse response = searchRequestBuilder.execute().actionGet();
         return response;
    }

以上因為使用了聚合,所以關(guān)閉的普通查詢的數(shù)據(jù)size先蒋,將其設(shè)置為0骇钦,相反的,打開聚合需要的數(shù)據(jù)size竞漾。
注意:一定要看清楚aggregation的層級眯搭,在了解到es桶特性之后,其實想要排序只能對桶進行排序业岁,一般情況下是對單個桶里面的數(shù)據(jù)進行排序鳞仙,多個桶也能排序,只需要將求和笔时,平均這些函數(shù)方法放到最后一個桶即可棍好,但是es支持不友好很有可能多個桶返回的數(shù)據(jù)并沒有按照預(yù)想的排序。
2.業(yè)務(wù)層獲取es數(shù)據(jù)進行業(yè)務(wù)開發(fā)

Aggregations firstAggs = response.getAggregations();
        if (null == firstAggs) {
            return null;
        }

        Terms contentNameTerms = firstAggs.get("contentName");
        for (Terms.Bucket contentNameBucket : contentNameTerms.getBuckets()) {
            number++;
            if(number >= 11){
                break;
            }
            String contentName = contentNameBucket.getKeyAsString();
                    
                    TableData td = new TableData();
                    td.setRank(String.valueOf(number));
                    td.setName(contentName);
                    td.setKind(this.queryLevel1NameByContentName(commonQueryParam,contentName));
                    Sum flow = contentNameBucket.getAggregations().get("flow");
                    td.setTotalFlow(String.format("%.0f", flow.getValue()));
                    Sum flowMobile = contentNameBucket.getAggregations().get("flowMobile");
                    td.setMobileFlow(String.format("%.0f", flowMobile.getValue()));
                    Sum flowWifi = contentNameBucket.getAggregations().get("flowWifi");
                    td.setWifiFlow(String.format("%.0f", flowWifi.getValue()));
                    Sum avgFlowMobile = contentNameBucket.getAggregations().get("avgFlowMobile");
                    td.setAvgFlow(String.format("%.2f", avgFlowMobile.getValue()*1024));
                    tableDataList.add(td);
                }
        return tableDataList;
    }

要清楚聚合返回數(shù)據(jù)的結(jié)構(gòu)要去了解es桶的原理允耿,簡單來說就是借笙,有多少tems就要for循環(huán)多少次,tems循環(huán)出來的就是桶(bucket),一個桶可以就是group by的數(shù)據(jù)较锡,通過這個桶可以拿到group by的字段名稱比如contentName,然后可以根據(jù)這個桶再去拿桶里面聚合好的數(shù)據(jù)比如contentNameBucket.getAggregations().get("flow");

普通查詢與聚合查詢的使用區(qū)別


1.普通查詢在javaApi里面只能用普通查詢的方式獲取值
2.聚合查詢在javaApi里面只能用聚合查詢方式獲取值
3.由于兩個的不相關(guān)性业稼,他們的size要分別設(shè)置,如果要求聚合蚂蕴,那么在普通查詢的size設(shè)置將失去意義低散,應(yīng)該設(shè)置普通查詢size參數(shù)為0,而在聚合查詢的size參數(shù)盡量設(shè)置大一些骡楼,比如.size(2147483647)熔号,聚合的size越大越能保證桶內(nèi)聚合的時候,sum(value)的數(shù)據(jù)盡量準確鸟整。

補充一個多字段聚合的例子說明多字段的層級關(guān)系

注意多少個group by就需要多少個terms引镊,最后一個terms里面才放sum等函數(shù)聚合,而不是sum聚合函數(shù)放到terms的任意層級篮条!

//設(shè)置用戶運營指標聚合
    private void setMemberServiceAgg(SearchRequestBuilder searchRequestBuilder) {
        searchRequestBuilder.addAggregation(AggregationBuilders.terms("dayid").field("dayid").size(2147483647)
                .subAggregation(AggregationBuilders.terms("provinceName").field("province_name").size(2147483647)
                        .subAggregation(AggregationBuilders.terms("cityName").field("city_name").size(2147483647).order(Terms.Order.term(true))
                                .subAggregation(AggregationBuilders.sum("sumNewPayMember").field("new_pay_member"))
                                .subAggregation(AggregationBuilders.sum("sumCancelMember").field("cancel_member"))
                                .subAggregation(AggregationBuilders.sum("sumMembers").field("members"))
                                .subAggregation(AggregationBuilders.sum("sumMemberActive").field("member_active"))
                        )
                )
        );
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弟头,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子兑燥,更是在濱河造成了極大的恐慌,老刑警劉巖琴拧,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件降瞳,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機挣饥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門除师,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人扔枫,你說我怎么就攤上這事汛聚。” “怎么了短荐?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵倚舀,是天一觀的道長。 經(jīng)常有香客問我忍宋,道長痕貌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任糠排,我火速辦了婚禮舵稠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘入宦。我一直安慰自己哺徊,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布乾闰。 她就那樣靜靜地躺著落追,像睡著了一般。 火紅的嫁衣襯著肌膚如雪汹忠。 梳的紋絲不亂的頭發(fā)上淋硝,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音宽菜,去河邊找鬼谣膳。 笑死,一個胖子當(dāng)著我的面吹牛铅乡,可吹牛的內(nèi)容都是我干的继谚。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼阵幸,長吁一口氣:“原來是場噩夢啊……” “哼花履!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起挚赊,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤诡壁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后荠割,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妹卿,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡旺矾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了夺克。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箕宙。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖铺纽,靈堂內(nèi)的尸體忽然破棺而出柬帕,到底是詐尸還是另有隱情,我是刑警寧澤狡门,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布陷寝,位于F島的核電站,受9級特大地震影響融撞,放射性物質(zhì)發(fā)生泄漏盼铁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一尝偎、第九天 我趴在偏房一處隱蔽的房頂上張望饶火。 院中可真熱鬧,春花似錦致扯、人聲如沸肤寝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鲤看。三九已至,卻和暖如春耍群,著一層夾襖步出監(jiān)牢的瞬間义桂,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工蹈垢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留慷吊,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓曹抬,卻偏偏與公主長得像溉瓶,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子谤民,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,465評論 2 348