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();
问题原因
- 循环引用:
DoctorSpecialty中通过@ObjectProjection引用了Doctor,而Doctor又包含List<DoctorSpecialty>,导致投影时出现循环层级,干扰Hibernate Search对字段基数的判断。 - 多值字段的投影处理缺失:
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
相关产品推荐
相关产品推荐

