Easy-Es Easy-Es
💋首页
  • v3.0.0(当前版本)
  • What's New

    • What' s New In Easy-Es v3.0.0?
  • 历史版本

    • v1.x.x
    • v2.x.x
  • 升级指南

    • 升级到3.x.x说明
💖赞助
  • 开源社区
  • 周边好物
  • 项目PPT (opens new window)
  • 项目介绍
  • 项目成员
  • 参与贡献
加入社区讨论
谁在使用
  • Doc-Apis (opens new window)
  • 健身计划一键生成系统 (opens new window)
  • 极氪汽车
  • Vuepress-theme-vdoing (opens new window)
  • Gitee (opens new window)
  • GitCode (opens new window)
  • Github (opens new window)
  • 简体中文 (opens new window)
  • English (opens new window)

广告采用随机轮播方式显示 ❤️成为赞助商
💋首页
  • v3.0.0(当前版本)
  • What's New

    • What' s New In Easy-Es v3.0.0?
  • 历史版本

    • v1.x.x
    • v2.x.x
  • 升级指南

    • 升级到3.x.x说明
💖赞助
  • 开源社区
  • 周边好物
  • 项目PPT (opens new window)
  • 项目介绍
  • 项目成员
  • 参与贡献
加入社区讨论
谁在使用
  • Doc-Apis (opens new window)
  • 健身计划一键生成系统 (opens new window)
  • 极氪汽车
  • Vuepress-theme-vdoing (opens new window)
  • Gitee (opens new window)
  • GitCode (opens new window)
  • Github (opens new window)
  • 简体中文 (opens new window)
  • English (opens new window)
  • 快速入门

    • 简介
    • 适用场景
    • 顾虑粉碎
    • 避坑指南
    • 快速开始
    • springboot集成demo
    • spring集成指南
    • solon集成指南
    • 配置
    • 注解
  • 核心功能

    • 条件构造器

      • 条件构造器介绍
      • 索引条件构造器
      • 查询条件构造器
      • 更新条件构造器
    • 索引CRUD

      • 索引托管模式
      • 索引CRUD
    • 数据CRUD

      • 数据同步方案
      • 数据CRUD
    • 多数据源支持
    • 动态索引支持
    • 四大嵌套查询
    • 链式调用
  • 拓展功能

    • 混合查询
    • 原生查询
    • 分页查询
    • 嵌套类型
      • 前言
      • 嵌套类型创建索引
      • 嵌套类型 CRUD
    • Join父子类型
    • 获取DSL语句
    • 执行DSL语句
    • 执行SQL语句
    • 自定义RequestOptions
    • 自定义default方法
  • 高阶语法

    • 查询字段过滤
    • 排序
    • 聚合查询
    • 分词&模糊匹配
    • 权重
    • 高亮查询
    • GEO地理位置查询
    • IP查询
  • 插件

    • 插件
    • 领域模型生成插件
  • 其它

    • 问答
    • 与MP差异
    • MySQL和EE语法对比
    • 更新日志
    • 更新计划
    • 版权
    • 鸣谢
  • v2.x文档
  • 拓展功能
老汉
2023-03-18
目录

嵌套类型

# 前言

在MySQL以及其它关系型数据库中,表与表之间相互关联可以用JOIN来实现,但ES中并没有JOIN,所以想要处理这种关联关系就需要了解嵌套类型父子类型和大宽表.

ES底层是Lucene,由于Lucene实际上是不支持嵌套类型的,所有文档都是以扁平的结构存储在Lucene中,ES对嵌套文档的支持,实际上也是采取了一种投机取巧的方式实现的.

嵌套的文档均以独立的文档存入,然后添加关联关系,这就会导致,一条嵌套类型的文档,底层实际上存储了N条数据,而且更新时会株连九族式更新,导致效率低下(如果您的业务场景是写多于读,那么建议您采用父子类型,如果读多于写,则用此嵌套类型).

对于嵌套类型, 我们并不建议您使用,除非万不得已,因为引入嵌套类型后,您后续的CRUD都会变得非常复杂,如果有嵌套+聚合的需求,其编码复杂度会让你怀疑人生.

ES本身更适合"大宽表"模式,不要带着传统关系型数据库那种思维方式去使用ES,我们完全可以通过把多张表中的字段和内容合并到一张表(一个索引)中,来完成期望功能,尽可能规避嵌套类型的使用,不仅效率高,功能也更强大.

当然存在即合理,也确实有个别场景下,不可避免的会用到嵌套类型,作为全球首屈一指的ES-ORM框架,我们对此也提供了支持,用户可以不用,但我们不能没有!

# 嵌套类型创建索引

  • 自动挡模式:

按照下述配置,配置完成后直接启动项目,框架自动完成索引创建/更新

    public class Document{
        // 省略其它字段...
        /**
         * 嵌套类型 
         */
        @IndexField(fieldType = FieldType.NESTED, nestedClass = User.class)
        private List<User> users;
    }
1
2
3
4
5
6
7
8

注意

务必像上面示例一样指定类型为fieldType=NESTED及其nestedClass,否则会导致框架无法正常运行

  • 手动挡模式

方式一:按照自动挡模式,配置好注解,然后直接调用一键生成API生成索引

documentMapper.createIndex();
1

方式二:纯手工打造,所有字段自己安排一遍,不推荐,麻烦得很

LambdaEsIndexWrapper<Document> wrapper = new LambdaEsIndexWrapper<>();
// 省略其它代码
wrapper.mapping(Document::getUsers, FieldType.NESTED);
1
2
3

注意

在手动挡模式下,除了要通过注解@TableField指定nestedClass外,还需要通过wrapper指定该嵌套字段,然后完成索引创建/更新

# 嵌套类型 CRUD

nested(String path, Consumer<Param> consumer);
nested(String path, Consumer<Param> consumer, ScoreMode scoreMode);
nested(boolean condition, String path, Consumer<Param> consumer);
nested(boolean condition, String path, Consumer<Param> consumer, ScoreMode scoreMode);
1
2
3
4

提示

其中path为当前查询对象字段名,例如我在Document对象中嵌套了User数组,字段名为users,又在User对象中嵌套了Faq数组,当我需要去查询User中满足 某些指定条件的数据时,传入的path就为字符串"users" 当我需要查询Faq中满足某些指定条件的数据时,则传入的path为字符串"users.faq" 另外字段的获取方式如果要采取Lambda方式获取,可以使用FieldUtils.val(R column)工具类获取.

其中增删改与非嵌套类型使用无差异,这里不赘述

查询示例:

    @Test
    public void testNestedMatch() {
        // 嵌套查询 查询年龄等于18或8,且密码等于123的数据
        LambdaEsQueryWrapper<Document> wrapper = new LambdaEsQueryWrapper<>();
        wrapper.nested("users", w ->
            w.in(FieldUtils.val(User::getAge), 18, 8)
            .eq(FieldUtils.val(User::getPassword), "123"));
        List<Document> documents = documentMapper.selectList(wrapper);
        System.out.println(documents);

        // 嵌套查询 查询年龄满足18或者问题名称匹配'size也18吗'的全部数据
        LambdaEsQueryWrapper<Document> wrapper2 = new LambdaEsQueryWrapper<>();
        wrapper2.nested("users", w -> w.in("age", 18))
                .or()
                .nested("users.faqs", w -> w.match("faq_name", "size也18吗"));
        List<Document> documents2 = documentMapper.selectList(wrapper2);
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

相关demo可参考源码的test模块->test目录->nested包

帮助我们改善此文档 (opens new window)
上次更新: 2025/05/11
分页查询
Join父子类型

← 分页查询 Join父子类型→

Theme by Vdoing | Copyright © 2021-2025 老汉 | 浙ICP备2022020479号 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式