如何在休眠搜索中查询空集合

How to query for empty collection in hibernate search

我们正在使用带有 ES 后端的 hibernate-search。 Parent class 有多个不同子对象的集合。我们可以根据子项的值过滤父项,因为集合用 @IndexedEmbedded.

注释

我们希望能够根据子集合是否为空来过滤父集合。我们尝试使用 @IndexedEmbedded(indexNullAs = "null"),然后在 queryBuilder.phrase().onField("parent.children").sentence("null").createQuery() 上进行过滤,但没有任何区别。使用 ES 控制台我们可以显示父级,但是当集合为空时它根本没有列出,导致我们相信它没有被索引,因为它是空的。

另一种选择是使用通配符在 parent.collection.field 上进行过滤,但是由于性能原因,hibernate 搜索文档不推荐这样做。

如果升级到Hibernate Search 6, you will be able to use the exists predicate

List<MyEntity> hits = Search.session(entityManager)
        .search(MyEntity.class)
        .where(f -> f.matchAll().except(f.exists().field(“parent.children”))
        .fetchHits(20);

那会解决您的问题,然后然后您可以开始担心性能在您的特定情况下

仍然在 Hibernate Search 6 中,如果您的测试表明第一个解决方案的性能确实存在问题,我建议在 [=15= 上使用 custom bridge ] 索引集合是否为空。像这样:

@SuppressWarnings("rawtypes")
public class MyCollectionEmptyBridge implements ValueBridge<Collection, Boolean> {
    @Override
    public Boolean toIndexedValue(Collection value, ValueBridgeToIndexedValueContext context) {
        return value == null || value.isEmpty();
    }
}

public class MyParentEntity {

   // ...

   @GenericField( 
            name = "childrenAreEmpty",
            valueBridge = @ValueBridgeRef(type = MyCollectionEmptyBridge.class), 
            // Apply the bridge directly to the collection and not to its elements
            // See https://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#_disabling_container_extraction
            extraction = @ContainerExtraction(extract = ContainerExtract.NO) 
    )
    private List<Child> children = new ArrayList<>();

}

List<MyEntity> hits = Search.session(entityManager)
        .search(MyEntity.class)
        .where(f -> f.match().field(“parent.childrenAreEmpty”).matching(true))
        .fetchHits();

第二个解决方案也可以使用 Hibernate Search 5 来实现,尽管 Hibernate Search 5's custom bridges 使用起来有点困难。