1、关于Nested 问题

上次讲解了Elasticsearch 数据建模之后,很多同学反馈问题:

  • Q1:用nested做嵌套文档,对嵌套文档的字段做查询,只要主文档下一个嵌套文档符合要求,就会把主文档以及下面的所有的嵌套文档都查出来,实际我只需要符合要求的嵌套文档。这个用nested可以做吗?

  • Q2:请教个问题 这个nested 是只要用这个字段类型就影响性能还是说当只有用这个字段类型去筛选才影响性能?

  • Q3:Elasticsearch Nested 取一条数据 怎么搞?

  • Q4:nested聚合查询等,导致jvm内存剧增,出现长时间的full GC,如何破?

介于此,非常有必要将 Nested 类型再梳理一遍。

2、Nested 产生的背景

博文“干货 | Elasticsearch Nested类型深入详解”有讲过,这里再强调一遍。

Object 对象类型对数据拉平存储,不能实现精准检索匹配,会召回不满足查询结果的数据,才导致 Nested 的出现。

举例如下:

PUT laptops-demo/_doc/1
{"id": 1,"name": "联想ThinkPad P1(01CD)","price": 29999,"brand": "Lenovo","attributes": [{"attribute_name": "cpu","attribute_value": "Intel Core i9-10885H"},{"attribute_name": "memory","attribute_value": "32GB"},{"attribute_name": "storage","attribute_value": "2TB"}]
}GET laptops-demo/_searchGET laptops-demo/_search
{"query": {"bool": {"must": [{ "match": { "attributes.attribute_name": "cpu" }},{ "match": { "attributes.attribute_value":  "32GB" }}]}}
}

如上逻辑混乱的检索条件(CPU,8GB 内存混搭的条件),也能召回数据,这不是实际业务需要满足的场景。

本质原因:默认不指定 Mapping,如上的 attributes 里的键值对元素映射为:Object 类型

而 Object 存储类似是单个文档拉平存储的,如下所示:

{
"id": 1,
"name": "联想ThinkPad P1(01CD)",
"price": 29999,
"brand": "Lenovo",
"attributes.attribute_name": ["cpu", "memory", "storage"],
"attributes.attribute_value": [“Intel Core i9-10885H”, “32GB”, “2TB”]
}

有了 Nested 类型,则可以很好的规避上述检索不精确的问题。

3、Nested 如何存储数据的?

先将一下上小节例子,用 Nested 类型实现如下:

注意:若选型 Nested,必须 Mapping 层面明确设定 Nested。

PUT laptops-demo
{"mappings": {"properties": {"id": {"type": "long"},"name": {"type": "text","analyzer": "ik_max_word"},"price": {"type": "long"},"brand": {"type": "keyword"},"attributes": {"type": "nested","properties": {"attribute_name": {"type": "keyword"},"attribute_value": {"type": "keyword"}}}}}
}

还是插入之前数据。

PUT laptops-demo/_doc/1
{"id": 1,"name": "联想ThinkPad P1(01CD)","price": 29999,"brand": "Lenovo","attributes": [{"attribute_name": "cpu","attribute_value": "Intel Core i9-10885H"},{"attribute_name": "memory","attribute_value": "32GB"},{"attribute_name": "storage","attribute_value": "2TB"}]
}

这里想说明的是:对于如下的拼凑且逻辑混乱的检索条件,不再返回数据。

GET laptops-demo/_search
{"query": {"nested": {"path": "attributes","query": {"bool": {"must": [{"match": {"attributes.attribute_name": "cpu"}},{"match": {"attributes.attribute_value": "8GB"}}]}}}}
}

只有将上面的 “8GB” 换成与 cpu 对应的属性值:“Intel Core i9-10885H”,才会有数据召回。

这体现了 Nested  的好处,实现了对象元素的“精准打击(检索)”。

嵌套对象将数组中的每个对象作为单独的隐藏文档(hidden separate document)进行索引。

拿上面的“联想电脑”的例子,用户看到写入了一个文档(对应文档id为1,包含三组attributes属性对象数据),实际后台是:4 个 Lucene 文档。

4个 Lucene 文档组成:1个父 Lucene 文档 (或者叫做:根文档)+ 3 个 Lucene 隐藏文档(nested 对象文档)。

具体文档存储大致拆解如下所示:

  • 父文档或根文档

{ "id": 1,"name": "联想ThinkPad P1(01CD)","price": 29999,"brand": "Lenovo"
}
  • 第二个文档

{ "attributes.attribute_name": "cpu","attributes.attribute_value": "Intel Core i9-10885H"
}
  • 第三个文档

{ "attributes.attribute_name": "memory","attributes.attribute_value": "32GB"
}
  • 第四个文档

{ "attributes.attribute_name": "storage","attributes.attribute_value": "2TB"
}

这意味着:如果 attributes 键值对增多,假设上述示例中电脑的相关属性有100个,那么后台就会有:101 个文档。这看似风平浪静的存储,实际造成的风险还是很大的。

同样的一份文档写入,若包含 Nested 类型,则意味着有 N 个Nesed 子对象,就会多出 N 个 隐形文档,写入必然会有压力。

同样的,检索原来一个文档搞定,现在要在根文档及周边的 N 个隐形文档附件召回数据,势必检索性能也会受到影响。

大家似乎能隐约感觉到了:写入慢、更新慢、检索慢的问题所在了!

4、Nested 实战问题及解答

4.1 Nested 新增或更新子文档操作,为什么需要更新整个文档?

嵌套 Nested 文档在物理上位于根文档旁边的 Lucene 段中。这是为什么当只想更改单个嵌套文档时必须重新索引根文档和所有嵌套 Nested 文档的原因。

4.2 Nested 文档和父子文档(join 类型)本质区别?

6.X 之前的版本:父子文档是独立不同 type 实现,6.X 之后版本父、子文档要必须位于同一个分片上。

Nested 的存储不同之处如前所述:嵌套文档和父文档(根文档)必须在段中依次相邻。

这样对比下来,仅就更新操作:Join 父子文档是独立的,可以独立更新;而 Nested 嵌套文档需要全文档进行重建(类似:reindex 操作)。

4.3 为什么 Nested 写入和更新操作会很慢?

当需要:新增数据、修改数据的时候,看似更新子文档,实际整个document 都需要重建(类似:reindex 操作),这是更新慢的根源。

因为频繁的更新会产生很多的嵌套文档,则创建的 Lucene 文档量会很大。

5、Nesed 选型注意事项

第一:如果需要索引对象数组而不是单个对象,请先考虑使用嵌套数据类型Nested。

第二:Object、Nested 选型注意:如果不需要对 Nested 子文档精确搜索的就选型 object,需要的选型 Nested。

第三 :对于子文档相对更新不频繁的场景,推荐使用:Nested 类型。注意:Nested 需要 Nested 专属 query,Nested 专属聚合实现检索和聚合操作。

第四:对于子文档频繁更新的场景,推荐使用 Join 父子文档,其特点是:父、子文档分离,但在同一分片上,写入性能能相对快,但检索性能较 Nested 更慢。

Join 类型检索的结果不能同时返回父子文档,一次 join 查询只能返回一种类型的文档(除非:inner_hits)。

第五:早期版本 Github issue 有提及:inner_hits 检索的性能问题,新版本已有改善,但使用也要注意,使用前做一下:不加 inner_hits 和加 inner_hits 的响应时间比较。

https://github.com/elastic/elasticsearch/issues/14229

第六:为避免 Nested 造成的索引膨胀,需要灵活结合如下两个参数,合理设置索引或者模板。

更新 Mapping 操作如下:

PUT products/_settings
{"index.mapping.nested_fields.limit": 10,"index.mapping.nested_objects.limit": 500
}

index.mapping.nested_fields.limit 含义:一个索引中不同的 Nested 字段类型个数。

如果超出,会报错如下:

  "reason" : "Limit of nested fields [1] has been exceeded"

index.mapping.nested_objects.limit 含义:一个 Nested 字段中对象数目,多了可能导致内存泄露。

这个字段,在我验证的时候,没有达到预期,后面我再通过留言补充完善。

第七:选型 Nested 类型或者 Join 类型,就势必提前考虑性能问题,建议多做一些压力测试、性能测试。

6、小结

多表关联是很多业务场景的刚需。但,选型一定要慎重,了解一下各种多表关联类型:Nested、Join 的底层存储和逻辑,能有助于更好的选型。

Nested 本质:将 Nested 对象作为隐藏的多个子文档存储,一次更新或写入子文档操作会需要全部文档的更新操作。

上周末深圳的 meetup 提及:整合 mongoDB + ES 的解决方案(见文末社区参考链接),mongo DB 实现了多表融合,也就是大宽表一步到位,本质是:空间换时间的方案。该方案我认为脑洞非常大,如果业务层面可行,大家可以借鉴。

您使用 Nested 遇到哪些问题?欢迎留言交流。

参考

  • https://medium.com/codex/learn-advanced-crud-and-search-queries-for-nested-objects-in-elasticsearch-from-practical-examples-7aebc1408d6f

  • https://discuss.elastic.co/t/whats-nested-documents-layout-inside-the-lucene/59944

  • https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html

  • https://discuss.elastic.co/t/nested-types-are-slower/90546

  • https://elasticsearch.cn/slides/284

推荐

1、Elasticsearch 7.X 进阶实战私训课

2、如何系统的学习 Elasticsearch ?

3、全网首发!《 Elasticsearch 最少必要知识教程 V1.0 》低调发布

4、从实战中来,到实战中去——Elasticsearch 技能更快提升方法论

5、刻意练习 Elasticsearch 10000 个小时,鬼知道经历了什么?!

6、干货 | 拆解一个 Elasticsearch Nested 类型复杂查询问题

7、干货 | Elasticsearch Nested类型深入详解

更短时间更快习得更多干货!

中国50%+Elastic认证工程师出自于此!

比同事抢先一步学习进阶干货!

Elasticsearch Nested 选型,先看这一篇!相关推荐

  1. ElasticSearch中文分词,看这一篇就够了

    写在前面:我是「且听风吟」,目前是某上市游戏公司的大数据开发工程师,热爱大数据开源技术,喜欢分享自己的所学所悟,现阶段正在从头梳理大数据体系的知识,以后将会把时间重点放在Spark和Flink上面. ...

  2. msp430中如何连续对位进行取反_图像视觉|相机、镜头、光源如何选型?看完这篇你就懂了...

    一.视觉系统原理描述 机器视觉就是用机器代替人眼来做测量和判断.机器视觉系统是指通过机器视觉产品(即图像摄取装置,分 CMOS 和CCD 两种)将被摄取目标转换成图像信号,传送给专用的图像处理系统,根 ...

  3. Elasticsearch 的使用,看这一篇就够了!

    前两天看到曹政大佬的文章,说他上个世纪末在广州做 PHP 程序员的时候,接到一个私活儿. 有个客户是开律所的,要做个法律查询的网站.他整了个 Mysql,把内容导进去,写个搜索查询语句就搞定了.客户觉 ...

  4. api网关选型_如何轻松打造百亿流量API网关?看这一篇就够了(下)

    如何轻松打造百亿流量API网关?看这一篇就够了(上) 上篇整体描述了网关的背景,涉及职能.分类.定位环节,本篇进入本文的重点,将会具体谈下百亿级流量API网关的演进过程. 准备好瓜子花生小板凳开始积累 ...

  5. Elasticsearch架构选型指南——不止是搜索引擎,还有......

    最近被咨询到"ETC 卡口数据的存储以及车流量分析.车路线分析业务场景是否适合 Elasticsearch 去做"的问题. 这个问题涉及 Elasticsearch 架构选型的问题 ...

  6. mos管开关电路_MOS管的知识,看这一篇就可以了

    原标题:MOS管的知识,看这一篇就可以了 今天的文章简单总结一下MOS管,如下是本文目录. ▉ 场效应管分类 场效应管分为结型(JFET)和金属-氧化物-半导体型(MOSFET)两种类型. JFET的 ...

  7. Redis看这一篇就够了

    大数据时代NoSQL开始大行其道,其中常用于缓存的Redis可谓风头正盛,是大小公司技术架构中必不可少的一种中间件,也是职场技术同仁们必知必会的一种技术.本场Chat将从各个方面对Redis进行全面的 ...

  8. 【硬见小百科】看完这篇,请不要再说不懂MOSFET!

    [硬见小百科]看完这篇,请不要再说不懂MOSFET! 云创硬见 2020-04-24 10:27 01 认识功率器件 1.1 功率半导体器件在工业 .消费 .军事等领域都有着广泛应用 ,具有很高的战略 ...

  9. Spring事务传播属性有那么难吗?看这一篇就够了

    点击上方"后端技术精选",选择"置顶公众号" 技术文章第一时间送达! 作者:不学无数的程序员 juejin.im/post/5da6eee2f265da5bb9 ...

  10. Spring 事务传播属性有那么难吗?看这一篇就够了!

    尊重原创,原文链接 学习东西要知行合一,如果只是知道理论而没实践过,那么掌握的也不会特别扎实,估计过几天就会忘记,接下来我们一起实践来学习Spring事务的传播属性. 传播属性 传播属性定义的是当一个 ...

最新文章

  1. VS2010安装项目的系统必备中添加.NET 2.0
  2. 西霞口船业公司疑遭外商合谋欺诈
  3. java jcheckbox事件_JAVA事件-----JCheckBox和JRadioButton事件响应
  4. 多个输出用java怎么写_请问用java写程序怎么输出这两个图形
  5. java 方法 示例_Java集合syncedSet()方法与示例
  6. 服务器配置列表在哪个文件夹,FolderMagic
  7. 【论文】Awesome Relation Extraction Paper(关系抽取)(PART IV)
  8. 机械优化设计进退法c语言程序,机械优化设计powell法程序
  9. PHP字符串部分方法
  10. 堆排序时间复杂度计算
  11. 停车位配建标准:北上广深
  12. java:xml数据转json
  13. 数据科学和人工智能技术笔记 二十、数据可视化
  14. 怎么把文字转换成语音?如何将文字变成音频呢?
  15. 又一款5G旗舰:vivo NEX 3S瞄准高端市场
  16. AndroidStudio输入生日计算星座
  17. 怪盗基德的滑翔翼 线性DP 最长上升子序列
  18. 静态HTML页面的参数的获取
  19. 怎么加入到开源社区,开心做开源
  20. Python property函数:定义属性

热门文章

  1. 物联网协议之NBIOT
  2. 使用scrapy爬取拉钩网招聘信息
  3. 视频剪辑怎么学?四个方面要注意,整体思路是关键
  4. vue怎么制作甘特图——dhtmlx-gantt
  5. 中兴Nubia Z5S mini一键ROOT教程 获取ROOT权限
  6. 图像处理之颜色检测分类标记(Python OpenCV实现)
  7. python的十句名言_程序员的二十句励志名言,看看你最喜欢哪句?
  8. PHP面向对象编程的基本概念定义操作属性方法
  9. E4A(易安卓)学习——第一个APP
  10. javaweb实现个人博客系统