Hibernate Search 6 中 FullTextQuery.setCriteriaQuery() 的替代品是什么?

What is replacement for FullTextQuery.setCriteriaQuery() in Hibernate Search 6?

我正在将 Hibernate Search 5 迁移到 Hibernate Search 6。 虽然 documentation 确实很有帮助,但我无法在 Hibernate Search 6 中找到标准查询的替代方法,也没有完全从文档中获得。

这是我要转换的 Hibernate Search 5 查询,

final Criteria criteria = entityManager.unwrap(Session.class).createCriteria(KnowledgeData.class);
    criteria.add(Restrictions.eq("deleted", knowledgeSearchRequest.isDeleted()));
    if (knowledgeSearchRequest.isPublished()) {
        criteria.add(Restrictions.eq("published", knowledgeSearchRequest.isPublished()));
    }
    if (!allDesk) {
        criteria.add(Restrictions.eq("deskId", deskId));
        knowledgeSearchRequest.setDesk(deskId);

    } else {
        Disjunction orJunction = Restrictions.disjunction();
        for (String desk : knowledgeSearchRequest.getDeskIds()) {
            orJunction.add(Restrictions.eq("deskId", desk));
        }
        criteria.add(orJunction);
    }
    if (knowledgeSearchRequest.getLang() != null && knowledgeSearchRequest.getLang().size() > 0) {
        criteria.createAlias("language", "lan");
        Disjunction disJunction = Restrictions.disjunction();
        for (String lang : knowledgeSearchRequest.getLang()) {
            disJunction.add(Restrictions.eq("lan.elements", lang));
        }
        criteria.add(disJunction);
    }
    if (knowledgeSearchRequest.getTags() != null && knowledgeSearchRequest.getTags().size() > 0) {
        criteria.createAlias("tags", "tag");
        Disjunction disJunction = Restrictions.disjunction();
        for (String tag : knowledgeSearchRequest.getTags()) {
            disJunction.add(Restrictions.eq("tag.elements", tag));
        }
        criteria.add(disJunction);
    }
    criteria.add(Restrictions.ne("dataType", DataType.FOLDER));
    // if (userProvider.getCurrentUser().isSystemUser() || visibleToUser) {
    final List<DataVisibility> visibility = new ArrayList<>();
    visibility.add(DataVisibility.PUBLIC);
    if (knowledgeSearchRequest.isAddCpUserDocs()) {
        visibility.add(DataVisibility.ALL_USERS_OF_CUSTOMER_PORTAL_ONLY);
    }
    if (knowledgeSearchRequest.isIncludeCpDocs()) {
        visibility.add(DataVisibility.CUSTOMER_PORTAL);
        visibility.add(DataVisibility.ALL_SIGNED_IN_USERS_OF_CUSTOMER_PORTAL_ONLY);
        visibility.add(DataVisibility.ALL_USERS_OF_CUSTOMER_PORTAL_ONLY);
    }
    criteria.add(Restrictions.in("visibility", visibility));
    // }
    if (knowledgeSearchRequest.isPublished()) {
        final long now = System.currentTimeMillis();
        criteria.add(Restrictions.or(
                Restrictions.and(Restrictions.isNotNull("validFrom"), Restrictions.lt("validFrom", now)),
                Restrictions.isNull("validFrom")));
        criteria.add(Restrictions.or(
                Restrictions.and(Restrictions.isNotNull("validTo"), Restrictions.gt("validTo", now)),
                Restrictions.isNull("validTo")));

    }

而且,我到目前为止构建的谓词是,

searchPredicateFactory.bool(
                            f -> f.should(searchPredicateFactory.phrase().field(KnowledgeData.STANDARD_FIELD_NAME_NAME).boost(3)
                                    .field(KnowledgeData.STANDARD_FIELD_NAME_DISPLAY_NAME).boost(3)
                                    .field("description").boost(2).field("content").matching(resultantQuery))
                                    .should(searchPredicateFactory.wildcard().field(KnowledgeData.STANDARD_FIELD_NAME_NAME).boost(3)
                                            .field(KnowledgeData.STANDARD_FIELD_NAME_DISPLAY_NAME).boost(3)
                                            .field("description").boost(2).field("content").matching(resultantQuery))).toPredicate();

感谢任何线索。

This is the Hibernate Search 5 query that I am trying to convert,

我会挑剔一点:这不是 Hibernate Search 5 查询,这是 Hibernate (ORM) Criteria 查询。这些限制是针对数据库执行的,而不是针对搜索索引执行的。

根据您的问题标题,我假设您正在使用 FullTextQuery.setCriteriaQuery() 将这些限制添加到您的 Hibernate 搜索查询中。请注意 the documentation in Hibernate Search 5 states "using restriction (ie a where clause) on your Criteria query should be avoided" and the javadoc goes even further by stating "No where restriction can be defined".

无论如何...它似乎曾经在 Hibernate Search 5 中工作,至少在某些情况下是这样。

现在,要将其迁移到 Hibernate Search 6+,有一个详细的迁移指南,a section specifically about your problem:

Hibernate Search 6 does not allow adding a Criteria object to a search query.

[...]

If your goal is to apply a filter expressed by an SQL "where" clause executed in-database, rework your query to project on the entity ID, and execute a JPA/Hibernate ORM query after the search query to filter the entities and load them.

简而言之,做这样的事情:

List<Long> ids = Search.session(entityManager).search(MyEntity.class)
        .select(f -> f.id(Long.class))
        .where(f -> ...)
        .fetchHits(20);

criteria.add(Restrictions.in("id", ids));

List<MyEntity> hits = criteria.list();

请注意,这只是一个快速修复:就像 Hibernate Search 5 中的 setCriteria 一样,它的性能可能非常差,分页效果非常差,并且可能导致命中计数不正确。

我建议索引您在 Criteria 查询中使用的属性,并仅使用 Hibernate Search 定义您的 whole 查询,以避免 运行 查询一次针对 Elasticsearch,然后再次针对您的数据库。

另见 https://hibernate.atlassian.net/browse/HSEARCH-3630