Поиск количества встроенных объектов в спящем поиске - PullRequest
0 голосов
/ 10 марта 2020

У меня есть следующие 2 определения сущностей. Отношение Attribute к AttributeValue является «Один ко многим». Я хочу выполнить поиск по объектам атрибутов по указанной категории атрибутов и вернуть все соответствующие объекты атрибутов, с которыми связано хотя бы одно значение атрибута.

Что я пробовал:

Я попробовал наивный подход: сначала поискать все атрибуты, которые соответствуют указанной категории атрибутов, затем для каждого такого атрибута выполнить поиск по значению атрибута по атрибуту и ​​вернуть все совпадающие сущности. Таким образом, я точно знаю, имеет ли атрибут хотя бы одно значение атрибута, связанное с ним. Этот подход довольно медленный.

Вопрос:

Есть ли лучший способ сделать это в поиске гибернации? (Желательно после поиска по атрибуту, у меня уже есть вся информация о количестве значений атрибутов.) Я прочитал раздел Внедренные и связанные объекты в последнем официальном документе поиска в режиме гибернации, но не мог прийти в себя, чтобы иметь четкий подход. Любая помощь приветствуется.

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;  }

1 Ответ

0 голосов
/ 10 марта 2020

Предполагая, что все AttributeValue имеют идентификатор, вы можете попробовать что-то вроде этого:

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 (в бета-версии), с exists предикат . Но для этого потребуется изменить большую часть кода, так как 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 );
...