- 浏览: 2189182 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (682)
- 软件思想 (7)
- Lucene(修真篇) (17)
- Lucene(仙界篇) (20)
- Lucene(神界篇) (11)
- Solr (48)
- Hadoop (77)
- Spark (38)
- Hbase (26)
- Hive (19)
- Pig (25)
- ELK (64)
- Zookeeper (12)
- JAVA (119)
- Linux (59)
- 多线程 (8)
- Nutch (5)
- JAVA EE (21)
- Oracle (7)
- Python (32)
- Xml (5)
- Gson (1)
- Cygwin (1)
- JavaScript (4)
- MySQL (9)
- Lucene/Solr(转) (5)
- 缓存 (2)
- Github/Git (1)
- 开源爬虫 (1)
- Hadoop运维 (7)
- shell命令 (9)
- 生活感悟 (42)
- shell编程 (23)
- Scala (11)
- MongoDB (3)
- docker (2)
- Nodejs (3)
- Neo4j (5)
- storm (3)
- opencv (1)
最新评论
-
qindongliang1922:
粟谷_sugu 写道不太理解“分词字段存储docvalue是没 ...
浅谈Lucene中的DocValues -
粟谷_sugu:
不太理解“分词字段存储docvalue是没有意义的”,这句话, ...
浅谈Lucene中的DocValues -
yin_bp:
高性能elasticsearch ORM开发库使用文档http ...
为什么说Elasticsearch搜索是近实时的? -
hackWang:
请问博主,有用solr做电商的搜索项目?
Solr中Group和Facet的用法 -
章司nana:
遇到的问题同楼上 为什么会返回null
Lucene4.3开发之第八步之渡劫初期(八)
前面文章介绍了,在es里面的几种数据组织关系,包括array[object],nested,以及今天要说的Parent-Child。
Parent-Child与Nested非常类似,都可以用来处理一对多的关系,如果多对多的关系,那就拆分成一对多在处理。前面提到nested的缺点是对数据的更新需要reindex整个nested结构下的所有数据,所以注定了它的使用场景一定是查询多更新少的场景,如果是更新多的场景,那么nested的性能未必会很好,而Parent-Child就非常适合在更新多的场景,因为Parent-Child的数据存储都是独立的,只要求父子文档都分布在同一个shard里面即可而nested模式下,不仅要求在同一个shard下还必须是同一个sengment里面的同一个block下,这种模式注定了nested查询的性能要比Parent-Child好,但是更新性能就大大不如Parent-Child了,对比nested模式,Parent-Child主要有下面的几个特点:
(1) 父文档可以被更新,而无须重建所有的子文档
(2)子文档的添加,修改,或者删除不影响它的父文档和其他的子文档,这尤其是在子文档数量巨大而且需要被添加和更新频繁的场景下Parent-Child能获取更好的性能
(3)子文档可以被返回在搜索结果里面
ElasticSearch在内存里面维护了一个父子关系的映射表,以便于能够加速查询,这种映射使用的是doc-value,如果数据量巨大内存放不下,会自动的保存到磁盘中,当然此时性能也会下降。
下面来看一个例子,首先我们要定义mapping:
{ "order": 0, "template": "pc_test*", "settings": { "index": { "number_of_replicas": "0", "number_of_shards": "3" } }, "mappings": { "employee": { "_parent": { "type": "branch" } }, "branch": {} }, "aliases": {} }
branch:代表一个分公司
employee:代表员工
关系: 一个公司可以包含多个员工
下面开始插入数据,首先我们先插入公司数据:
POST /company/branch/_bulk { "index": { "_id": "london" }} { "name": "London Westminster", "city": "London", "country": "UK" } { "index": { "_id": "liverpool" }} { "name": "Liverpool Central", "city": "Liverpool", "country": "UK" } { "index": { "_id": "paris" }} { "name": "Champs Élysées", "city": "Paris", "country": "France" }
注意插入公司数据的type是branch,数据的id用的是city字段,
添加员工数据的时候,要指定的父文档是属于哪个,这样才能把父子数据给关联到同一台机器上。
PUT /company/employee/1?parent=london { "name": "Alice Smith", "dob": "1970-10-24", "hobby": "hiking" }
parent id字段有两个用途:
(1)它创建了连接父子文档的关系并且确保了子文档一定和父文档存在一个shard里面
(2)默认情况下es用的是文档的id字段进行hash取模分片的,如果父文档的id字段被指定,那么路由字段就是id,而在子文档中我们指定parent的值也是父文档的id字段,所以就一定确保了父子文档都在一个shard里面,在父子文档的关系中,index,update,add,delete包括search在使用的时候都必须设置路由字段,否则查询结果会出错。
继续插入子文档:
POST /company/employee/_bulk { "index": { "_id": 2, "parent": "london" }} { "name": "Mark Thomas", "dob": "1982-05-16", "hobby": "diving" } { "index": { "_id": 3, "parent": "liverpool" }} { "name": "Barry Smith", "dob": "1979-04-01", "hobby": "hiking" } { "index": { "_id": 4, "parent": "paris" }} { "name": "Adrien Grand", "dob": "1987-05-11", "hobby": "horses" }
注意:如果parent的值改变了,必须删除这个parent下面的所有子文档然后删除本身,最后添加新的父文档,再添加新的子文档,否则parent值改变后,父文档的parent改变了,子的没改变会出现父子不在同一个shard里面,从而导致查询出错。
下面来看下,如何查询父子关系的数据,这里面主要有两个查询方法:
(1)has_child
使用子文档的字段当成查询条件,查询出符合条件的父文档的数据
一个查询例子如下:
GET /company/branch/_search { "query": { "has_child": { "type": "employee", "query": { "range": { "dob": { "gte": "1980-01-01" } } } } } }
这里面关于父文档的score,是由所有子文档的评分通过一个计算方法得来的,这里可以设置,有5种策略:
none:忽略评分
avg:所有子文档的平均分
min:所有子文档的最小分
max:所有子文档的最大分
sum:所有子文档的得分和
通过下面的查询,可以看出评分对排序的影响:
GET /company/branch/_search { "query": { "has_child": { "type": "employee", "score_mode": "max", "query": { "match": { "name": "Alice Smith" } } } } }
得分设置为none拥有更快的查询性能,因为少了额外的计算
此外has_child查询还可以接受两个限制参数min_children和max_children,在查询的时候根据子文档的个数做过滤,看下面的一个例子:
GET /company/branch/_search { "query": { "has_child": { "type": "employee", "min_children": 2, "query": { "match_all": {} } } } }
上面的查询仅仅查询最子文档个数符合过滤条件的父文档,has_child也可以使用filter查询。
(2)has_parent
has_parent查询和has_child相反,通过查询父文档的字段,从而得到子文档的数据。
一个例子如下:
GET /company/employee/_search { "query": { "has_parent": { "type": "branch", "query": { "match": { "country": "UK" } } } } }
has_parent也支持score_mode,有两种设置一个none,一个score因为每个child只有一个parent,所以不需要做聚合的评分。
最后看下parent-child的聚合,一个例子:
GET /company/branch/_search { "size" : 0, "aggs": { "country": { "terms": { "field": "country" }, "aggs": { "employees": { "children": { "type": "employee" }, "aggs": { "hobby": { "terms": { "field": "hobby" } } } } } } } }
上面聚合的意思是:
按国家分组,然后算组内的员工再根据其爱好进行分组
最后,parent-child模式,支持多层的关系
一个对多对多,目前官网上给出了3层关系的例子,从社区上来看说是支持无限层级的关系映射,但是超过3层的映射,官网没有给出使用例子,具体的使用还得使用者去测试,不过现实情况包含3级以上的关系数据应该非常少了。
一个的3级例子的mapping:
PUT /company { "mappings": { "country": {}, "branch": { "_parent": { "type": "country" } }, "employee": { "_parent": { "type": "branch" } } } }
多了一级国家的映射,总体的关系是:
一个国家可以有多个分公司,每个分公司又可以有多个员工
看下,数据例子:
(1)先插入国家数据
POST /company/country/_bulk { "index": { "_id": "uk" }} { "name": "UK" } { "index": { "_id": "france" }} { "name": "France" }
(2)在插入公司数据
POST /company/branch/_bulk { "index": { "_id": "london", "parent": "uk" }} { "name": "London Westmintster" } { "index": { "_id": "liverpool", "parent": "uk" }} { "name": "Liverpool Central" } { "index": { "_id": "paris", "parent": "france" }} { "name": "Champs Élysées" }
注意parent是父的,公司的route用的是city
(3)插入员工数据
PUT /company/employee/1?parent=london&routing=uk { "name": "Alice Smith", "dob": "1970-10-24", "hobby": "hiking" }
第三层的插入数据用了parent字段来确保和父文档的关联,又用了routding字段来确保和父文档,祖父文档位于同一个shard里面。
注意如果超过3层,routing字段一定最顶层的文档的路由值,而parent字段则是其真正的关联的父文档。超过3层的映射官网没有给出例子,具体是否是那样用的,有兴趣的朋友可以自行测试,多层的父子关系会消耗更多的内存,以及性能更糟糕所以设计上应该尽量避免出现这种情况,此外如果非得设计,注意parent id字段应该尽量短的,从而在doc value中获的更好的压缩以减少使用的内存。
参考文章:
[url]https://discuss.elastic.co/t/would-it-be-possible-the-relation-grate-grandparent-grate-grandchild-in-elasticsearch/26875/4
[/url]
发表评论
-
复盘一个Elasticsearch排序问题的剖析
2019-07-15 21:12 1199最近线上的es查询的 ... -
elasticsearch里面bulk的用法
2018-04-09 20:23 1427上篇文章介绍了在es里 ... -
elasticsearch里面的关于批量读取mget的用法
2018-04-04 16:01 1839es的api除了提供了基本 ... -
elasticsearch的查询流程分析
2018-04-02 20:29 1333我们都知道es是一个分 ... -
如何在elasticsearch里面使用深度分页功能
2018-03-28 18:13 2030前面的文章提到过es默认的from+size的分页方式返回的结 ... -
如何在Elasticsearch里面使用索引别名
2018-03-27 20:37 1684在elasticsearch里面给index起一个alias ... -
如何优雅的全量读取Elasticsearch索引里面的数据
2018-03-26 20:27 7660### (一)scroll的介绍 有时候我们可能想要读取整个 ... -
关于elaticsearch中更新数据的几种方式
2018-03-21 19:00 972作为一个成熟的框架, ... -
Elasticsearch里面的segment合并
2018-03-20 17:50 2102通过前面的文章,我 ... -
Elasticsearch如何保证数据不丢失?
2018-03-19 20:52 2147上篇文章提到过,在elasticsearch和磁盘之间还有一层 ... -
为什么说Elasticsearch搜索是近实时的?
2018-03-16 19:41 9478通过前面两篇文章的介绍,我们大概已经知道了 Elasticse ... -
Elasticsearch如何动态维护一个不可变的倒排索引
2018-03-15 21:34 1144上一篇文章中介绍了Elasticsearch中是如何搜索文本 ... -
Elasticsearch如何检索数据
2018-03-14 20:11 1098我们都知道Elasticsearch是一个全文检索引擎,那么它 ... -
如何备份ElasticSearch索引数据到HDFS上
2018-02-09 18:19 2428在ElasticSearch里面备份策略已经比较成熟了 ... -
Elasticsearch5.6.4集群搭建
2018-02-07 20:13 1346本次搭建的是一个三节点的集群 (一)es的安装 (1)下 ... -
如何使log4j生成json格式的log
2017-09-15 17:44 3852使用java开发项目时,log日志一般都是应用程序必不可少的一 ... -
简述ElasticSearch里面复杂关系数据的存储方式
2017-08-18 20:10 2417在传统的数据库里面,对数据关系描述无外乎三种,一对一,一对多和 ... -
使用Java Rest Client操作Elasticsearch
2017-08-09 19:42 2275Elasticsearch作为一个成熟的开源框架,对主流的多种 ... -
ElasticSearch里面的偏好查询
2017-06-22 17:17 1307在es查询的时候我们可 ... -
ElasticSearch里面的路由功能介绍
2017-06-21 18:17 2252在ElaticSearch里面,路由 ...
相关推荐
**Elasticsearch Parent-Child 关系理解与应用** 在Elasticsearch中,Parent-Child关系是一种特殊的数据模型,用于处理一对多的关系,如一篇文章(Parent)有多个评论(Child)。这种关系模型允许我们对子文档进行...
在这个特定的场景中,我们关注的是一个自定义的"elasticsearch join 插件",这个插件是基于Elasticsearch的parent-child关系进行改进的,新增了字段join功能。 在Elasticsearch原生的parent-child关系中,数据被...
Boost the searching capabilities of your system through synonyms, multilingual data handling, nested objects and parent-child documents Deep dive into the world of data aggregation and data analysis ...
深入源码有助于理解Elasticsearch内部工作机制,例如使用Guice进行依赖注入和模块化设计。 **十九、Index流程** 了解索引流程有助于优化索引性能,包括文档的分析、存储和索引构建等步骤。 综上所述,掌握Elastic...
09-6 -nested_vs_parent_child.avi 09-7 -reindex.avi 09-8 其他建议.avi 10-1 生产环境部署建议.avi 10-2 写性能优化.avi 10-3 读性能优化.avi 10-4 如何设定shard数.avi 10-5 xpack监控功能介绍.avi 11-1 入门及...
Elasticsearch 功能强大,但对于新手来说却很难理解。 这个示例应用程序旨在让用户更容易地获得插件在映射、索引和通过 ES 搜索方面实际启用的功能。如何为了充分理解用本项目实现的不同案例之间的关系,建议按以下...
- **parent-child文档关系处理**:讲解如何在Elasticsearch中建立和查询parent-child文档关系,适用于某些特定的数据模型。 - **脚本使用**:介绍如何使用脚本来执行复杂的逻辑操作,如动态计算字段值等。 #### 第...
ElasticSearch是一款基于Lucene构建的开源搜索引擎,它提供了分布式的全文搜索功能,常用于大...这表明文档不仅提供了理论知识,还包含了丰富的实践经验,能够帮助开发者更深入地理解和使用ElasticSearch Java API。
GET /parent-index/_left{ "query": { "match": { "productName": "상품 조회" } }, "from": 0, "size": 10000, "join": { "index": "child-index", "parent": "bundleKey", "child": "bundleKey", "query": { "mat...
- 有些名词复数形式有特殊变化,例如:child--children,mouse--mice,man--men,woman--women。 通过以上知识点的学习,学生应该能够更熟练地谈论自己的家庭,构建和理解 Family Tree,并掌握如何在句子中正确...
jQuery1.2 API 中文版折叠展开折叠全部展开全部 英文说明 核心jQuery 核心函数 jQuery(expression,[context]) jQuery(expression,[context]) 这个函数接收一个包含 CSS 选择器的字符串,然后用这个字符串去匹配一组...
- 特殊的不规则变化,如child->children,man->men,woman->women 通过这些知识点的学习,学生能够更熟练地表达和讨论家庭成员,增强语言表达的丰富性和准确性,同时也能增进对中西方家庭文化差异的理解。
The author has charged in a previous article that child psychotherapy is es- sentially an expensive illusion with regard to the great majority of children referred to private therapists and to ...
1. 名词复数形式:名词变复数有固定规则,如一般情况下加-s(parent -> parents),以s、x、ch、sh结尾的加-es(bus -> buses),以元音+y结尾的变y为i再加-es(child -> children),不规则名词变化(life -> lives...
这些规则和练习题帮助我们理解和掌握可数名词单数变复数的基本规律。在实际应用中,还需要注意一些不规则变化的名词,如child -> children,man -> men,woman -> women等。通过不断练习,可以提高对名词复数形式的...
let child = Object.create(parent); child.name; // 输出 "Parent" ``` 在压缩包中的`Base.js`文件可能包含了一个基础类或者对象的实现,用于演示或作为其他类的基础。这个文件可能定义了一些基本的属性和方法,...
console.log('Log from parent constructor'); }, { foo: function() { return 42; } }); var ChildClass = CG(function() { console.log('Log from child constructor'); }, { getMeaning: function() { ...
- `family tree`:家谱,用来记录家族成员关系的图表。 - `in the first photo` 和 `in the next picture`:用于描述在不同照片中的内容。 2. **Grammar Points**: - `This is … .These are … .`: 用于介绍离...
div.parent div.child { /* 选择父div下的子div */ } /* 使用逻辑运算符 or */ .button.primary, .button.secondary { /* 选择类为primary或secondary的按钮 */ } ``` 通过学习和分析这个项目的源代码,你可以...
在这个例子中,`Child`类通过`Parent.call(this, name)`继承了`Parent`类的属性,同时`Child.prototype`指向了`Parent.prototype`的一个新副本,从而继承了`Parent`类的方法。这种方式既保留了父类的实例属性,又...