springboot 集成 Elasticsearch

一、SpringBoot模版方式接入(不建議)

其實(shí)一開始是準(zhǔn)備用SpringBoot的模版來(lái)直接接入使用的,也就是以下這樣的接入方式,也是網(wǎng)上大家都這么說(shuō)的使用方式。

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
  </dependency>

但是后面看java api的官方文檔

Deprecated in 7.0.0.

The TransportClient is deprecated in favour of the Java High Level REST Client and will be removed in Elasticsearch 8.0. The migration guide describes all the steps needed to migrate.
<meta charset="utf-8">

再看看模版方式引入的源碼

SpringBoot模版方式引入

直接模版方式的java api調(diào)用方式钞脂,后續(xù)官方會(huì)不支持了,不建議使用捕儒,要使用Java High Level REST Client來(lái)代替冰啃,Elasticsearch 8.0版本后直接移除,想想還是換人家建議的使用方式吧刘莹,免得以后更新?lián)Q代還得做遷移阎毅,也就是我們現(xiàn)在準(zhǔn)備的使用方式。

二点弯、High Level Java REST Client方式接入

使用High Level Java REST Client進(jìn)行Elasticsearch檢索查詢扇调,第一步添加依賴

  • org.elasticsearch.client:elasticsearch-rest-client
  • org.elasticsearch:elasticsearch

2.1、添加依賴

在SpringBoot中的具體添加方式是在pom.xml中:

        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>6.3.2</version>
        </dependency>

        <!-- Java High Level REST Client -->
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>6.3.2</version>
        </dependency>

2.2抢肛、添加配置地址

添加依賴之后即可進(jìn)行初始化

RestHighLevelClient client = new RestHighLevelClient(
        RestClient.builder(
                new HttpHost("localhost", 9200, "http")));

這個(gè) client的內(nèi)部會(huì)維護(hù)一個(gè)線程池狼钮,所以在任務(wù)完成后可以通過(guò) client.close()來(lái)釋放資源碳柱,但是這得看需求,如果需要頻繁進(jìn)行查詢的話熬芜,就直接做成單例莲镣,避免線程池的不斷創(chuàng)建和釋放也會(huì)影響應(yīng)用的性能,在SpringBoot的做法做成單例的話更簡(jiǎn)單涎拉。
application.yml配置文件中添加集群地址瑞侮,我這邊只有一個(gè),有多個(gè)的可以用逗號(hào)分割然后自己解析鼓拧。

elasticsearch:
  ip: localhost:9200
@Configuration
public class ElasticsearchRestClient {

    /**
     * ES地址,ip:port
     */
    @Value("${elasticsearch.ip}")
    String ipPort;

    @Bean
    public RestClientBuilder restClientBuilder() {

        return RestClient.builder(makeHttpHost(ipPort));
    }


    @Bean(name = "highLevelClient")
    public RestHighLevelClient highLevelClient(@Autowired RestClientBuilder restClientBuilder) {
        restClientBuilder.setMaxRetryTimeoutMillis(60000);
        return new RestHighLevelClient(restClientBuilder);
    }


    private HttpHost makeHttpHost(String s) {
        String[] address = s.split(":");
        String ip = address[0];
        int port = Integer.parseInt(address[1]);
        
        return new HttpHost(ip, port, "http");
    }
}

我們這邊只有一個(gè)地址半火,如果有多個(gè)地址,自己做下處理即可季俩。

三钮糖、Elasticsearch檢索查詢

經(jīng)過(guò)上一步驟之后就可以在項(xiàng)目中使用client來(lái)進(jìn)行具體的檢索及查詢操作了,具體使用之前先清楚幾個(gè)概念种玛。

3.1 Elasticsearch數(shù)據(jù)結(jié)構(gòu)

在我們這邊的使用場(chǎng)景中藐鹤,Elasticsearch是用來(lái)存儲(chǔ)各個(gè)端的日志瓤檐,在這種場(chǎng)景下赂韵,每一條日志就是一個(gè)Document(文檔),我們知道日志中包含了很多信息挠蛉,比如上傳時(shí)間祭示,瀏覽器,ip等等谴古,每條日志中包含多個(gè)字段信息就是Field(字段)质涛,不同的日志可能有不同的類型,比如服務(wù)器日志掰担,用戶行為日志汇陆,這就是Type(類型),每天的日志分開進(jìn)行存儲(chǔ)是Indice(索引)带饱,可以類比于關(guān)系型數(shù)據(jù)庫(kù)比如MySQL毡代。

關(guān)系型數(shù)據(jù)庫(kù) Elasticsearch
Databases(數(shù)據(jù)庫(kù)) Indices(索引)
Tables(表) Types(類型)
Rows(行) Documents(文檔)
Columns(列) Fields(字段)

Elasticsearch包含多個(gè)索引(indices)(數(shù)據(jù)庫(kù)),每個(gè)索引可以包含多個(gè)類型(types)(表)勺疼,每個(gè)類型包含多個(gè)文檔(documents)(行)教寂,每個(gè)文檔包含多個(gè)字段(Fields)(列)。

舉個(gè)栗子执庐,手動(dòng)添加一條日志酪耕,指定indice為customer,type為_doc轨淌,document的id為1迂烁。

localhost:9200/customer/_doc/1?pretty

然后再查詢一下剛添加的日志看尼。

GET localhost:9200/customer/_doc/1?pretty
{
    "_index": "customer",
    "_type": "_doc",
    "_id": "1",
    "_version": 3,
    "_seq_no": 2,
    "_primary_term": 1,
    "found": true,
    "_source": {
        "city": "北京",
        "useragent": "Mobile Safari",
        "sys_version": "Linux armv8l",
        "province": "北京",
        "event_id": "",
        "log_time": 1559191912,
        "session": "343730"
    }
}

另外,我們所有的數(shù)據(jù)要有一個(gè)順序的盟步,直接用postman狡忙,請(qǐng)求你的es地址put一個(gè)語(yǔ)句


postMan
PUT chat_info_msg/_mapping/chatinfomsg

{
  "properties": {
    "timestamp": { 
      "type":     "text",
      "fielddata": true
    }
  }
}

3.2 Elasticsearch條件查詢

第一步需要初始化SearchRequest,設(shè)置索引(indices)和類型(types)址芯,以上面添加的日志為例灾茁。

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices("customer");
        searchRequest.types("_doc");

然后需要組合查詢條件,主要涉及到=谷炸、!=北专、><這幾個(gè)條件的查詢旬陡,需要更復(fù)雜的可以查看官方文檔拓颓。

// 條件=
MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("city", "北京");
TermQueryBuilder termQuery = QueryBuilders.termQuery("province", "福建");

// 范圍查詢
RangeQueryBuilder timeFilter = QueryBuilders.rangeQuery("log_time").gt(12345).lt(343750);

構(gòu)建好需要的查詢條件后,需要進(jìn)行組合查詢描孟,在組合查詢里頭實(shí)現(xiàn)!=條件查詢驶睦,需要用到BoolQueryBuilderBoolQueryBuilder包含4個(gè)方法:

  • must 相當(dāng)于 &(與)條件匿醒。
  • must not 相當(dāng)于~(非)條件场航。
  • should 相當(dāng)于 | (或)條件。
  • filter 類似must廉羔,區(qū)別在于它不參與計(jì)算分值溉痢,在不需要用到分值計(jì)算的時(shí)候效率更高。
QueryBuilder totalFilter = QueryBuilders.boolQuery()
                .filter(matchQuery)
                .filter(timeFilter)
                .mustNot(termQuery);

3.3 Elasticsearch分頁(yè)查詢

可以設(shè)置每次查詢返回的文檔數(shù)量憋他,如果不設(shè)置的話孩饼,默認(rèn)只返回10條hits,這個(gè)數(shù)量可以手動(dòng)設(shè)置:

sourceBuilder.query(totalFilter).size(100);

單單設(shè)置返回條數(shù)還不滿足需求竹挡,因?yàn)槲覀冞@邊是沒有辦法事先確定的镀娶,所以需要自己來(lái)實(shí)現(xiàn)分頁(yè),需要from()方法進(jìn)行輔助揪罕。

完整示例代碼如下:

@Service
    public class TestService {
        @Autowired
        RestHighLevelClient highLevelClient;

        private void search(RestHighLevelClient highLevelClient) throws IOException {

            SearchRequest searchRequest = new SearchRequest();
            searchRequest.indices("customer");
            searchRequest.types("_doc");

            // 條件=
            MatchQueryBuilder matchQuery = QueryBuilders.matchQuery("city", "北京");
            TermQueryBuilder termQuery = QueryBuilders.termQuery("province", "福建");
            // 范圍查詢
            RangeQueryBuilder timeFilter = QueryBuilders.rangeQuery("log_time").gt(12345).lt(343750);
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

            QueryBuilder totalFilter = QueryBuilders.boolQuery()
                    .filter(matchQuery)
                    .filter(timeFilter)
                    .mustNot(termQuery);

            int size = 200;
            int from = 0;
            long total = 0;

            do {
                try {
                    sourceBuilder.query(totalFilter).from(from).size(size);
                    sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
                    searchRequest.source(sourceBuilder);

                    SearchResponse response = highLevelClient.search(searchRequest);
                    SearchHit[] hits = response.getHits().getHits();
                    for (SearchHit hit : hits) {
                        System.out.println(hit.getSourceAsString());
                    }

                    total = response.getHits().totalHits;

                    System.out.println("測(cè)試:[" + total + "][" + from + "-" + (from + hits.length) + ")");

                    from += hits.length;

                    // from + size must be less than or equal to: [10000]
                    if (from >= 10000) {
                      System.out.println("測(cè)試:超過(guò)10000條直接中斷");
                      break;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } while (from < total);
        }
    }

3.4 分頁(yè)查詢異常

在分頁(yè)的過(guò)程中出現(xiàn)了一個(gè)問(wèn)題是當(dāng)查詢的數(shù)據(jù)超過(guò)10000條的時(shí)候報(bào)了異常:

from + size must be less than or equal to: [10000]

這個(gè)問(wèn)題最快捷的解決方式是增大窗口大小:

curl -XPUT http://127.0.0.1:9200/customer/_settings -d '{ "index" : { "max_result_window" : 500000}}'

但是對(duì)應(yīng)增大窗口大小梯码,會(huì)犧牲更多的服務(wù)器的內(nèi)存、CPU資源耸序,在我們這邊的使用場(chǎng)景下忍些,這樣做是劃不來(lái)的,因?yàn)槲覀兊哪康氖亲瞿繕?biāo)數(shù)據(jù)的搜索坎怪,而不是大規(guī)模的遍歷罢坝,所以我們這邊會(huì)直接放棄超過(guò)這個(gè)數(shù)量的查詢,也就是上面的這段代碼:

 // from + size must be less than or equal to: [10000]
  if (from > 10000) {
     System.out.println("測(cè)試:超過(guò)10000條直接中斷");
     break;
  }

對(duì)于Elasticsearch其實(shí)也是很多地方還不熟悉,感興趣的童鞋可以多多一起交流和指正嘁酿,不然的話后續(xù)也只能在使用過(guò)程中來(lái)加深理解隙券。

參考:
1、Elasticsearch: 權(quán)威指南
2闹司、Elasticsearch: Java API [7.1]
3娱仔、Elasticsearch: Java REST Client [7.1]
4、Elasticsearch查詢——布爾查詢Bool Query
5游桩、解決ElasticSearch深度分頁(yè)機(jī)制中Result window is too large問(wèn)題

轉(zhuǎn)自鏈:http://www.reibang.com/p/de838a665eec

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末牲迫,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子借卧,更是在濱河造成了極大的恐慌盹憎,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铐刘,死亡現(xiàn)場(chǎng)離奇詭異陪每,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)镰吵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門檩禾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人疤祭,你說(shuō)我怎么就攤上這事盼产。” “怎么了画株?”我有些...
    開封第一講書人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵辆飘,是天一觀的道長(zhǎng)啦辐。 經(jīng)常有香客問(wèn)我谓传,道長(zhǎng),這世上最難降的妖魔是什么芹关? 我笑而不...
    開封第一講書人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任续挟,我火速辦了婚禮,結(jié)果婚禮上侥衬,老公的妹妹穿的比我還像新娘诗祸。我一直安慰自己,他們只是感情好轴总,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開白布直颅。 她就那樣靜靜地躺著,像睡著了一般怀樟。 火紅的嫁衣襯著肌膚如雪功偿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,488評(píng)論 1 302
  • 那天往堡,我揣著相機(jī)與錄音械荷,去河邊找鬼共耍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛吨瞎,可吹牛的內(nèi)容都是我干的痹兜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼颤诀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼字旭!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起崖叫,我...
    開封第一講書人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤谐算,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后归露,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體洲脂,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年剧包,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恐锦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡疆液,死狀恐怖一铅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情堕油,我是刑警寧澤潘飘,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站掉缺,受9級(jí)特大地震影響卜录,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜眶明,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一艰毒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧搜囱,春花似錦丑瞧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至扮宠,卻和暖如春西乖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工浴栽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荒叼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓典鸡,卻偏偏與公主長(zhǎng)得像被廓,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子萝玷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

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