learn and grow up

spring-data-elasticsearch-组件查询的bug跟踪

字数统计: 750阅读时长: 3 min
2020/04/19 Share

写在前面

最近在排查生产问题的时候发现,基于spring-data-es(版本:spring-data-elasticsearch-3.0.8.RELEASE.jar)的ElasticsearchRepository的查询有bug,如下方法:

1
2
3
4
public interface IiapImplTemplateDeviceRepository extends ElasticsearchRepository<IiapTemplateDeviceDoc, String> {
List<IiapTemplateDeviceDoc> findByXXId(String id);

}

这个方法原本是需要返回全量数据,但是它最多只会返回了10条数据,跟踪源码最终发现了此问题。

bug定位

首先根据之前的文章spring-data-es的源码浅析 分析,我们直接去该组件的RepositoryQuery的实现类去看问题ElasticsearchPartQuery。
拦截后最终执行的代码如下:

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
//org.springframework.data.elasticsearch.repository.query.ElasticsearchPartQuery#execute
//可以看到这里首先是针对返回的类型或参数进行判断到低属于删除还是分页查询还是列表查询等等,
//可以看到我们最终会运行到这个判断里:if (this.queryMethod.isCollectionQuery())
public Object execute(Object[] parameters) {
ParametersParameterAccessor accessor = new ParametersParameterAccessor(this.queryMethod.getParameters(), parameters);
CriteriaQuery query = this.createQuery(accessor);
if (this.tree.isDelete()) {
Object result = this.countOrGetDocumentsForDelete(query, accessor);
this.elasticsearchOperations.delete(query, this.queryMethod.getEntityInformation().getJavaType());
return result;
} else if (this.queryMethod.isPageQuery()) {
query.setPageable(accessor.getPageable());
return this.elasticsearchOperations.queryForPage(query, this.queryMethod.getEntityInformation().getJavaType());
} else if (this.queryMethod.isStreamQuery()) {
Class<?> entityType = this.queryMethod.getEntityInformation().getJavaType();
if (query.getPageable().isUnpaged()) {
int itemCount = (int)this.elasticsearchOperations.count(query, this.queryMethod.getEntityInformation().getJavaType());
query.setPageable(PageRequest.of(0, Math.max(1, itemCount)));
}

return StreamUtils.createStreamFromIterator(this.elasticsearchOperations.stream(query, entityType));
} else if (this.queryMethod.isCollectionQuery()) {
if (accessor.getPageable() == null) {
int itemCount = (int)this.elasticsearchOperations.count(query, this.queryMethod.getEntityInformation().getJavaType());
query.setPageable(PageRequest.of(0, Math.max(1, itemCount)));
} else {
query.setPageable(accessor.getPageable());
}

return this.elasticsearchOperations.queryForList(query, this.queryMethod.getEntityInformation().getJavaType());
} else {
return this.tree.isCountProjection() ? this.elasticsearchOperations.count(query, this.queryMethod.getEntityInformation().getJavaType()) : this.elasticsearchOperations.queryForObject(query, this.queryMethod.getEntityInformation().getJavaType());
}
}

看到这里又判断了一遍是否分页: accessor.getPageable() == null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//org.springframework.data.repository.query.ParametersParameterAccessor#getPageable
public Pageable getPageable() {
if (!this.parameters.hasPageableParameter()) {
return Pageable.unpaged();
} else {
Pageable pageable = (Pageable)this.values.get(this.parameters.getPageableIndex());
return pageable == null ? Pageable.unpaged() : pageable;
}
}
//看到我们这个方法最终要么返回Pageable.unpaged(),要么是Pageable对象。
//org.springframework.data.domain.Pageable#unpaged
static Pageable unpaged() {
return Unpaged.INSTANCE;
}

可以看到这个判断: accessor.getPageable() == null 永远不会成立!

所以就算我们前面定义了全量查询,这里也会设置为分页查询:query.setPageable(accessor.getPageable());

解决方案

可以看到spring-data本身没问题,是spring-data-es的组件代码出错了,我们可否升级其中一个呢?

看到spring-data-es的pom里已经写明了spring-data的版本号,

如下:

pom.xml

所以我们还是要升级spring-data-es

1、升级版本:在github上也找到了这个问题的修复描述,可以看到修复这个bug影响的版本为:3.1.5.RELEASE,我们可以在github上对下3.1.4和3.1.5的该处不同即可发现:

https://github.com/spring-projects/spring-data-elasticsearch/blob/3.1.5.RELEASE/src/main/java/org/springframework/data/elasticsearch/repository/query/ElasticsearchPartQuery.java

修改记录明细为:https://github.com/spring-projects/spring-data-elasticsearch/commit/519a2a11a4eb3648ea330854bf30f0d461836e7f

2、如果怕升级版本麻烦。需要自己封装queryBuilder然后调用template的search方法即可全量查询

CATALOG
  1. 1. 写在前面
  2. 2. bug定位
  3. 3. 解决方案