在休眠搜索中查找嵌入式实体的计数

Finding counts of embedded entities in hibernate search

我有以下两个实体定义。从 Attribute 到 AttributeValue 的关系是一对多的。我想按指定的属性类别和 return 全部搜索属性实体 匹配具有至少一个关联属性值的属性实体。

我试过的:

我尝试了一种天真的方法,即首先搜索与指定属性类别匹配的所有属性,然后对于每个此类属性,按属性和 return 所有匹配的实体搜索属性值。这样,我就可以确定一个属性是否至少有一个属性值与其相关联。这种方法虽然很慢。

问题:

在休眠搜索中有更好的方法吗? (最好是在搜索属性之后,我已经有了所有属性值计数信息 returned。)我已经阅读了最新休眠中的 Embedded and associated objects 部分查了官方文档也没找到明确的方法。感谢任何帮助。

public class Attribute {

    @Id
    @DocumentId
    @Column(name = "ID")
    private Long id;

    @Field
    @Column(name = "ATTRIBUTE_NAME", unique = true, nullable = false)
    private String attributeName;

    @Field
    @FieldBridge(impl = EnumBridge.class)
    @Enumerated(EnumType.STRING)
    @Column(name = "ATTRIBUTE_CATEGORY", nullable = false)
    private AttributeCategory attributeCategory;

    @IndexedEmbedded(includePaths = {"id"})
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "attribute", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Set<AttributeValue> attributeValues = new HashSet<>();  }

public class AttributeValue {

    @Id
    @DocumentId
    @Column(name = "ID")
    private Long id;

    @Field
    @Column(name = "ATTRIBUTE_VALUE_NAME")
    private String attributeValueName;

    @IndexedEmbedded(includePaths = {"id", "attributeName"})
    @ManyToOne
    @JoinColumn(name = "ATTRIBUTE_ID")
    private Attribute attribute;  }

假设所有 AttributeValue 都有一个 ID,您可以尝试这样的操作:

AttributeCategory expectedCategory = ...;
QueryBuilder qb = ...;
Query luceneQuery = qb.bool()
    .must( qb.keyword().onField( "attributeCategory" )
            .matching( expectedCategory ).createQuery() )
    .must( qb.keyword().wildcard().onField( "attributeValues.id" )
            .matching( "*" ).createQuery() )
    .createQuery();
FullTextQuery query = Search.getSearchEntityManager( entityManager )
        .createFullTextQuery( luceneQuery, Attribute.class );
query.setMaxResults( 20 );
List<Attribute> hits = query.getResultList();

在 Hibernate Search 6(Beta 版)中使用 exists predicate 更直观(并且可能更有效)。但这需要您更改大部分代码,因为 API 不同:

AttributeCategory expectedCategory = ...;
List<Attribute> hits = Search.session( entityManager )
        .search( Attribute.class )
        .where( f -> f.bool()
            .must( f.match().field( "attributeCategory" )
                .matching( expectedCategory ) )
            .must( f.exists().field( "attributeValue" ) ) )
        .fetchHits( 20 );