【问题标题】:NoSuchMethodError when using HibernateSearch 6.0.6 with ElasticSearch 5.6将 HibernateSearch 6.0.6 与 ElasticSearch 5.6 一起使用时出现 NoSuchMethodError
【发布时间】:2021-10-12 22:52:20
【问题描述】:

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

由于从我们的代码中替换/删除对 ElasticSearch API 的直接调用的整个过程看起来有点吓人,我想一步一步地迭代进行。

首先,我刚刚将 HibernateSearch 6.0.6.Final 的依赖项添加到我们的 Maven pom.xml 文件中,但保留了 ElasticSearch 5.6。依赖项(因为大量 Java 代码仍然直接调用 ElasticSearch 5.6. 类和方法),所以 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$0(ElasticsearchClientImpl.java:82)
    at org.hibernate.search.util.common.impl.Futures.lambda$create$0(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.6.Final 附带的 org.hibernate.search.backend.elasticsearch.client.impl.ElasticsearchClientImpl 版本毕竟与我们的 ElasticSearch 5.6.16 不兼容,这与 HibernateSearch 的兼容性矩阵所暗示的相反。

由于这是一个 HibernateSearch 类,而不是 ElasticSearch 类,我想知道为什么会发生这个错误。不会和类路径中同一个类的另一个版本冲突吧?

正如预期的那样,从 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 兼容的方法和类?这可以在hibernate.cfg.xml配置文件中以某种方式配置吗?

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

因此,我们将不胜感激任何有关如何解决此问题的帮助或提示!

【问题讨论】:

    标签: java maven elasticsearch hibernate-search nosuchmethoderror


    【解决方案1】:

    正如here 解释的那样,compatibility matrix 为您提供了 Hibernate Search 与 Elasticsearch 服务器的兼容性。

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

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

    话虽如此,新的低级 REST 客户端 JAR与旧的 Elasticsearch 服务器版本兼容。因此,您可以将 Elasticsearch 低级 REST Client 7.10 与 Elasticsearch server 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。

    【讨论】:

    • 非常感谢@yrodiere 的解释。不幸的是,我们确实也使用了elasticsearch-rest-high-level-client 依赖项。但如果我理解正确的话,应该可以将 HibernateSearch 5.11.9.Final 与我们当前的 ElasticSearch 5.6.16 客户端一起使用,因为该版本的 HibernateSearch 依赖于完全相同的客户端,对吗?在这种情况下,我们应该能够将现有代码与 HibernateSearch 一起使用(尽管是旧版本),不是吗?
    • 您应该可以使用 Hibernate Search 5.11。但我不建议在 2021 年开始使用 Hibernate Search 5.11。首先因为 Hibernate Search 5.11 中的 Elasticsearch 集成是实验性的并且有局限性,并非所有这些都清楚地记录在案。 HSearch 6 更适合 Elasticsearch 后端。其次,因为 5.11 是旧版本,而 Hibernate Search API 与 6.0 完全不同。通过选择 Hibernate Search 5.11,您将在最终迁移到 Hibernate Search 6 时为更多迁移工作做好准备......
    • 好的,那么我可能会从你的答案中走出来,首先将我们的 ES API 升级到版本 7,然后再集成 HibernateSearch。再次感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 2020-04-12
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 2021-02-28
    • 2017-10-19
    • 2017-12-04
    相关资源
    最近更新 更多