SpringBoot2.x 版本集成elasticsearch 8.x

  之前使用的elasticsearch 7.14.2,Springboot版本是2.4.13(这个版本坑比较多,用的人也比较少,找问题真的很痛苦)。

   es中间件升级到8.13.3之后,之前的代码在使用保存和编辑之后,es数据里面是都操作成功,但是代码接口却会报错。

复制代码
at java.util.Objects.requireNonNull(Objects.java:203) ~[na:1.8.0_272]
    at org.elasticsearch.action.DocWriteResponse.<init>(DocWriteResponse.java:116) ~[elasticsearch-7.15.2.jar:7.15.2]
    at org.elasticsearch.action.index.IndexResponse.<init>(IndexResponse.java:43) ~[elasticsearch-7.15.2.jar:7.15.2]
    at org.elasticsearch.action.index.IndexResponse.<init>(IndexResponse.java:28) ~[elasticsearch-7.15.2.jar:7.15.2]
    at org.elasticsearch.action.index.IndexResponse$Builder.build(IndexResponse.java:96) ~[elasticsearch-7.15.2.jar:7.15.2]
    at org.elasticsearch.action.index.IndexResponse$Builder.build(IndexResponse.java:93) ~[elasticsearch-7.15.2.jar:7.15.2]
    at org.elasticsearch.action.bulk.BulkItemResponse.fromXContent(BulkItemResponse.java:148) ~[elasticsearch-7.15.2.jar:7.15.2]
    at org.elasticsearch.action.bulk.BulkResponse.fromXContent(BulkResponse.java:177) ~[elasticsearch-7.15.2.jar:7.15.2]
    at org.elasticsearch.client.RestHighLevelClient.parseEntity(RestHighLevelClient.java:2011) ~[elasticsearch-rest-high-level-client-7.15.2.jar:7.15.2]
    at org.elasticsearch.client.RestHighLevelClient.lambda$performRequestAndParseEntity$8(RestHighLevelClient.java:1673) ~[elasticsearch-rest-high-level-client-7.15.2.jar:7.15.2]
    at org.elasticsearch.client.RestHighLevelClient.internalPerformRequest(RestHighLevelClient.java:1749) ~[elasticsearch-rest-high-level-client-7.15.2.jar:7.15.2]
    ... 14 common frames omitted

Caused by: java.io.IOException: Unable to parse response body for Response{requestLine=POST /_bulk?timeout=1m HTTP/1.1, host=http://localhost:9200, response=HTTP/1.1 200 OK}

Caused by: java.lang.NullPointerException: null

Caused by: java.lang.RuntimeException: Bulk request failed

Caused by: java.io.IOException: Unable to parse response body for Response{requestLine=POST /_bulk?timeout=1m HTTP/1.1, host=http://localhost:9200, response=HTTP/1.1 200 OK}
复制代码

  这个是请求es返回的数据有异常。也就是说低版本的es和版本的es返回的数据结构是有差别的,所以归根到底就是客户端和服务端的版本不一致。es官方也说了,高版本的es推荐使用java 17之后的版本,springboot推荐使用3.0的。但是不能说升级一个中间件结果把整个系统都升级一遍,所以官方也给出了一个兼容的模式,具体的代码放在下面,尤其是maven的依赖包版本不要错误。

复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-elasticsearch</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>4.4.2</version>
<scope>compile</scope>

</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.17.4</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>7.17.4</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.17.4</version>
</dependency>
复制代码
复制代码
import cn.hutool.core.convert.Convert;
import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.nio.reactor.IOReactorConfig;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.RestHighLevelClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.RestClients;
import org.springframework.data.elasticsearch.config.AbstractElasticsearchConfiguration;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;

import javax.annotation.PreDestroy;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.List;

@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {


    @Autowired
    private ElasticsearchProperties elasticsearchProperties;
    private RestHighLevelClient client;

    @Override
    @Bean
    public RestHighLevelClient elasticsearchClient() {
        RestClientBuilder restBuilder = RestClient
                .builder(this.getHttpHosts());

        restBuilder.setHttpClientConfigCallback(httpClientBuilder ->
                httpClientBuilder
                        .setKeepAliveStrategy(getConnectionKeepAliveStrategy())
                        .setMaxConnPerRoute(10).
                        setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build()));
        String username = elasticsearchProperties.getAccount().getUsername();
        String password = elasticsearchProperties.getAccount().getPassword();
        SSLContextBuilder sscb = SSLContexts.custom();
        try {
            sscb.loadTrustMaterial((chain, authType) -> {
                // 在这里跳过证书信息校验
                //System.out.println("暂时isTrusted|" + authType + "|" + Arrays.toString(chain));
                return true;
            });
        } catch (NoSuchAlgorithmException | KeyStoreException e) {
            e.printStackTrace();
        }
        if (username != null && password != null) {
            final CredentialsProvider credential = new BasicCredentialsProvider();
            credential.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
            restBuilder.setHttpClientConfigCallback(httpClientBuilder ->
            {
                try {
                    return httpClientBuilder
                            .setSSLContext(sscb.build())
                            .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                            .setDefaultCredentialsProvider(credential)
                            .setKeepAliveStrategy(getConnectionKeepAliveStrategy())
                            .setMaxConnPerRoute(10)
                            .setDefaultIOReactorConfig(IOReactorConfig.custom().setIoThreadCount(1).build());
                } catch (NoSuchAlgorithmException e) {
                    throw new RuntimeException(e);
                } catch (KeyManagementException e) {
                    throw new RuntimeException(e);
                }
            });
        }
        restBuilder.setDefaultHeaders(compatibilityHeaders());
        restBuilder.setRequestConfigCallback(requestConfigBuilder ->
                requestConfigBuilder.setConnectTimeout(1000) //time until a connection with the server is established.
                        .setSocketTimeout(12 * 1000) //time of inactivity to wait for packets[data] to receive.
                        .setConnectionRequestTimeout(2 * 1000)); //time to fetch a connection from the connection pool 0 for infinite.

        client = new RestHighLevelClient(restBuilder);
        restBuilder.build();
        RestHighLevelClient esClient = new RestHighLevelClientBuilder(restBuilder.build())
                .setApiCompatibilityMode(true)
                .build();
        return esClient;
    }

    private Header[] compatibilityHeaders() {
        return new Header[]{
                new BasicHeader(HttpHeaders.ACCEPT, "application/vnd.elasticsearch+json;compatible-with=7"),
                new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/vnd.elasticsearch+json;compatible-with=7")
        };
    }

    private HttpHost[] getHttpHosts() {
        List<String> clusterNodes = elasticsearchProperties.getClusterNodes();
        HttpHost[] httpHosts = new HttpHost[clusterNodes.size()];
        for (int i = 0; i < clusterNodes.size(); i++) {
            String[] node = clusterNodes.get(i).split(":");
            httpHosts[i] = new HttpHost(node[0], Convert.toInt(node[1]), elasticsearchProperties.getSchema());
        }
        return httpHosts;
    }

    private ConnectionKeepAliveStrategy getConnectionKeepAliveStrategy() {
        return (response, context) -> 2 * 60 * 1000;
    }

    /**
     * it gets called when bean instance is getting removed from the context if
     * scope is not a prototype
     * If there is a method named shutdown or close then spring container will try
     * to automatically configure them as callback methods when bean is being
     * destroyed
     */
    @PreDestroy
    public void clientClose() {
        try {
            this.client.close();
        } catch (IOException e) {
        }
    }


    @Bean
    public ElasticsearchRestTemplate restTemplate(RestHighLevelClient restHighLevelClient){
        return new ElasticsearchRestTemplate(restHighLevelClient);
    }


}
复制代码

所以选择中间件升级是一个比较严肃的事情,选择版本要谨慎。

posted @   小杨ABC  阅读(512)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示