如何在休眠搜索中测试 OneToMany 的每个子级的两个条件?

问题描述 投票:0回答:1

给定两个实体

Organization
Job
及其使用 Hibernate Search 的索引(我被迫仍然使用 HS 5.12)。

@Entity
@Indexed(index = "idx_organization")
public class Organization {
    // ...

    @OneToMany(mappedBy = "orga", cascade = CascadeType.ALL, orphanRemoval = true)
    @IndexEmbedded
    final private Set<Job> jobs = new HashSet<>();
}
@Entity
@Indexed(index = "idx_job")
public class Job {
    // ...

    @NotNull
    @ManyToOne
    @JoinColumn(nullable = false)
    @ContainedIn
    private Organization orga;

    @NotNull
    @Column(nullable = false)
    private String title;

    @Nullable
    @Field
    private OffsetDateTime archivedOn;

    @Nullable
    @Field
    private OffsetDateTime publishedOn;
}

我想要获取所有至少拥有一项

Job
a
以及
a.publishedOn != null
a.archivedOn == null
的组织(即至少拥有一项已发布且非存档作业的组织)

这是我尝试过的,但结果不包括拥有 2 个已发布职位且其中一个已存档的组织。

FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);

QueryBuilder qb = fullTextEntityManager
        .getSearchFactory()
        .buildQueryBuilder()
        .forEntity(Organization.class)
        .get()
final var q = qb.bool();
q.must(qb.keyword()
        .wildcard()
        .onField(Organization_.JOBS + "." + Job_.PUBLISHED_ON)
        .ignoreFieldBridge()
        .matching("*")
        .createQuery()
);
q.must(qb.bool().must(
            qb.keyword()
                .wildcard()
                .onField(Organization_.JOBS + "." + Job_.ARCHIVED_ON)
                .ignoreFieldBridge()
                .matching("*")
                .createQuery()
        ).not() // <-- note the "not"
        .createQuery()
);
hibernate-search
1个回答
0
投票

我被迫仍然使用 HS 5.12

我猜你的意思是 5.11,因为 5.12 不存在。

我想要获取所有至少拥有一项作业 a 且 a.publishedOn != null 且 a.archivedOn == null 的组织

这在 Hibernate Search 5 中的查询时是不可能的。

本质上您需要 Hibernate Search 6+ 的

nested
谓词

在 Hibernate Search 5 中您能做的最好的事情就是在索引时执行两个条件的组合,如下所示。

@Entity
@Indexed(index = "idx_job")
public class Job {
    // ...

    @NotNull
    @ManyToOne
    @JoinColumn(nullable = false)
    @ContainedIn
    private Organization orga;

    @NotNull
    @Column(nullable = false)
    private String title;

    @Nullable
    @Field
    private OffsetDateTime archivedOn;

    @Nullable
    @Field
    private OffsetDateTime publishedOn;

    @Field
    @javax.persistence.Transient
    public boolean isLive() {
        return publishedOn != null && archivedOn == null;
    } 
}

重新索引您的数据,然后您可以使用新字段,如下所示。

FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);

QueryBuilder qb = fullTextEntityManager
        .getSearchFactory()
        .buildQueryBuilder()
        .forEntity(Organization.class)
        .get()
final var q = qb.bool();
q.must(qb.keyword()
        .wildcard()
        .onField(Organization_.JOBS + ".live")
        .matching(true)
        .createQuery()
);
© www.soinside.com 2019 - 2024. All rights reserved.