Spring Boot 集成 ElasticSearch應(yīng)用小結(jié)
1 加入依賴
首先創(chuàng)建一個項目,在項目中加入 ES 相關(guān)依賴,具體依賴如下所示:
<dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.1.0</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.1.0</version> </dependency>
2 創(chuàng)建 ES 配置
在配置文件 application.properties 中配置 ES 的相關(guān)參數(shù),具體內(nèi)容如下:
elasticsearch.host=localhost elasticsearch.port=9200 elasticsearch.connTimeout=3000 elasticsearch.socketTimeout=5000 elasticsearch.connectionRequestTimeout=500
其中指定了 ES 的 host 和端口以及超時時間的設(shè)置,另外我們的 ES 沒有添加任何的安全認(rèn)證,因此 username 和 password 就沒有設(shè)置。
然后在 config 包下創(chuàng)建 ElasticsearchConfiguration 類,會從配置文件中讀取到對應(yīng)的參數(shù),接著申明一個 initRestClient 方法,返回的是一個 RestHighLevelClient,同時為它添加 @Bean(destroyMethod = “close”) 注解,當(dāng) destroy 的時候做一個關(guān)閉,這個方法主要是如何初始化并創(chuàng)建一個 RestHighLevelClient。
@Configuration public class ElasticsearchConfiguration { @Value("${elasticsearch.host}") private String host; @Value("${elasticsearch.port}") private int port; @Value("${elasticsearch.connTimeout}") private int connTimeout; @Value("${elasticsearch.socketTimeout}") private int socketTimeout; @Value("${elasticsearch.connectionRequestTimeout}") private int connectionRequestTimeout; @Bean(destroyMethod = "close", name = "client") public RestHighLevelClient initRestClient() { RestClientBuilder builder = RestClient.builder(new HttpHost(host, port)) .setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder .setConnectTimeout(connTimeout) .setSocketTimeout(socketTimeout) .setConnectionRequestTimeout(connectionRequestTimeout)); return new RestHighLevelClient(builder); } }
3 定義文檔實體類
首先在 constant 包下定義常量接口,在接口中定義索引的名字為 user:
public interface Constant { String INDEX = "user"; }
然后在 document 包下創(chuàng)建一個文檔實體類:
public class UserDocument { private String id; private String name; private String sex; private Integer age; private String city; // 省略 getter/setter }
4 ES 基本操作
在這里主要介紹 ES 的索引、文檔、搜索相關(guān)的簡單操作,在 service 包下創(chuàng)建 UserService 類。
4.1 索引操作
在創(chuàng)建索引的時候可以在 CreateIndexRequest 中設(shè)置索引名稱、分片數(shù)、副本數(shù)以及 mappings,在這里索引名稱為 user,分片數(shù) number_of_shards 為 1,副本數(shù) number_of_replicas 為 0,具體代碼如下所示:
public boolean createUserIndex(String index) throws IOException { CreateIndexRequest createIndexRequest = new CreateIndexRequest(index); createIndexRequest.settings(Settings.builder() .put("index.number_of_shards", 1) .put("index.number_of_replicas", 0) ); createIndexRequest.mapping("{\n" + " \"properties\": {\n" + " \"city\": {\n" + " \"type\": \"keyword\"\n" + " },\n" + " \"sex\": {\n" + " \"type\": \"keyword\"\n" + " },\n" + " \"name\": {\n" + " \"type\": \"keyword\"\n" + " },\n" + " \"id\": {\n" + " \"type\": \"keyword\"\n" + " },\n" + " \"age\": {\n" + " \"type\": \"integer\"\n" + " }\n" + " }\n" + "}", XContentType.JSON); CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT); return createIndexResponse.isAcknowledged(); }
通過調(diào)用該方法,就可以創(chuàng)建一個索引 user,索引信息如下:
關(guān)于 ES 的 Mapping會專門出一篇文章進(jìn)行講解
4.2 刪除索引
在 DeleteIndexRequest 中傳入索引名稱就可以刪除索引,具體代碼如下所示:
public Boolean deleteUserIndex(String index) throws IOException { DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index); AcknowledgedResponse deleteIndexResponse = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT); return deleteIndexResponse.isAcknowledged(); }
介紹完索引的基本操作,下面介紹文檔的相關(guān)操作:
4.3 文檔操作
在這里演示下創(chuàng)建文檔、批量創(chuàng)建文檔、查看文檔、更新文檔以及刪除文檔:
4.3.1 創(chuàng)建文檔
創(chuàng)建文檔的時候需要在 IndexRequest 中指定索引名稱,id 如果不傳的話會由 ES 自動生成,然后傳入 source,具體代碼如下:
public Boolean createUserDocument(UserDocument document) throws Exception { UUID uuid = UUID.randomUUID(); document.setId(uuid.toString()); IndexRequest indexRequest = new IndexRequest(Constant.INDEX) .id(document.getId()) .source(JSON.toJSONString(document), XContentType.JSON); IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT); return indexResponse.status().equals(RestStatus.OK); }
下面通過調(diào)用這個方法,創(chuàng)建兩個文檔,具體內(nèi)容如下:
4.3.2 批量創(chuàng)建文檔
在一個 REST 請求中,重新建立網(wǎng)絡(luò)開銷是十分損耗性能的,因此 ES 提供 Bulk API,支持在一次 API 調(diào)用中,對不同的索引進(jìn)行操作,從而減少網(wǎng)絡(luò)傳輸開銷,提升寫入速率。
下面方法是批量創(chuàng)建文檔,一個 BulkRequest 里可以添加多個 Request,具體代碼如下:
public Boolean bulkCreateUserDocument(List<UserDocument> documents) throws IOException { BulkRequest bulkRequest = new BulkRequest(); for (UserDocument document : documents) { String id = UUID.randomUUID().toString(); document.setId(id); IndexRequest indexRequest = new IndexRequest(Constant.INDEX) .id(id) .source(JSON.toJSONString(document), XContentType.JSON); bulkRequest.add(indexRequest); } BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT); return bulkResponse.status().equals(RestStatus.OK); }
下面通過該方法創(chuàng)建些文檔,便于下面的搜索演示。
4.3.3 查看文檔
查看文檔需要在 GetRequest 中傳入索引名稱和文檔 id,具體代碼如下所示:
public UserDocument getUserDocument(String id) throws IOException { GetRequest getRequest = new GetRequest(Constant.INDEX, id); GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT); UserDocument result = new UserDocument(); if (getResponse.isExists()) { String sourceAsString = getResponse.getSourceAsString(); result = JSON.parseObject(sourceAsString, UserDocument.class); } else { logger.error("沒有找到該 id 的文檔"); } return result; }
下面?zhèn)魅胛臋n id 調(diào)用該方法,結(jié)果如下所示:
4.3.4 更新文檔
更新文檔則是先給 UpdateRequest 傳入索引名稱和文檔 id,然后通過傳入新的 doc 來進(jìn)行更新,具體代碼如下:
public Boolean updateUserDocument(UserDocument document) throws Exception { UserDocument resultDocument = getUserDocument(document.getId()); UpdateRequest updateRequest = new UpdateRequest(Constant.INDEX, resultDocument.getId()); updateRequest.doc(JSON.toJSONString(document), XContentType.JSON); UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT); return updateResponse.status().equals(RestStatus.OK); }
下面將文檔 id 為 9b8d9897-3352-4ef3-9636-afc6fce43b20 的文檔的城市信息改為 handan,調(diào)用方法結(jié)果如下:
4.3.5 刪除文檔
刪除文檔只需要在 DeleteRequest 中傳入索引名稱和文檔 id,然后執(zhí)行 delete 方法就可以完成文檔的刪除,具體代碼如下:
public String deleteUserDocument(String id) throws Exception { DeleteRequest deleteRequest = new DeleteRequest(Constant.INDEX, id); DeleteResponse response = client.delete(deleteRequest, RequestOptions.DEFAULT); return response.getResult().name(); }
介紹完文檔的基本操作,接下來對搜索進(jìn)行簡單介紹:
4.4 搜索操作
簡單的搜索操作需要在 SearchRequest 中設(shè)置將要搜索的索引名稱(可以設(shè)置多個索引名稱),然后通過 SearchSourceBuilder 構(gòu)造搜索源,下面將 TermQueryBuilder 搜索查詢傳給 searchSourceBuilder,最后將 searchRequest 的搜索源設(shè)置為 searchSourceBuilder,執(zhí)行 search 方法實現(xiàn)通過城市進(jìn)行搜索,具體代碼如下所示:
public List<UserDocument> searchUserByCity(String city) throws Exception { SearchRequest searchRequest = new SearchRequest(); searchRequest.indices(Constant.INDEX); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("city", city); searchSourceBuilder.query(termQueryBuilder); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); return getSearchResult(searchResponse); }
4.4.1 聚合搜索
聚合搜索就是給 searchSourceBuilder 添加聚合搜索,下面方法是通過 TermsAggregationBuilder 構(gòu)造一個先通過城市就行分類聚合,其中還包括一個子聚合,是對年齡求平均值,然后在獲取聚合結(jié)果的時候,可以使用通過在構(gòu)建聚合時的聚合名稱獲取到聚合結(jié)果,具體代碼如下所示:
public List<UserCityDTO> aggregationsSearchUser() throws Exception { SearchRequest searchRequest = new SearchRequest(Constant.INDEX); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); TermsAggregationBuilder aggregation = AggregationBuilders.terms("by_city") .field("city") .subAggregation(AggregationBuilders .avg("average_age") .field("age")); searchSourceBuilder.aggregation(aggregation); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); Aggregations aggregations = searchResponse.getAggregations(); Terms byCityAggregation = aggregations.get("by_city"); List<UserCityDTO> userCityList = new ArrayList<>(); for (Terms.Bucket buck : byCityAggregation.getBuckets()) { UserCityDTO userCityDTO = new UserCityDTO(); userCityDTO.setCity(buck.getKeyAsString()); userCityDTO.setCount(buck.getDocCount()); // 獲取子聚合 Avg averageBalance = buck.getAggregations().get("average_age"); userCityDTO.setAvgAge(averageBalance.getValue()); userCityList.add(userCityDTO); } return userCityList; }
下面是執(zhí)行該方法的結(jié)果:
到此為止,ES 的基本操作就簡單介紹完了,大家可以多動手試試,不會的可以看下官方文檔。
5 總結(jié)
本文的完整代碼在https://github.com/363153421/springboot-elasticsearch下。
Spring Boot 結(jié)合 ES 還是比較簡單的,大家可以下載項目源碼,自己在本地運行調(diào)試這個項目,更好地理解如何在 Spring Boot 中構(gòu)建基于 ES 的應(yīng)用。
到此這篇關(guān)于Spring Boot 集成 ElasticSearch的文章就介紹到這了,更多相關(guān)Spring Boot 集成 ElasticSearch內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java 線程池的實現(xiàn)原理、優(yōu)點與風(fēng)險、以及4種線程池實現(xiàn)
這篇文章主要介紹了java 線程池的實現(xiàn)原理、優(yōu)點與風(fēng)險、以及4種線程池實現(xiàn)包括了:配置線程池大小配置,線程池的實現(xiàn)原理等,需要的朋友可以參考下2023-02-02Mybatis批量插入數(shù)據(jù)返回主鍵的實現(xiàn)
這篇文章主要介紹了Mybatis批量插入數(shù)據(jù)返回主鍵的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01Java日常練習(xí)題,每天進(jìn)步一點點(24)
下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望可以幫到你2021-07-07Java中的FutureTask實現(xiàn)異步任務(wù)代碼實例
這篇文章主要介紹了Java中的FutureTask實現(xiàn)異步任務(wù)代碼實例,普通的線程執(zhí)行是無法獲取到執(zhí)行結(jié)果的,FutureTask?間接實現(xiàn)了?Runnable?和?Future?接口,可以得到子線程耗時操作的執(zhí)行結(jié)果,AsyncTask?異步任務(wù)就是使用了該機(jī)制,需要的朋友可以參考下2024-01-01Spring整合Mybatis 掃描注解創(chuàng)建Bean報錯的解決方案
這篇文章主要介紹了Spring 整合Mybatis 掃描注解創(chuàng)建Bean報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10