Spring Boot 集成 Elasticsearch 實(shí)戰(zhàn)
Spring Boot 集成 ES
加入 ES 依賴 配置 ES 演示 ES 基本操作
加入依賴
????org.elasticsearch
????elasticsearch
????7.1.0
????org.elasticsearch.client
????elasticsearch-rest-high-level-client
????7.1.0
創(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
ElasticsearchConfiguration 類,會(huì)從配置文件中讀取到對(duì)應(yīng)的參數(shù),接著申明一個(gè) initRestClient 方法,返回的是一個(gè) RestHighLevelClient,同時(shí)為它添加 @Bean(destroyMethod = "close") 注解,當(dāng) destroy 的時(shí)候做一個(gè)關(guān)閉,這個(gè)方法主要是如何初始化并創(chuàng)建一個(gè) 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);
????}
}
定義文檔實(shí)體類
constant 包下定義常量接口,在接口中定義索引的名字為 user:public?interface?Constant?{
????String?INDEX?=?"user";
}
document 包下創(chuàng)建一個(gè)文檔實(shí)體類:public?class?UserDocument?{
????private?String?id;
????private?String?name;
????private?String?sex;
????private?Integer?age;
????private?String?city;
????//?省略?getter/setter
}
ES 基本操作
service 包下創(chuàng)建 UserService 類。索引操作
創(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();
}
user,索引信息如下:
刪除索引
DeleteIndexRequest 中傳入索引名稱就可以刪除索引,具體代碼如下所示:public?Boolean?deleteUserIndex(String?index)?throws?IOException?{
????DeleteIndexRequest?deleteIndexRequest?=?new?DeleteIndexRequest(index);
????AcknowledgedResponse?deleteIndexResponse?=?client.indices().delete(deleteIndexRequest,?RequestOptions.DEFAULT);
????return?deleteIndexResponse.isAcknowledged();
}
文檔操作
創(chuàng)建文檔
IndexRequest 中指定索引名稱,id 如果不傳的話會(huì)由 ES 自動(dòng)生成,然后傳入 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);
}

批量創(chuàng)建文檔
BulkRequest 里可以添加多個(gè) Request,具體代碼如下:public?Boolean?bulkCreateUserDocument(List
?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);
}
查看文檔
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("沒(méi)有找到該?id?的文檔");
????}
????return?result;
}

更新文檔
UpdateRequest 傳入索引名稱和文檔 id,然后通過(guò)傳入新的 doc 來(lái)進(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);
}
9b8d9897-3352-4ef3-9636-afc6fce43b20 的文檔的城市信息改為 handan,調(diào)用方法結(jié)果如下:
刪除文檔
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();
}
搜索操作
SearchRequest 中設(shè)置將要搜索的索引名稱(可以設(shè)置多個(gè)索引名稱),然后通過(guò) SearchSourceBuilder 構(gòu)造搜索源,下面將 TermQueryBuilder 搜索查詢傳給 searchSourceBuilder,最后將 searchRequest 的搜索源設(shè)置為 searchSourceBuilder,執(zhí)行 search 方法實(shí)現(xiàn)通過(guò)城市進(jìn)行搜索,具體代碼如下所示:public?List
?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);
}

聚合搜索
searchSourceBuilder 添加聚合搜索,下面方法是通過(guò) TermsAggregationBuilder 構(gòu)造一個(gè)先通過(guò)城市就行分類聚合,其中還包括一個(gè)子聚合,是對(duì)年齡求平均值,然后在獲取聚合結(jié)果的時(shí)候,可以使用通過(guò)在構(gòu)建聚合時(shí)的聚合名稱獲取到聚合結(jié)果,具體代碼如下所示:public?List
?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?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;
}

總結(jié)
https://github.com/wupeixuan/SpringBoot-Learn 的 elasticsearch 目錄下。有道無(wú)術(shù),術(shù)可成;有術(shù)無(wú)道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號(hào)
好文章,我在看??
