迁移到 Spring Data Elasticsearch 5 后如何运行 Elasticsearch 操作?

问题描述 投票:0回答:2

我正在将 Maven 项目从 Spring Boot 2.7 升级到 Spring Boot 3.1.5,并将其迁移到 Spring Data Elasticsearch 5.1 和 Elasticsearch 7.17.2 到 8.7。

在更新 Spring Data Elasticsearch 后,他们删除了依赖项,其中包含:

org.elasticsearch.index.query.QueryBuilders;

因此,它默认附带一组新的查询对象:

co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;

但是,新的查询类型与

Elasticsearchoperations
不兼容,而这正是我在以前版本的 Elasticsearch 中能够使用的。

我尝试将其替换为:

co.elastic.clients.elasticsearch.ElasticsearchClient;

因为这使用了新的

Query
类,但正如评论者所说,我似乎已经搞错了。如果我尝试
@Autowire
ElasticsearchClient 并运行搜索,我会收到错误“连接已关闭”:

Unsatisfied dependency expressed through constructor parameter 4: Error creating bean with name 'myESRepository' defined in org.MyProject....MyESRepository defined in @EnableElasticsearchRepositories declared on IndexingConfiguration: Failed to instantiate [org.springframework.data.elasticsearch.repository.support.SimpleElasticsearchRepository]: Constructor threw exception
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:801)
        at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:240)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1352)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1189)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:973)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:950)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:616)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:738)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:440)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
        at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137)
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58)
        at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46)
        at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1406)
        at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:545)
        at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137)
        at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108)
        at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:187)
        at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:119)
        ... 73 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myESRepository' defined in org.blah.MyESRepository defined in @EnableElasticsearchRepositories declared on IndexingConfiguration: Failed to instantiate [org.springframework.data.elasticsearch.repository.support.SimpleElasticsearchRepository]: Constructor threw exception
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1770)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1417)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337)
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:910)
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:788)
        ... 97 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.elasticsearch.repository.support.SimpleElasticsearchRepository]: Constructor threw exception
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:224)
        at org.springframework.data.repository.core.support.RepositoryFactorySupport.lambda$instantiateClass$5(RepositoryFactorySupport.java:571)
        at java.base/java.util.Optional.map(Optional.java:260)
        at org.springframework.data.repository.core.support.RepositoryFactorySupport.instantiateClass(RepositoryFactorySupport.java:571)
        at org.springframework.data.repository.core.support.RepositoryFactorySupport.getTargetRepositoryViaReflection(RepositoryFactorySupport.java:536)
        at org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactory.getTargetRepository(ElasticsearchRepositoryFactory.java:79)
        at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:317)
        at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:279)
        at org.springframework.data.util.Lazy.getNullable(Lazy.java:245)
        at org.springframework.data.util.Lazy.get(Lazy.java:114)
        at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:285)
        at org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactoryBean.afterPropertiesSet(ElasticsearchRepositoryFactoryBean.java:69)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1817)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1766)
        ... 108 more
Caused by: org.springframework.dao.DataAccessResourceFailureException: Connection is closed
        at org.springframework.data.elasticsearch.client.elc.ElasticsearchExceptionTranslator.translateExceptionIfPossible(ElasticsearchExceptionTranslator.java:107)
        at org.springframework.data.elasticsearch.client.elc.ElasticsearchExceptionTranslator.translateException(ElasticsearchExceptionTranslator.java:63)
        at org.springframework.data.elasticsearch.client.elc.ChildTemplate.execute(ChildTemplate.java:73)
        at org.springframework.data.elasticsearch.client.elc.IndicesTemplate.doExists(IndicesTemplate.java:177)
        at org.springframework.data.elasticsearch.client.elc.IndicesTemplate.exists(IndicesTemplate.java:169)
        at org.springframework.data.elasticsearch.repository.support.SimpleElasticsearchRepository.<init>(SimpleElasticsearchRepository.java:83)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:211)
        ... 121 more
Caused by: java.lang.RuntimeException: Connection is closed
        at org.springframework.data.elasticsearch.client.elc.ElasticsearchExceptionTranslator.translateException(ElasticsearchExceptionTranslator.java:62)
        ... 131 more
Caused by: org.apache.http.ConnectionClosedException: Connection is closed
        at org.elasticsearch.client.RestClient.extractAndWrapCause(RestClient.java:920)
        at org.elasticsearch.client.RestClient.performRequest(RestClient.java:300)
        at org.elasticsearch.client.RestClient.performRequest(RestClient.java:288)
        at co.elastic.clients.transport.rest_client.RestClientTransport.performRequest(RestClientTransport.java:153)
        at co.elastic.clients.elasticsearch.indices.ElasticsearchIndicesClient.exists(ElasticsearchIndicesClient.java:620)
        at org.springframework.data.elasticsearch.client.elc.IndicesTemplate.lambda$doExists$2(IndicesTemplate.java:177)
        at org.springframework.data.elasticsearch.client.elc.ChildTemplate.execute(ChildTemplate.java:71)
        ... 130 more
Caused by: org.apache.http.ConnectionClosedException: Connection is closed
        at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.endOfInput(HttpAsyncRequestExecutor.java:356)
        at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:261)
        at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:87)
        at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:40)
        at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:114)
        at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162)
        at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337)
        at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
        at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
        at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
        at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:591)
        at java.base/java.lang.Thread.run(Thread.java:833)

在之前的版本中,我可以在 ElasticsearchOperations 上使用

@Autowired
,并且在我的集成测试中,它将正确连接到正在运行的 Elasticsearch Testcontainer。

我有多个共享测试容器的测试;任何使用它的测试都只需实现这个接口:

@SpringBootTest
@Testcontainers
public interface ElasticsearchIntegrationTest {
    final DockerImageName ES_IMAGE = DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch:8.7.0");

    static ElasticsearchContainer elasticsearchContainer = new ElasticsearchContainer(ES_IMAGE);

    @DynamicPropertySource
    static void elasticsearchProperties(final DynamicPropertyRegistry dynamicPropertyRegistry) {
        final String username = "elastic";
        final String password = "password";
        elasticsearchContainer.withPassword(password);
        elasticsearchContainer.start();

        dynamicPropertyRegistry.add("spring.elasticsearch.username", () -> username);
        dynamicPropertyRegistry.add("spring.elasticsearch.password", () -> password);
        dynamicPropertyRegistry.add("spring.elasticsearch.uris",
                () -> List.of(elasticsearchContainer.getHttpHostAddress()));
    }
}

如果我选择手动包含从 Spring Data Elasticsearch 中删除的依赖项(感觉不对):

<dependency>
  <groupId>org.elasticsearch</groupId>
  <artifactId>elasticsearch</artifactId>
  <version>8.11.3</version>
</dependency>

然后我仍然可以使用旧的查询类型,除了

NativeQuery
,它已被弃用。

因此,如果我使用新 API 编写查询,我将无法使用 Elasticsearchoperations,但如果我坚持使用旧 API,我将无法使用 NativeQuery。

我的测试课

Elasticsearchoperations
看起来像这样:

class MyIndexIntegrationTest
        implements ElasticsearchIntegrationTest {

    @Autowired
    private Elasticsearchoperations elasticsearchOperations;

    @Test
    void testSearchMyIndex() {
         final String matchThis = "hello";
         final Query field1Query = new NativeSearchQueryBuilder() // Removed in Spring Data 5
                .withQuery(QueryBuilders.matchQuery("field1",
                        matchThis))
                .build();

          final List<MyIndex> actualIndexed = elasticsearchOperations
                .search(field1Query, MyIndex.class)
                .stream()
                .map(SearchHit::getContent)
                .toList();

          // assertions etc
     }

}

这在 Spring Data Elasticsearch 的早期版本中有效,但现在 NativeSearchQueryBuilder 已被删除。如果我能找到一种方法将 matchQuery 转换为 Elasticsearchoperations.search 可以作为其第一个参数的标准查询,我就有可能绕过它,但这似乎不可能,而且依赖旧的查询似乎是错误的API(我什至不知道 Elasticsearch 8 容器是否可以使用该 API)。

那我该怎么办?如何使用已弃用的 NativeQuery 运行搜索?或者,我如何使用新 API 中的新 QueryBuilder 进行搜索?

java spring-boot elasticsearch spring-data-elasticsearch testcontainers
2个回答
0
投票

ElasticsearchOperations
Query
作为参数,它是 Spring Data Elasticsearch 中定义的接口。其中一个实现是在版本
NativeSearchQuery
中,它已被
NativeQuery
取代。顾名思义,这些实现使用底层 Elasticsearch 客户端库的本机函数,这在版本 5 中发生了变化。因此,您需要使用 Elasticsearch Java 客户端的方法重新创建查询。

或者,如果您想独立于客户端代码,请查看是否可以使用

CriteriaQuery
或 Spring Data 存储库以及类似
findByField1(String)

的匹配方法

0
投票

“连接已关闭”错误确实来自 SSL 强制执行。我可以通过将其添加到我的 DynamicPropertySource 来解决这个问题:

elasticsearchContainer.getEnvMap().put("xpack.security.enabled", "false");

至于

Elasticsearchoperations
,我始终无法让它与最新的 API 一起工作,但我发现我完全可以不用它,只需向我的 ElasticsearchRepository 接口添加方法来执行我需要的搜索即可。在上面的例子中,它是:

@Repository
public interface MyIndexRepository extends ElasticsearchRepository<MyIndex, UUID> {
    List<MyIndex> findByField1(String field1);
}

还有测试班:

final List<MyIndex> actualIndexed = myIndexRepository.findByField1("hello");

这可以通过手动包含 org.elasticsearch.elasticsearch 依赖项(甚至高达 8.11.2)来保留原始 API 的 Query 对象,或者实际上通过使用

co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders

中的新 Query API
© www.soinside.com 2019 - 2024. All rights reserved.