如何在休眠搜索中查询空集合
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 使用起来有点困难。
我们正在使用带有 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 使用起来有点困难。