Spring Data Solr是否支持Solr 8原生非匿名嵌套子文档及实现示例
从 Spring Data Solr 4.0 版本(匹配 Solr 8.x 官方支持线)开始,框架已正式兼容 Solr 8 推出的带类型标签的原生嵌套文档模型;低版本仅能通过手动拼接原生查询的方式绕开限制,无法自动完成对象映射。
一、VO 类的正确定义方式
你之前的注解使用存在几处常见适配误区,最简实现不需要引入多余注解:
- 父文档类:正常使用
@SolrDocument绑定对应 Solr Core,子文档集合字段统一使用框架提供的@ChildDocument注解标记,不再使用已适配老匿名子文档的@Field(child = true)写法。 - 子文档类:绝对不要添加
@SolrDocument注解——子文档不是独立存储的顶级文档,加注解会触发框架的独立文档序列化逻辑,直接破坏嵌套结构。 - 子文档内:不需要单独定义
@Id主键字段——Solr 会自动为所有嵌套层级的文档维护关联的_root_字段、内部层级id,子文档的业务字段正常用@Indexed标注即可。
正确代码示例:
import org.springframework.data.solr.core.mapping.ChildDocument; import org.springframework.data.solr.core.mapping.Indexed; import org.springframework.data.solr.core.mapping.SolrDocument; import org.springframework.data.annotation.Id; import java.util.List; @SolrDocument(solrCoreName = "nested_demo_core") public class ParentIndex { @Id @Indexed private String id; // 标记该字段为关联的子文档集合 @ChildDocument private List<ChildIndex> childList; } // 注意:此处不添加@SolrDocument注解 public class ChildIndex { // 注意:此处不添加@Id注解 @Indexed private String data; }
框架序列化时,会自动为每个挂载的子文档写入对应路径的 _nest_path_ 字段,不需要手动维护这个字段的取值。
二、Schema 配置的限制说明
@EnableSolrRepositories 的 schemaCreationSupport 自动建表能力,目前无法自动生成嵌套文档所需的专属配置,所有和嵌套相关的 Schema 必须手动在 Solr 端提前配置完成,不存在自动适配的可能。
你之前写的嵌套式 Field 定义是 Solr 5 之前的老旧嵌套实现方式,在 Solr 8+ 的原生嵌套模型下完全不需要这么写,正确配置要求为:
- 确保 Solr Core 开启嵌套文档支持,手动加载两个内置字段:
_root_:string 类型,indexed、非 stored,用于存储整个嵌套文档树的根文档id_nest_path_:使用 Solr 内置的solr.NestPathField类型,用于标识文档在嵌套树中的层级和所属类型
- 所有业务字段(包括父文档的id、子文档的id、子文档的data字段)全部采用平铺式定义,不需要嵌套在某个子Field标签内,和普通文档的字段配置没有区别。
- 由于子文档类没有标注
@SolrDocument,框架的自动扫描逻辑不会识别到子文档的字段,必须手动在 Schema 中提前定义好这些字段,哪怕用动态字段匹配也要配好,不然写入时会报字段不存在的错误。
三、Repository 操作与 [child] 参数的使用
Repository 基础定义和普通业务接口完全无区别,不需要额外扩展:
import org.springframework.data.solr.repository.SolrRepository; public interface ParentIndexRepository extends SolrRepository<ParentIndex, String> { }
Save 操作
直接调用 repository.save(parentIndexObject) 即可完成整个嵌套文档树的写入,框架会自动处理 _nest_path_、_root_ 字段的填充,不需要手动拼接 Solr 更新请求。
查询操作与 [child] 参数说明
[child] 是 Solr 端返回嵌套子文档的强制必要参数:Solr 默认查询只返回匹配的顶级父文档,不会自动展开挂载的子文档。如果不带这个参数,哪怕存储的是嵌套结构,查询结果里也不会包含任何子文档内容,框架自然也就没法把子文档映射到定义的 childList 字段里。
如果需要在查询时把子文档一并返回,可以通过自定义查询方法指定返回字段:
public interface ParentIndexRepository extends SolrRepository<ParentIndex, String> { // 通过fields参数手动拼接[child]标识,实现子文档的联动返回 @Query(value = "*:*", fields = "*,[child]") List<ParentIndex> findAllWithChildren(); }
如果使用框架默认的 findAll() 方法,这个方法不会自动携带 [child] 参数,返回的父文档对象中的 childList 永远为空,必须自定义方法或者修改 SolrTemplate 的默认查询配置,才能实现带嵌套子文档的查询。
内容的提问来源于stack exchange,提问作者Jaroslav Pubal

