当前位置: 首页 > 图灵资讯 > 技术篇> ES数据打平或者flat扁平化 导致嵌套对象查询可能出错

ES数据打平或者flat扁平化 导致嵌套对象查询可能出错

来源:图灵教育
时间:2023-06-11 09:15:25

探索ES-对象和嵌套对象(3)前文回顾

上一篇文章写了探索ES-入门Kibana(2),基本完成了ElasticSearchKibana安装和基本概念。今天,让我们正式谈谈一些ElasticSearch使用中会遇到的问题和解决问题的方法。

引言

ElasticSearch作为一个Nosql其中一个特点是不支持数据库多表关联的。所以,在ElasticSearch中间的数据都是以反范式存储的方式。简单来说,它将被存储为一个大Json对象

对象数据在ElasticSearch中是作为object类型存储。但是,如果对象数据是数组,则在查询过程中会出现无法相关查询的问题。

不知道有没有朋友看到这里一脸懵比?

如果您不知道这是什么问题,请参见下面的例子。

如果你知道这是什么意思,请看下面的解决方案。

对象

举一个博客系统的例子。

假设我们要在那里ElasticSearch中建立一个blog索引。blog索引包括以下内容。

  • title:博客的标题
  • content:博客的内容
  • comment:博客的评论
  • comment.username:用户对博客进行评论
  • comment.content:博客评论的内容

不知道这里有没有人发现博客和评论是一对多的关系,没有发现也没关系,继续往下看。

根据上面分解的字段,我们在ElasticSearch建立以下索引。

PUT blog{  "mappings": {    "_doc": {      "properties": {        "blog": {          "properties": {            "title": {              "type": "keyword"            },            "content": {              "type": "text"            },            "comment": {              "properties": {                "content": {                  "type": "text"                },                "username": {                  "type": "keyword"                }              }            }          }        }      }    }  }}复制代码

可以发现blogcomment都是作为object存储类型。在ElasticSearch默认情况下,中会将字段作为object来存储。

我们插入一个文档。

PUT blog/_doc/1{  "blog": {    "title": "this is my first blog",    "content": "this is my first blog content",    "comment": {      "content": "so bad!",      "username": "li si"    }  }}复制代码

本文档的内容大致是有人写了一篇博客,然后李四同学在下面批评so bad

我们以评论为维度进行搜索。

GET blog/_search{  "query":{    "match": {      "blog.comment.content": "bad"    }  }}复制代码

可以搜索数据。

ES数据打平或者flat扁平化 导致嵌套对象查询可能出错_数据

扁平化

这里需要注意的是在ES中,对象数据最终会被flat(扁平化)

什么意思?

也就是说,上面的内容数据终于在了ES以下形式存储。

blog:this is my first blogcontent:this is my first blog contentcomment.content:so badcomment.username:li 复制代码的si

然而,一般来说,博客肯定不止一个数据。一般来说,会有多个数据,即上述一对多关系。

我们更新了以前的数据。

PUT blog/_doc/1{  "blog": {    "title": "this is my first blog",    "content": "this is my first blog content",    "comment": [      {        "content": "oh so good!",        "username": "zhang san"      },      {        "content": "so bad!",        "username": "zhang san"      },      {        "content": "so bad!",        "username": "li si"      }    ]  }}复制代码

以上数据的意思是,除了李四说bad之外,还有张三大哥说good。

根据之前的查询方法,我们也可以正常查询。但是,如果我们现在想联系查询,我们不仅要求评论员是李四,还要求李四说谷歌查询。让我们写一个bool查询。bool可以写多个查询,不管是不是term还是match只能写一个查询。

GET blog/_search{  "query": {    "bool": {      "must": [        {          "match": {            "blog.comment.content": "good"          }        },        {          "match": {            "blog.comment.username": "li si"          }        }      ]    }  }}复制代码

然而,我们仍然可以查询这些数据。显然,李四说的是bad而不是good。为什么还能查询?

ES数据打平或者flat扁平化 导致嵌套对象查询可能出错_elasticsearch_02

那是因为对象被扁平化后,在ES就是这样存储的。

blog.comment.content:["oh so good!","so bad!"]blog.comment.username:["zhang san","li si复制代码

两个字段都以数组的形式存储数据。数组和数组之间没有对应的关系。

ES先在blog.comment.coetent看看有没有good,发现有。再次发现blog.comment.username看看有没有li si发现还是有的。

最后,查询了这个数据。

那么如何实现相关查询呢?使用nested,嵌套对象即可。

嵌套对象

默认字段的类型是object使用类型nested需要显式指定。删除之前的索引后,重新建立索引。因为在ES在中间,我们无法修改以前的内容mapping,我们只能删除并重建它。如果需要以前的数据,可以使用reindex将数据导入新索引。

PUT blog{  "mappings": {    "_doc": {      "properties": {        "blog": {          "properties": {            "title": {              "type": "keyword"            },            "content": {              "type": "text"            },            "comment": {              "type":"nested",              "properties": {                "content": {                  "type": "text"                },                "username": {                  "type": "keyword"                }              }            }          }        }      }    }  }}复制代码

我们再次插入一个数据。

PUT blog/_doc/1{  "blog": {    "title": "this is my first blog",    "content": "this is my first blog content",    "comment": [      {        "content": "oh so good!",        "username": "zhang san"      },      {        "content": "so bad!",        "username": "zhang san"      },      {        "content": "so bad!",        "username": "li si"      }    ]  }}复制代码

我们进行相关搜索。

GET blog/_search{  "query": {    "bool": {      "must": [        {          "match": {            "blog.comment.content": "good"          }        },        {          "match": {            "blog.comment.username": "li si"          }        }      ]    }  }}复制代码

此时,我们发现我们无法搜索相应的数据。因为在这个时候,ESnested对象之间的关系被额外存储。

ES数据打平或者flat扁平化 导致嵌套对象查询可能出错_字段_03