Springboot整合Elasticsearch(查詢資料的方式)
阿新 • • 發佈:2022-05-20
參考文件地址:
Elasticsearch 官方文件地址:點選連結
Spring Data Elasticsearch 官方文件地址:點選連結
新增maven依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>
1.初始化Elasticsearch
- 在yml配置檔案中配置es的連線引數(略)
- 新建一個config類,配置es(如下)
@Configuration public class ElasticsearchConfig { @Bean public RestHighLevelClient restHighLevelClient() { // 這個是springboot的文件推薦寫法 // ClientConfiguration clientConfiguration = ClientConfiguration.builder() // .connectedTo("192.168.203.129:9200").build();// // return RestClients.create(clientConfiguration).rest(); // es官方文件推薦寫法 RestHighLevelClient client = new RestHighLevelClient( RestClient.builder( new HttpHost("192.168.203.129", 9200, "http"))); return client; } }
2.簡單查詢
Spring Data Elasticsearch提供了一個ElasticsearchRepository介面,可以很方便的自定義簡單的查詢方法。
public interface MyRepository extends ElasticsearchRepository<User, Long> { /** * 根據id或者年齡或者名字查詢 * @param id * @param age * @param name * @return */ User findByIdOrAgeOrName(Long id, Integer age, String name); /** * 刪除年齡大於或等於給定值的資料 * @param age */ void deleteByAgeGreaterThanEqual(Integer age); /** * 搜尋指定年齡段的user * @param start 開始年齡 * @param end 結束年齡 * @return */ User findAllByAgeBetween(int start,int end); }
這裡要注意,自定義方法的名字是有規則的,idea會自動提示,根據提示,以及自己想要的操作,書寫方法名和對應引數即可。在Spring Data Elasticsearch的文件裡也有相關說明:
1.1測試程式碼
@Autowired private MyRepository myRepository; // 查詢年齡為27歲的使用者資料 @Test void myTest6() { User rico = myRepository.findByIdOrAgeOrName(null, 27, null); System.out.println(rico); } // 插入一條user資料 @Test void myTest7() throws IOException { User user = User.builder() .name("rico3") .age(35) .id(3L) .birthday(new Date()) .build(); User save = myRepository.save(user); System.out.println(save); restHighLevelClient.close(); } // 刪除年齡大於或等於29歲的使用者的資料 @Test void myTest8() throws IOException { myRepository.deleteByAgeGreaterThanEqual(29); restHighLevelClient.close(); }
3.複雜查詢
3.1使用ElasticsearchRestTemplate
先看測試程式碼
@Autowired private ElasticsearchRestTemplate elasticsearchRestTemplate; // 使用elasticsearchRestTemplate來查詢資料 @Test void myTest9() { // 建立一個query,QueryBuilders下可以選擇查詢方式 NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(QueryBuilders.matchAllQuery()); SearchHits<User> search = elasticsearchRestTemplate.search(nativeSearchQuery, User.class); for (org.springframework.data.elasticsearch.core.SearchHit<User> userSearchHit : search) { User content = userSearchHit.getContent(); System.out.println(content); } } @Test void myTest11() { NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder(); builder.withQuery(QueryBuilders.matchAllQuery()); // 搜尋age大於27的user資料,這裡的寫法其實和json查詢語句的寫法一樣的,如下 /* GET /bank/_search { "query": { "bool": { "must": { "match_all": {} }, "filter": { "range": { "balance": { "gte": 20000, "lte": 30000 } } } } } } */ builder.withQuery(QueryBuilders.boolQuery() .must(QueryBuilders.matchAllQuery()) .filter(QueryBuilders.rangeQuery("age").gte(27))); NativeSearchQuery query = builder.build(); SearchHits<User> searchHits = elasticsearchRestTemplate.search(query, User.class); for (org.springframework.data.elasticsearch.core.SearchHit<User> searchHit : searchHits) { System.out.println(searchHit.getContent()); } } // 查詢年齡大於10歲的使用者的數量 @Test public void myTest14() { NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder(); builder.addAggregation(AggregationBuilders .filter("age_gt_10", QueryBuilders.rangeQuery("age").gt(10)) .subAggregation(AggregationBuilders.count("group_by_count").field("name"))); NativeSearchQuery searchQuery = builder.build(); SearchHits<User> search = elasticsearchRestTemplate.search(searchQuery, User.class); Filter age_gt_10 = search.getAggregations().get("age_gt_10"); Aggregations aggregations = age_gt_10.getAggregations(); ValueCount count = aggregations.get("group_by_count"); System.out.println(count.getValue()); }
ElasticsearchRestTemplate適合做一些複雜的搜尋操作,比如聚合搜尋等。需要注意的是,ElasticsearchRestTemplate查詢返回的結果需要傳入我們的資料實體類User.class
。
@Data @Document(indexName = "users") // 將此類標記為Document,索引是users,對應es裡的資料 @Builder public class User { @Id private Long id; @Field(type = FieldType.Keyword) private String name; @Field(type = FieldType.Long) private Integer age; @Field(type = FieldType.Date,format= DateFormat.basic_date) private Date birthday; }
還有一個需要注意:在上面的程式碼myTest14函式中,builder的寫法需要基本是和es的json查詢語句一樣的,如下:
輸出結果是:
3.2使用RestHighLevelClient
@Autowired private RestHighLevelClient restHighLevelClient; @Test void myTest() throws IOException { // 建立一個索引,並設定了id為1的文件資料 IndexRequest request = new IndexRequest("spring-data3") .id("1") .opType(DocWriteRequest.OpType.CREATE) .source("name", "rico2") .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE); IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT); System.out.println(response.toString()); restHighLevelClient.close(); // 獲取文件內容 @Test void myTest4() throws IOException { GetRequest getRequest = new GetRequest("users", "1"); boolean exists = restHighLevelClient.indices().exists(new GetIndexRequest(getRequest.index()), RequestOptions.DEFAULT); if (exists) { GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT); System.out.println(getResponse.getSourceAsString()); } else { System.out.println("索引不存在!"); } restHighLevelClient.close(); } // 搜尋index為users下的所有文件 @Test void myTest5() throws IOException { SearchRequest searchRequest = new SearchRequest("users"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchAllQuery()); searchRequest.source(searchSourceBuilder); SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); SearchHit[] hits = search.getHits().getHits(); for (SearchHit hit : hits) { System.out.println(hit.getSourceAsString()); System.out.println("================================="); } } // 查詢users下所有使用者的年齡平均值 @Test public void myTest12() throws IOException { SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); AvgAggregationBuilder avgAggregationBuilder = AggregationBuilders.avg("average_age").field("age"); searchSourceBuilder.aggregation(avgAggregationBuilder); SearchRequest request = new SearchRequest("users"); request.source(searchSourceBuilder); SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); Aggregations aggregations = response.getAggregations(); Avg average_age = aggregations.get("average_age"); System.out.println(average_age.getValue()); } // 查詢年齡大於10歲的使用者的數量,使用restHighLevelClient @Test public void myTest13() throws IOException { SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); FilterAggregationBuilder filter = AggregationBuilders .filter("age_gt_10", QueryBuilders.rangeQuery("age").gt(10)); filter.subAggregation(AggregationBuilders.count("group_by_count").field("name")); searchSourceBuilder.aggregation(filter); SearchRequest request = new SearchRequest("users"); request.source(searchSourceBuilder); SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT); Aggregations aggregations = response.getAggregations(); Filter age_gt_10 = aggregations.get("age_gt_10"); Aggregations aggregations1 = age_gt_10.getAggregations(); ValueCount group_by_count = aggregations1.get("group_by_count"); System.out.println(group_by_count.getValue()); }
可以看出,RestHighLevelClient既可以做簡單的查詢,也可以做複雜的查詢。如果只需要做簡單的資料操作,還是建議用ElasticsearchRepository,程式碼更簡單。和ElasticsearchRestTemplate一樣,建立查詢條件的程式碼要參照es的json查詢語句的寫法,比如這裡的myTest13用的就是巢狀查詢。