ElasticSearch 如何像 MySQL 一样做多表联合查询?

2年前 (2022) 程序员胖胖胖虎阿
348 0 0

松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->松哥要升级 SpringBoot 视频了,看看新增了哪些内容!


Es 系列更新到第 23 篇啦~今天我们来看 Es 中的嵌套查询与父子文档,这两个东西很有来头!关系型数据库中的多表联合查询需求在 Es 中可以用它们来解决。

视频:

如果大家觉得视频风格还能接受,也可以看看松哥的付费视频:Spring Boot+Vue+微人事视频教程

以下是视频笔记:

注意,笔记只是视频内容的一个简要记录,因此笔记内容比较简单,完整的内容可以查看视频。

关系型数据库中有表的关联关系,在 es 中,我们也有类似的需求,例如订单表和商品表,在 es 中,这样的一对多一般来说有两种方式:

  • 嵌套文档(nested)
  • 父子文档

18.1 嵌套文档

假设:有一个电影文档,每个电影都有演员信息:

PUT movies
{
  "mappings": {
    "properties": {
      "actors":{
        "type""nested"
      }
    }
  }
}

PUT movies/_doc/1
{
  "name":"霸王别姬",
  "actors":[
    {
      "name":"张国荣",
      "gender":"男"
    },
    {
      "name":"巩俐",
      "gender":"女"
    }
    ]
}

注意 actors 类型要是 nested,具体原因参考 10.2.3 小节。

缺点

查看文档数量:

GET _cat/indices?v

查看结果如下:

ElasticSearch 如何像 MySQL 一样做多表联合查询?
image-20201119162958456

这是因为 nested 文档在 es 内部其实也是独立的 lucene 文档,只是在我们查询的时候,es 内部帮我们做了 join 处理,所以最终看起来就像一个独立文档一样。因此这种方案性能并不是特别好。

18.2 嵌套查询

这个用来查询嵌套文档:

GET movies/_search
{
  "query": {
    "nested": {
      "path""actors",
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "actors.name""张国荣"
              }
            },
            {
              "match": {
                "actors.gender""男"
              }
            }
          ]
        }
      }
    }
  }
}

18.3 父子文档

相比于嵌套文档,父子文档主要有如下优势:

  • 更新父文档时,不会重新索引子文档
  • 创建、修改或者删除子文档时,不会影响父文档或者其他的子文档。
  • 子文档可以作为搜索结果独立返回。

例如学生和班级的关系:

PUT stu_class
{
  "mappings": {
    "properties": {
      "name":{
        "type""keyword"
      },
      "s_c":{
        "type""join",
        "relations":{
          "class":"student"
        }
      }
    }
  }
}

s_c 表示父子文档关系的名字,可以自定义。join 表示这是一个父子文档。relations 里边,class 这个位置是 parent,student 这个位置是 child。

接下来,插入两个父文档:

PUT stu_class/_doc/1
{
  "name":"一班",
  "s_c":{
    "name":"class"
  }
}
PUT stu_class/_doc/2
{
  "name":"二班",
  "s_c":{
    "name":"class"
  }
}

再来添加三个子文档:

PUT stu_class/_doc/3?routing=1
{
  "name":"zhangsan",
  "s_c":{
    "name":"student",
    "parent":1
  }
}
PUT stu_class/_doc/4?routing=1
{
  "name":"lisi",
  "s_c":{
    "name":"student",
    "parent":1
  }
}
PUT stu_class/_doc/5?routing=2
{
  "name":"wangwu",
  "s_c":{
    "name":"student",
    "parent":2
  }
}

首先大家可以看到,子文档都是独立的文档。特别需要注意的地方是,子文档需要和父文档在同一个分片上,所以 routing 关键字的值为父文档的 id。另外,name 属性表明这是一个子文档。

父子文档需要注意的地方:

  1. 每个索引只能定义一个 join filed
  2. 父子文档需要在同一个分片上(查询,修改需要routing)
  3. 可以向一个已经存在的 join filed 上新增关系

18.4 has_child query

通过子文档查询父文档使用 has_child query。

GET stu_class/_search
{
  "query": {
    "has_child": {
      "type""student",
      "query": {
        "match": {
          "name""wangwu"
        }
      }
    }
  }
}

查询 wangwu 所属的班级。

18.5 has_parent query

通过父文档查询子文档:

GET stu_class/_search
{
  "query": {
    "has_parent": {
      "parent_type""class",
      "query": {
        "match": {
          "name""二班"
        }
      }
    }
  }
}

查询二班的学生。但是大家注意,这种查询没有评分。

可以使用 parent id 查询子文档:

GET stu_class/_search
{
  "query": {
    "parent_id":{
      "type":"student",
      "id":1
    }
  }
}

通过 parent id 查询,默认情况下使用相关性计算分数。

18.6 小结

整体上来说:

  1. 普通子对象实现一对多,会损失子文档的边界,子对象之间的属性关系丢失。
  2. nested 可以解决第 1 点的问题,但是 nested 有两个缺点:更新主文档的时候要全部更新,不支持子文档属于多个主文档。
  3. 父子文档解决 1、2 点的问题,但是它主要适用于写多读少的场景。

ElasticSearch 系列其他文章:

  1. 打算出一个 ElasticSearch 教程,谁赞成,谁反对?
  2. ElasticSearch 从安装开始
  3. ElasticSearch 第三弹,核心概念介绍
  4. ElasticSearch 中的中文分词器该怎么玩?
  5. ElasticSearch 索引基本操作
  6. ElasticSearch 文档的添加、获取以及更新
  7. ElasticSearch 文档的删除和批量操作
  8. ElasticSearch 文档路由,你的数据到底存在哪一个分片上?
  9. ElasticSearch 并发的处理方式:锁和版本控制
  10. ElasticSearch 中的倒排索引到底是什么?
  11. ElasticSearch 动态映射与静态映射
  12. ElasticSearch 四种字段类型详解
  13. ElasticSearch 中的地理类型和特殊类型
  14. ElasticSearch 23 种映射参数详解
  15. ElasticSearch 如何配置某个字段的权重?
  16. ElasticSearch 23 种映射参数详解【3】
  17. ElasticSearch 映射模版
  18. ElasticSearch 搜索入门
  19. ElasticSearch 全文搜索怎么玩?
  20. ElasticSearch 打错字还能搜索到?试试 fuzzy query!
  21. ElasticSearch 复合查询,理解 Es 中的文档评分策略!
  22. 想搜索附近评分较高的餐厅,ElasticSearch 大显身手!






往期推荐
0
1

50+ 需求文档免费下载!

0
2

Spring Security 教程合集

0
3

接了两个私活,都是血汗钱

ElasticSearch 如何像 MySQL 一样做多表联合查询?

本文分享自微信公众号 - 江南一点雨(a_javaboy)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

相关文章

暂无评论

暂无评论...