You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate Search 5.12中如何测试OneToMany子项的双条件?

查询包含有效职位的组织(Hibernate Search 5.12)

实体定义

Organization实体

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

    @OneToMany(mappedBy = "orga", cascade = CascadeType.ALL, orphanRemoval = true)
    // 显式指定为嵌套类型,让每个Job作为独立的嵌套文档索引
    @IndexEmbedded(embeddedType = IndexEmbeddedType.NESTED, includePaths = {"publishedOn", "archivedOn"})
    final private Set<Job> jobs = new HashSet<>();
}

Job实体

@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的Organization:

  • publishedOn != null(已发布)
  • archivedOn == null(未归档)

原有查询的问题

你提供的查询代码会排除那些存在多个已发布职位但其中一个已归档的组织。原因是原有查询将条件作用于整个Organization的多值字段,而非单个Job实例:

  • 第一个条件要求Organization的jobs.publishedOn字段至少有一个值(存在已发布职位)
  • 第二个条件要求Organization的jobs.archivedOn字段完全没有值(所有职位都未归档)

这和需求不符——我们只需要存在至少一个职位同时满足已发布且未归档即可,不需要所有职位都符合。

正确的查询实现

使用Hibernate Search的嵌套查询(nested query),将两个条件绑定到同一个Job嵌套文档上,确保存在至少一个Job同时满足两个条件:

FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);

QueryBuilder qb = fullTextEntityManager
        .getSearchFactory()
        .buildQueryBuilder()
        .forEntity(Organization.class)
        .get();

// 构建嵌套查询上下文,指向单个Job文档
NestedContext nestedJobContext = qb.nested()
        .onField("jobs")
        .get();

// 单个Job的有效条件:已发布且未归档
Query validJobQuery = nestedJobContext.bool()
        // 条件1:publishedOn不为null
        .must(qb.keyword()
                .wildcard()
                .onField("jobs.publishedOn")
                .ignoreFieldBridge()
                .matching("*")
                .createQuery())
        // 条件2:archivedOn为null(索引中无此字段值)
        .must(qb.bool()
                .must(qb.keyword()
                        .wildcard()
                        .onField("jobs.archivedOn")
                        .ignoreFieldBridge()
                        .matching("*")
                        .createQuery())
                .not()
                .createQuery())
        .createQuery();

// 最终查询:至少存在一个符合条件的Job
Query finalQuery = qb.bool()
        .must(validJobQuery)
        .createQuery();

// 执行查询并获取结果
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(finalQuery, Organization.class);
List<Organization> result = fullTextQuery.getResultList();

关键说明

  1. 嵌套索引配置:必须在Organization的jobs字段上添加embeddedType = IndexEmbeddedType.NESTED,否则Hibernate Search会将所有Job的字段平铺到Organization文档中,无法针对单个Job设置组合条件。
  2. 嵌套查询逻辑:通过qb.nested().onField("jobs")进入嵌套Job的上下文,该上下文中的条件会针对单个Job文档生效,确保两个条件同时满足于同一个Job。
  3. null值处理:用wildcard(*)匹配非空字段,用not()配合wildcard匹配空字段(Hibernate Search默认不会索引null值,因此null字段不会出现在索引中)。

内容的提问来源于stack exchange,提问作者Stuck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 06:47:39