将 HibernateSearch 6.0.6 与 ElasticSearch 5.6 一起使用时出现 NoSuchMethodError

NoSuchMethodError when using HibernateSearch 6.0.6 with ElasticSearch 5.6

我正在尝试将 HibernateSearch 6.0.6.Final 添加到当前使用 ElasticSearch 5.6 的项目中,使用 https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/ 作为指南。

由于 replacing/removing 从我们的代码直接调用 ElasticSearch API 的整个过程似乎有点令人生畏,我想逐步进行迭代。

首先,我刚刚将 HibernateSearch 6.0.6.Final 的依赖项添加到我们的 Maven pom.xml 文件中,但保留了 ElasticSearch 5.6。那里的依赖项(因为大量 Java 代码仍然直接调用 ElasticSearch 5.6。classes 和方法),所以 pom 看起来像这样:

<dependencies>
    ...
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>5.6.16</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.search</groupId>
        <artifactId>hibernate-search-mapper-orm</artifactId>
        <version>6.0.6.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.search</groupId>
        <artifactId>hibernate-search-backend-elasticsearch</artifactId>
        <version>6.0.6.Final</version>
    </dependency>
    ...
</dependencies>

根据 https://hibernate.org/search/releases/#compatibility-matrix 上的兼容性矩阵,这些版本应该可以协同工作。事实上,我仍然能够像以前一样编译和 运行 代码。

当我向我们的一些 bean 添加一些 HibernateSearch 映射注释时,就像这样:

...
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.DocumentId;
import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed;
...

@MappedSuperclass
@Indexed
public abstract class BaseBean implements Serializable {

    @Id
    @DocumentId
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Integer id;

我得到一个 NoSuchMethodeError 具有以下堆栈跟踪:

Caused by: java.lang.NoSuchMethodError: org.elasticsearch.client.Request.<init>(Ljava/lang/String;Ljava/lang/String;)V
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientImpl.toRequest(ElasticsearchClientImpl.java:169)
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientImpl.send(ElasticsearchClientImpl.java:113)
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientImpl.lambda$submit[=12=](ElasticsearchClientImpl.java:82)
    at org.hibernate.search.util.common.impl.Futures.lambda$create[=12=](Futures.java:44)
    at java.util.concurrent.CompletableFuture.uniComposeStage(CompletableFuture.java:981)
    at java.util.concurrent.CompletableFuture.thenCompose(CompletableFuture.java:2124)
    at org.hibernate.search.util.common.impl.Futures.create(Futures.java:44)
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientImpl.submit(ElasticsearchClientImpl.java:82)
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientUtils.tryGetElasticsearchVersion(ElasticsearchClientUtils.java:64)
    at org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientUtils.getElasticsearchVersion(ElasticsearchClientUtils.java:53)
    at org.hibernate.search.backend.elasticsearch.impl.ElasticsearchLinkImpl.initVersion(ElasticsearchLinkImpl.java:200)
    at org.hibernate.search.backend.elasticsearch.impl.ElasticsearchLinkImpl.onStart(ElasticsearchLinkImpl.java:142)
...

显然,HibernateSearch 6.0 附带的 org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientImpl 版本。6.Final 毕竟与我们的 ElasticSearch 5.6.16 不兼容,这与 HibernateSearch 的兼容性矩阵所建议的相反。

因为这是一个 HibernateSearch class,而不是 ElasticSearch class,我想知道为什么会出现这个错误。不会和class路径下同一个class的另一个版本冲突吧?

正如预期的那样,从 HibernateSearch 中排除 ElasticSearch 依赖项完全没有帮助:

<dependencies>
    ...
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>5.6.16</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.search</groupId>
        <artifactId>hibernate-search-mapper-orm</artifactId>
        <version>6.0.6.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.search</groupId>
        <artifactId>hibernate-search-backend-elasticsearch</artifactId>
        <version>6.0.6.Final</version>
        <exclusions>
            <exclusion>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>elasticsearch-rest-high-level-client</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.elasticsearch.client</groupId>
                <artifactId>elasticsearch-rest-client</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.elasticsearch</groupId>
                <artifactId>elasticsearch</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    ...
</dependencies>

那么有没有办法明确告诉 HibernateSearch 使用 ElasticSearch 5.6.16 兼容方法和 classes?这可以在 hibernate.cfg.xml 配置文件中以某种方式配置吗?

我不能只将 pom.xml 中的 ElasticSearch 版本更新为 6.x 或 7.x 进行测试,因为有很多代码需要调整' 使用较新版本的 ElasticSearch。现在,我只想编译并 运行 带有新注释的旧代码,然后从那里开始工作,以完成从 ElasticSearch 到 HibernateSearch 的过渡。

非常感谢任何有关如何解决此问题的帮助或提示!

如前所述 here, the compatibility matrix 为您提供了 Hibernate Search 与 Elasticsearch server.

的兼容性

Elastic 似乎完全可以在其客户端 JAR 中引入重大更改;有时甚至是次要版本。因此,任何依赖于这些 JAR 的库(例如 Hibernate Search)都需要以这些 JAR 的一个且仅一个版本为目标。 Hibernate Search 无法与方法定义不同的多个客户端 JAR 兼容;至少在没有我还没有准备好接受的重大维护负担的情况下。

长话短说:不要试图覆盖 Hibernate Search 使用的客户端 JAR 的版本;那不能很好地结束。这就像野蛮地将您的应用程序降级为 JPA 1.0 JAR;这不太可能奏效。

也就是说,新的低级别 REST 客户端 JAR 与旧的 Elasticsearch 服务器版本兼容。因此,您可以将 Elasticsearch 低级 REST 客户端 7.10 与 Elasticsearch 服务器 5.6 一起使用。

所以您可以这样迁移:

  1. 将应用程序中的客户端升级到版本 7.10(同时保留在 Elasticsearch 服务器 5.6 上)。
  2. 将 Hibernate Search 6.0 添加到您的应用程序。
  3. 稍后,升级到 Elasticsearch 服务器 7.10。最好尽快结束,因为 Elasticsearch 5.6 早就停产了。

不过,如果您使用的是高级客户端 JAR...它只与相同版本的 Elasticsearch 服务器兼容,因此您必须先迁移到 Elasticsearch 服务器 7.10,然后才能迁移到 Hibernate Search .