Elasticsearch: nested对象
在处理大量数据时,关系数据库存在很多问题。 无论是速度,高效处理,有效并行化,可扩展性还是成本,当数据量开始增长时,关系数据库都会失败。该关系数据库的另一个挑战是必须预先定义关系和模式。Elasticsearch也是一个NoSQL文档数据存储。 但是,尽管是一个NoSQL数据存储,Elasticsearch在一定程度上提供了很多帮助来管理关系数据。 它支持类似SQL的连接,并且在嵌套和相关的数据实体上工作得非常棒。
比如,对于一个像下面的blog形式的文档:
一个blog可能对应于很多的comments,或者一个员工对应于很多的经验。这种数据就是关系数据。使用Elasticsearch,您可以通过保留轻松地工作与不同实体的关联以及强大的全文搜索和分析。 Elasticsearch通过引入两种类型的文档关系模型使这成为可能:
- nested 关系: 在这种关系中,这种一对多的关系存在于同一个文档之中
- parent-child 关系:在这种关系中,它们存在于不同的文档之中。
这两种关系在同一个模式下工作,即一对多个的关系。一个root或parent可以有一个及多个子object。
如上图所示,在嵌套关系中,有一个根对象,它是我们拥有的主文档,它包含一个称为嵌套文档的子文档数组。 根对象内的文档嵌套级别没有限制。 例如,查看以下JSON以进行多级嵌套:
{
"location_id": "axdbyu",
"location_name": "gurgaon",
"company": [
{
"name": "honda",
"modelName": [
{ "name": "honda cr-v", "price": "2 million" }
]
}, {
"name": "bmw",
"modelName": [
{ "name": "BMW 3 Series", "price": "2 million"},
{ "name": "BMW 1 Series", "price": "3 million" }
]
} ]
}
下面,我们来做一个例子来展示一下为什么nested对象可以解决我们的问题。
Object数据类型
我们首先创建一个叫做developer的index,并输入如下的两个数据:
POST developer/_doc/101
{
"name": "zhang san",
"skills": [
{
"language": "ruby",
"level": "expert"
},
{
"language": "javascript",
"level": "beginner"
}
]
}
POST developer/_doc/102
{
"name": "li si",
"skills": [
{
"language": "ruby",
"level": "beginner"
}
]
}
上面显示是一对多的一个index。
Object Query
这个时候我们想搜一个skills: language是ruby,并且level是biginner的文档。我们可能想到的方法是:
GET developer/_search
{
"query": {
"bool": {
"filter": [
{
"match": {
"skills.language": "ruby"
}
},
{
"match": {
"skills.level": "beginner"
}
}
]
}
}
}
通过上面的搜寻,我们得到的结果是:
{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.0,
"hits" : [
{
"_index" : "developer",
"_type" : "_doc",
"_id" : "101",
"_score" : 0.0,
"_source" : {
"name" : "zhang san",
"skills" : [
{
"language" : "ruby",
"level" : "expert"
},
{
"language" : "javascript",
"level" : "beginner"
}
]
}
},
{
"_index" : "developer",
"_type" : "_doc",
"_id" : "102",
"_score" : 0.0,
"_source" : {
"name" : "li si",
"skills" : [
{
"language" : "ruby",
"level" : "beginner"
}
]
}
}
]
}
}
我们可以看到,我们得到两个结果。但是我们仔细查看一下发现得到的结果并不是我们想得到的。从我们的原意来说,我们想得到的是li si,因为只有li si这个人的language是ruby,并且他的level是biginner。zhang san这个文档,应该不在搜寻之列。这是为什么呢?
原来,langauge及level是skills的JSON内部数组项。当JSON对象被Lucene扁平化后,我们失去了language和level之间的对应关系。取而代之的是如下的这种关系:
{
"name": "zhang san",
"skills.language" :["ruby", "javascript"],
"skills.level": ["expert", "beginner"]
}
如上所示,我们看到的是一个扁平化的数组。之前的那种language和level之间的那种对应关系已经不存在了。
Object aggregation
同样的问题也存在于aggregation中,比如我们想做一下的aggregation:
GET developer/_search
{
"size": 0,
"aggs": {
"languages": {
"terms": {
"field": "skills.language.keyword"
},
"aggs": {
"level": {
"terms": {"field": "skills.level.keyword"}
}
}
}
}
}
显示的结果是:
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"languages" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "ruby",
"doc_count" : 2,
"level" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "beginner",
"doc_count" : 2
},
{
"key" : "expert",
"doc_count" : 1
}
]
}
},
{
"key" : "javascript",
"doc_count" : 1,
"level" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "beginner",
"doc_count" : 1
},
{
"key" : "expert",
"doc_count" : 1
}
]
}
}
]
}
}
}
显然,对于key javascript来说,它并没有expert对应的level,但是在我们的aggregation里显示出来了。这个结果显然是错误的。
nested 数据类型
nested数据类型能够让我们对object数组建立索引,并且分别进行查询。
如果需要维护数组中每个对象的关系,请使用nested数据类型
为了能够把我们的数据定义为nested,我们必须修改之前的索引mapping为:
DELETE developer
PUT developer
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"skills": {
"type": "nested",
"properties": {
"language": {
"type": "keyword"
},
"level": {
"type": "keyword"
}
}
}
}
}
}
经过这样的改造之后,重新把我们之前的数据输入到index里:
POST developer/_doc/101
{
"name": "zhang san",
"skills": [
{
"language": "ruby",
"level": "expert"
},
{
"language": "javascript",
"level": "beginner"
}
]
}
POST developer/_doc/102
{
"name": "li si",
"skills": [
{
"language": "ruby",
"level": "beginner"
}
]
}
针对101,在Lucence中的数据结构变为:
{
"name": "zhang san",
{
"skills.language": "ruby",
"skills.level": "expert"
},
{
"skills.language": "javascript",
"skills.level", "beginner"
}
}
nested query
我们来重新做我们之前的搜索:
GET developer/_search
{
"query": {
"nested": {
"path": "skills",
"query": {
"bool": {
"filter": [
{
"match": {
"skills.language": "ruby"
}
},
{
"match": {
"skills.level": "beginner"
}
}
]
}
}
}
}
}
注意上面的“nested”字段。显示的结果是:
{
"took" : 5,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.0,
"hits" : [
{
"_index" : "developer",
"_type" : "_doc",
"_id" : "102",
"_score" : 0.0,
"_source" : {
"name" : "li si",
"skills" : [
{
"language" : "ruby",
"level" : "beginner"
}
]
}
}
]
}
}
显然,我们只得到了一个我们想要的结果。
nested aggregation
同样,我们可以对我们的index来做一个aggregation:
GET developer/_search
{
"size": 0,
"aggs": {
"nested_skills": {
"nested": {
"path": "skills"
},
"aggs": {
"languages": {
"terms": {
"field": "skills.language"
},
"aggs": {
"levels": {
"terms": {
"field": "skills.level"
}
}
}
}
}
}
}
}
显示的结果是:
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"nested_skills" : {
"doc_count" : 3,
"languages" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "ruby",
"doc_count" : 2,
"levels" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "beginner",
"doc_count" : 1
},
{
"key" : "expert",
"doc_count" : 1
}
]
}
},
{
"key" : "javascript",
"doc_count" : 1,
"levels" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "beginner",
"doc_count" : 1
}
]
}
}
]
}
}
}
}
从上面显示的结果,可以看出来对于ruby来说,它分别对应于一个bigginer及一个expert。这个和我们之前的数据是一样的。对于javascript来说,它只有一个beginner的level。
Elasticsearch: nested对象的更多相关文章
- elasticsearch 嵌套对象之嵌套类型
nested类型是一种特殊的对象object数据类型(specialised version of the object datatype ),允许对象数组彼此独立地进行索引和查询. 1. 对象数组如 ...
- elasticSearch nested exist与missing查询
elasticSearch nested查询,简单意义上,你可以理解为,它不会被索引,只是被暂时隐藏起来,而查询的时候,开关就是使用nested query/filter去查询 下面我有一个例子,是查 ...
- 干货 | Elasticsearch Nested类型深入详解(转)
https://blog.csdn.net/laoyang360/article/details/82950393 0.概要在Elasticsearch实战场景中,我们或多或少会遇到嵌套文档的组合形式 ...
- 干货 | Elasticsearch Nested类型深入详解
在Elasticsearch实战场景中,我们或多或少会遇到嵌套文档的组合形式,反映在ES中称为父子文档. 父子文档的实现,至少包含以下两种方式: 1)父子文档 父子文档在5.X版本中通过parent- ...
- elasticsearch 嵌套对象使用Multi Match Query、query_string全文检索设置
参考: https://www.elastic.co/guide/en/elasticsearch/reference/1.7/mapping-nested-type.html https://sta ...
- elasticsearch嵌套对象的映射
在es中,我们有时候可能需要映射,{ "field" : "xx" , "field01" : [] }这样格式的嵌套对象,默认情况下es会 ...
- elasticsearch nested查询
项目里可能会遇到多级嵌套的情况,实际上最多两级,三级及以上,我测试不通过. 一级索引时,我插入数据,会自动创建索引映射:然二级时,索引映射必须手动创建. 映射: PUT test999 { " ...
- Elastic search中使用nested类型的内嵌对象
在大数据的应用环境中,往往使用反范式设计来提高读写性能. 假设我们有个类似简书的系统,系统里有文章,用户也可以对文章进行赞赏.在关系型数据库中,如果按照数据库范式设计,需要两张表:一张文章表和一张赞赏 ...
- 第三百六十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)用Django实现搜索的自动补全功能
第三百六十八节,Python分布式爬虫打造搜索引擎Scrapy精讲—用Django实现搜索的自动补全功能 elasticsearch(搜索引擎)提供了自动补全接口 官方说明:https://www.e ...
随机推荐
- EventBus使用的坑
最近使用eventbus发送通知,在想该怎么携带List集合数据.于是尝试直接发送List. 使用一次,正常接收.使用两次,出现类转换异常.原来在接收List类型的消息时,并不会管List内的泛型,是 ...
- 19年最新 Python0基础学习书籍推荐(内涵PDF地址以及书籍源码)
去年看过一篇文章,是关于18年的最适合0基础学习的书籍,今年,最新的书籍也已经统计出来.书籍的PDF太过于难找,所以很多PDF都找不到. 仅仅只能找到英文版PDF 本文章统计了18.19并做过对比,在 ...
- 利用Python进行数据分析_Pandas_处理缺失数据
申明:本系列文章是自己在学习<利用Python进行数据分析>这本书的过程中,为了方便后期自己巩固知识而整理. 1 读取excel数据 import pandas as pd import ...
- go 结构的方法2
你可以对包中的 任意 类型定义任意方法,而不仅仅是针对结构体. 但是,不能对来自其他包的类型或基础类型定义方法. package main import ( "fmt" ...
- 16-MySQL DBA笔记-调优基础理论和工具
第五部分 性能调优与架构篇 本篇将为读者介绍性能调优的一些背景知识和理论,然后介绍一些工具的运用,最后介绍从应用程序到操作系统.到数据库.到存储各个环节的优化. 性能调优是一个高度专业的领域,它需要一 ...
- (一)JNDI基础
一.简介 在Tomcat 4.1.27之后,在服务器上就直接增加了数据源的配置选项,直接在服务器上配置好数据源连接池即可.在J2EE服务器上保存着一个数据库的多个连接.每一个连接通过DataSourc ...
- 使用ef core自动生成mysql表和数据编码的问题
mysql默认的编码是不支持中文的,需要改成utf8编码格式. 而我使用的Pomelo.EntityFrameworkCore.MySql组件生成mysql库和表,他是使用默认编码的. 网上大多说修改 ...
- linux安装tmux分屏插件
linuxtmux分屏 一.安装tmux 二.基本使用 三.鼠标操作 一.安装tmux yum install -y tmux TMUX2版本以下 二.基本使用 使用tmux一般使用命令和快捷键来操作 ...
- Python练习_初识函数_day9
1. 1.作业 1,写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者. 2,写函数,判断用户传入的对象(字符串.列表.元组)长度是否大于5. 3,写函数,检查 ...
- QTabWidget标签实现双击关闭(转)
重载了QTabWidget(由于tabBar()是protected),这样就可以获取到标签了. 1 class Tab : public QTabWidget 2 { 3 Q_OBJECT 4 pu ...