松哥原创的 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
查看结果如下:
这是因为 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 属性表明这是一个子文档。
父子文档需要注意的地方:
-
每个索引只能定义一个 join filed
-
父子文档需要在同一个分片上(查询,修改需要routing)
-
可以向一个已经存在的 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 小结
整体上来说:
-
普通子对象实现一对多,会损失子文档的边界,子对象之间的属性关系丢失。
-
nested 可以解决第 1 点的问题,但是 nested 有两个缺点:更新主文档的时候要全部更新,不支持子文档属于多个主文档。
-
父子文档解决 1、2 点的问题,但是它主要适用于写多读少的场景。
ElasticSearch 系列其他文章:
-
打算出一个 ElasticSearch 教程,谁赞成,谁反对?
-
ElasticSearch 从安装开始
-
ElasticSearch 第三弹,核心概念介绍
-
ElasticSearch 中的中文分词器该怎么玩?
-
ElasticSearch 索引基本操作
-
ElasticSearch 文档的添加、获取以及更新
-
ElasticSearch 文档的删除和批量操作
-
ElasticSearch 文档路由,你的数据到底存在哪一个分片上?
-
ElasticSearch 并发的处理方式:锁和版本控制
-
ElasticSearch 中的倒排索引到底是什么?
-
ElasticSearch 动态映射与静态映射
-
ElasticSearch 四种字段类型详解
-
ElasticSearch 中的地理类型和特殊类型
-
ElasticSearch 23 种映射参数详解
-
ElasticSearch 如何配置某个字段的权重?
-
ElasticSearch 23 种映射参数详解【3】
-
ElasticSearch 映射模版
-
ElasticSearch 搜索入门
-
ElasticSearch 全文搜索怎么玩?
-
ElasticSearch 打错字还能搜索到?试试 fuzzy query!
-
ElasticSearch 复合查询,理解 Es 中的文档评分策略!
-
想搜索附近评分较高的餐厅,ElasticSearch 大显身手!
1
50+ 需求文档免费下载!
2
Spring Security 教程合集
3
接了两个私活,都是血汗钱
本文分享自微信公众号 - 江南一点雨(a_javaboy)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。