1. 程式人生 > 其它 >Springboot整合Elasticsearch(查詢資料的方式)

Springboot整合Elasticsearch(查詢資料的方式)

參考文件地址:
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用的就是巢狀查詢。