目录
ES中处理关联关系
-
关系型数据库,一般会考虑Normalize数据,在ES中,往往考虑Denormalize数据
-
Denormalize的好处是:读的速度快/无需表连接/无需行锁
-
-
ES并不擅长处理关联关系,我们一般采用以下四种方法处理关联
-
对象类型
-
嵌套对象
-
父子关联关系
-
应用端关联
-
案例1:博客和其作者关系
- 对象类型
-
在每一博客的文档中都保留作者的信息
-
如果作者信息发生变化,需要修改相关的博客文档
-
#设置mapping
PUT /blog
{
"mappings": {
"properties": {
"content": {
"type": "text"
},
"time": {
"type": "date"
},
"user": {
"properties": {
"city": {
"type": "text"
},
"userid": {
"type": "long"
},
"username": {
"type": "keyword"
}
}
}
}
}
}
#插入blog数据
PUT blog/_doc/1
{
"content":"I like Elasticsearch",
"time":"2019-01-01T00:00:00",
"user":{
"userid":1,
"username":"Jack",
"city":"Shanghai"
}
}
#文章中包含elasticsearch 作者是jack的文章
POST /blog/_search
{
"query": {
"bool": {
"must": [
{"match": {
"content": "Elasticsearch"
}},
{"match": {
"user.username": "Jack"
}}
]
}
}
}
包含对象数组的文档
#设置Mappering
PUT my_movies
{
"mappings" : {
"properties" : {
"actors" : {
"properties" : {
"first_name" : {
"type" : "keyword"
},
"last_name" : {
"type" : "keyword"
}
}
},
"title" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
#插入数据
POST my_movies/_doc/1
{
"title":"Speed",
"actors":[
{
"first_name":"Keanu",
"last_name":"Reeves"
},{
"first_name":"Dennis",
"last_name":"Hopper"
}]
}
为什么会搜到不需要的结果???
-
存储时,内部对象并没有考虑在内,JSON格式被处理成扁平式键值对的结构
-
actors.first_name作为一个数组
-
actors.last_name作为一个数组
-
-
当多个字段进行查询时,导致了意外的搜索结果
-
可以用Nested Data Type解决这个问题
Nested Data Type
-
Nested数据类型: 允许对象数组中的对象被独立索引
-
使用nested和properties关键字,将所有actors索引到多个分隔的文档
-
在内部,Nested文档会被保存在两个Luene文档中,在查询时做Join处理
#添加mappering
PUT my_movies
{
"mappings": {
"properties": {
"actors": {
"type": "nested",
"properties": {
"first_name": {
"type": "keyword"
},
"last_name": {
"type": "keyword"
}
}
},
"title": {
"type": "text"
}
}
}
}
#添加数据
POST my_movies/_doc/1
{
"title":"Speed",
"actors":[
{
"first_name":"Keanu",
"last_name":"Reeves"
},{
"first_name":"Dennis",
"last_name":"Hopper"
}]
}
#Nest查询
POST /my_movies/_search
{
"query": {
"bool": {
"must": [
{
"nested":{
"path": "actors",
"query": {
"bool": {
"must": [
{"match": {"actors.first_name": "Keanu"}},{"match": {"actors.last_name": "Hopper"}}
]
}
}
}
}
]
}
}
}
嵌套查询
- 在内部,Nested文档被保存在两个Lucene文档中,会在查询时做Join处理
嵌套对象的聚合查询
-
按照first_name进行分组
#按照之前的方法发现不起作用
POST my_movies/_search
{
"size": 0,
"aggs": {
"actor_name": {
"terms": {
"field": "actors.first_name"
}
}
}
}
- 解决办法:对于嵌套对象进行聚合分析的时候,我们需要指定聚合的字段为nested 嵌套对象,并且指定路径 将我们的聚合分析,写到nested内的子聚合分析.可以看到我们的子聚合是进行聚合分析的,主聚合没有进行聚合分析工作
POST my_movies/_search
{
"size": 0,
"aggs": {
"actors": {
"nested": {
"path": "actors"
},
"aggs": {
"actor_name": {
"terms": {
"field": "actors.first_name",
"size": 10
}
}
}
},
"actor_name": {
"terms": {
"field": "actors.first_name"
}
}
}
}