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

Hibernate Search ElasticBackend投影报错HSEARCH400655求助

Hibernate Search ElasticBackend投影多值字段错误解决方法

问题背景

使用Hibernate ORM 6.5.3.Final、Hibernate Search 7.2.1.Final的ElasticBackend时,通过@ProjectionConstructor定义投影记录后执行查询,触发如下错误:

HSEARCH400655: Invalid cardinality for projection on field 'doctorSpecialties.specialtyCode.id': the projection is single-valued, 
but this field is effectively multi-valued in this context, because parent object field 'doctorSpecialties' is multi-valued. Either call '.multi()' when you create the projection on 
field 'doctorSpecialties.specialtyCode.id', or wrap that projection in an object projection like this: 
'f.object("doctorSpecialties").from(<the projection on field doctorSpecialties.specialtyCode.id>).as(...).multi()'.  

投影记录定义如下:

@ProjectionConstructor
public record Doctor(
    UUID id,
    @ObjectProjection(includeDepth = 1) DoctorDetails doctorDetails,
    @ObjectProjection(includeDepth = 2) List<DoctorSpecialty> doctorSpecialties
) {}
public record DoctorSpecialty(
    UUID id,
    @ObjectProjection(includeDepth = 1) Specialty specialtyCode,
    @ObjectProjection(includeDepth = 1) Doctor doctor
) {}
public record Specialty(
    UUID id,
    String specialtyName,
    Integer specilalty // 注意此处字段名拼写错误,建议修正为specialty
) {}

查询代码:

List<com.platform.service.projection.dto.Doctor> suppliers = searchSession
            .search(com.platform.domain.Doctor.class)
            .select(com.platform.service.projection.dto.Doctor.class)
            .where(/* 查询条件 */)
            .fetchAll();

问题原因

  1. 循环引用:DoctorSpecialty中通过@ObjectProjection引用了Doctor,而Doctor又包含List<DoctorSpecialty>,导致投影时出现循环层级,干扰Hibernate Search对字段基数的判断。
  2. 多值字段的投影处理缺失:doctorSpecialties是多值列表(List<DoctorSpecialty>),自动投影时未明确标记该层级为多值,导致嵌套字段的基数判断错误。

解决步骤

1. 移除循环引用

修改DoctorSpecialty记录,去掉对Doctor的投影(或设置includeDepth = 0避免加载嵌套的Doctor):

public record DoctorSpecialty(
    UUID id,
    @ObjectProjection(includeDepth = 1) Specialty specialtyCode
    // 移除@ObjectProjection(includeDepth = 1) Doctor doctor 这一行
) {}

2. 手动构建投影(替代自动投影)

放弃依赖@ProjectionConstructor的自动映射,手动构建投影并明确标记多值字段:

List<Doctor> suppliers = searchSession
        .search(com.platform.domain.Doctor.class)
        .select(f -> f.composite(
                // 映射id字段
                f.field("id", UUID.class),
                // 映射DoctorDetails对象
                f.object("doctorDetails").as(DoctorDetails.class),
                // 映射多值的DoctorSpecialties列表,明确调用.multi()
                f.object("doctorSpecialties")
                        .multi()
                        .as(DoctorSpecialty.class)
        ))
        .where(/* 查询条件 */)
        .fetchAll();

3. 修正字段拼写错误(可选但推荐)

将Specialty中的specilalty字段名修正为specialty,避免后续ORM操作出现字段匹配问题:

public record Specialty(
    UUID id,
    String specialtyName,
    Integer specialty
) {}

验证

调整后重新执行查询,Hibernate Search会正确识别多值字段的基数,避免报错。

内容的提问来源于stack exchange,提问作者Another Good Guy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 18:34:57