大家好,我是老坛。
今天跟大家交流一个ES常见问题及解决方法。
错误发生场景
我引入ES的方式是使用的spring boot starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
然后spring boot的版本为:2.3.4.RELEASE
贴一下报错来源代码:
@SpringBootTest
@RunWith(SpringRunner.class)
public class ESTest {
@Resource
RestHighLevelClient restHighLevelClient;
String index = "index";
@Test
public void insertSingle() throws IOException {
IndexRequest request = new IndexRequest(index);
request.id("1001");
TextBook textBook = new TextBook();
textBook.setBookName("老坛聊开发");
textBook.setEdition("老坛");
textBook.setEditionTime("20221109");
request.source(JSON.toJSONString(textBook), XContentType.JSON);
restHighLevelClient.index(request, RequestOptions.DEFAULT);
}
}
当我对ES进行查询操作时是没有问题的,但是涉及到了任何的更新操作就会报下面的错误,但最奇怪的是我对ES的更新操作实际上在ES中是生效了的,但是控制台就是报错。
我先贴出来我这个问题的完整错误信息:
java.io.IOException: Unable to parse response body for Response{requestLine=PUT /index/_doc/1?timeout=1m HTTP/1.1, host=http://10.1.1.213:9200, response=HTTP/1.1 201 Created}
可以看出这条错误是解析返回值的时候出错的,再结合刚才说的在ES生效的现象可以推断出在ES操作实际上是成功了,但是ES那边返回成功提示的时候java这边解析出问题了。
问题分析
这个问题的特点是我们对ES的操作实际上是成功了,但是因为返回值的解析出错才失败了。
我们跟着错误栈定位一下发现错误抛出源码的位置:
try {
response = this.client.performRequest(req);
} catch (ResponseException var12) {
ResponseException e = var12;
if (ignores.contains(var12.getResponse().getStatusLine().getStatusCode())) {
try {
return responseConverter.apply(e.getResponse());
} catch (Exception var10) {
throw this.parseResponseException(var12);
}
}
throw this.parseResponseException(var12);
}
try {
return responseConverter.apply(response);
} catch (Exception var11) {
throw new IOException("Unable to parse response body for " + response, var11);
}
可见response已经回来了都没有出错,但是在下面解析的时候出错了。
更多优质文章资源请关注同名公众号:老坛聊开发
因此网上有些小伙伴提出了一种取巧的办法就是使用try-catch把对ES更新操作的代码包住,固定把这一种报错给隐蔽掉,修改后代码如下:
@Test
public void insertSingle() throws IOException {
IndexRequest request = new IndexRequest(index);
request.id("1001");
TextBook textBook = new TextBook();
textBook.setBookName("老坛聊开发");
textBook.setEdition("老坛");
textBook.setEditionTime("20221109");
request.source(JSON.toJSONString(textBook), XContentType.JSON);
try {
restHighLevelClient.index(request, RequestOptions.DEFAULT);
}
catch (Exception e) {
String msg = e.getMessage();
if(!msg.contains("201 Created") && !msg.contains("200 OK")) {
throw e;
}
}
}
这种方式看起来也能解决问题但会降低代码的可读性,而且不利于我们发现问题的本质,所以我们还需要继续取探索。
解决方法
这里告诉大家一个非常关键的经验:往往遇到奇奇怪怪的问题时通常是包冲突或者是中间件版本冲突引起的。
因为这些报错不是我们自己写代码引起的,它们肯定来自于我们引入的代码,所以我们才会觉得没见过或者奇奇怪怪,那引入的代码好好的又不可能会随便报错,那就只可能是他们所依赖的其它包的版本发生了变化或者是所依赖的中间件的版本发生了变化。
这里便不再赘述了。本次问题主要是中间件版本冲突引起的。
我们这里仔细看一下控制台不难发现:
日志里有一条warning,这条warning提示我们:我们所使用的es中间件的版本是8.5.0,但是我们使用的api包的版本是7.6.2,二者不匹配。 所以我们要不然就对自己的es中间件降级,要不然就升级我们的api包,总之保持二者版本一致就可以了。
关于如何去查找es中间件与api对应的版本关系,请参照我的这篇文章
【ES知识】es版本与java api版本对照一览https://blog.csdn.net/qq_34263207/article/details/127790216