最近防疫项目用到es做人员扫码快速检索能力,且es是集群部署,所以在深度分页这一块采用search_after的方式,项目采用spring-cloud开发,所以自然考虑使用spring-data-elasticsearch来操作es,过程中遇到一些坑,分享出来希望对大家有些帮助。

当然,先说正常的使用。

引入依赖,这里直接使用starter

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.7.4</version>
</dependency>

application.properties

1
2
3
4
5
6
7
8
9
spring.application.name=springdataesdemo
# 连接地址
spring.elasticsearch.rest.uris=172.29.0.22:31853
# 连接超时时间
spring.elasticsearch.rest.connection-timeout=1000
# 认证信息,有就填
spring.elasticsearch.rest.password=123456
spring.elasticsearch.rest.username=elastic
server.port=8082

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package org.example.springdataelasticsearch.entity;

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;

/**
* 记录实体类
*/
@Data
@Document(indexName = "record", createIndex = false)
public class Record {

/**
* 编号
*/
@Id
private String id;

/**
* 用户名
*/
private String username;

/**
* 创建时间
*/
@Field(name = "create_time")
private String createTime;

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package org.example.springdataelasticsearch;

import org.example.springdataelasticsearch.entity.Record;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.Query;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@SpringBootTest
public class RecordTest {

@Autowired
private ElasticsearchOperations operations;

@Test
void searchAfter(){
Query query = Query.findAll();
query.setPageable(PageRequest.of(0, 3));
query.addSort(Sort.by(Sort.Direction.ASC, "create_time"));

List<Object> searchAfter = null;
List<Record> foundEntities = new ArrayList<>();

int index = 0;
do {
query.setSearchAfter(searchAfter);
SearchHits<Record> searchHits = operations.search(query, Record.class);
if (index++ == 10 || searchHits.getSearchHits().isEmpty()){
break;
}
foundEntities.addAll(searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList()));
searchAfter = searchHits.getSearchHit((int) (searchHits.getSearchHits().size() - 1)).getSortValues();
}while (true);

System.out.println(foundEntities);
System.out.println(searchAfter);
}

}

至此翻页就可以正常使用了

下面是一些踩坑点

1.通过观察spring-data-elasticsearch的源码可以知道search_after能力在4.2版本才开始支持,所以此版本之前Query类中是没有setSearchAfter()方法的,如果使用的是spring-boot-starter-data-elasticsearch,那要注意其中的spring-data-elasticsearch版本有没有到达4.2

源码位置:https://github.com/spring-projects/spring-data-elasticsearch/blob/4.2.x/src/main/java/org/springframework/data/elasticsearch/core/query/Query.java

1
2
3
4
5
6
7
8
/**
* Sets the setSearchAfter objects for this query.
*
* @param searchAfter the setSearchAfter objects. These are obtained with {@link SearchHit#getSortValues()} from a
* search result.
* @since 4.2
*/
void setSearchAfter(@Nullable List<Object> searchAfter);
2.与Spring Boot版本对应错误导致spring-boot-starter-data-elasticsearchspring-data-elasticsearch版本错误问题

如果你的pom文件中继承的spring-boot-starter-parent版本小于2.5.0,那么哪怕你引入的spring-boot-starter-data-elasticsearch版本是2.7.xspring-data-elasticsearch还是会低于4.2.x,导致Query类中是没有setSearchAfter()方法:
image.png
可以通过将spring-boot-starter-parent的版本升级到2.5.x来解决这个问题,如果你的项目模块较多,或者什么原因升级版本有些麻烦,那么可以通过显示的添加指定版本的依赖来解决这个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<version>2.7.4</version>
<exclusions>
<exclusion>
<artifactId>spring-data-elasticsearch</artifactId>
<groupId>org.springframework.data</groupId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>4.4.3</version>
<scope>compile</scope>
</dependency>

<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.7.3</version>
</dependency>

image.png

官方的版本对应关系图

附上传送地址:https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#preface.versions
loading-ag-981