Elasticsearch中object类型与nested类型以及数组之间的区别

这篇具有很好参考价值的文章主要介绍了Elasticsearch中object类型与nested类型以及数组之间的区别。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、区别:

0、一般情况下用object 类型来查es中为json对象的字段数据,用nested来查es中为JsonArray数组类型的字段数据。
1、默认情况下ES会把JSON对象直接映射为object类型,只有手动设置才会映射为nested类型

2、object类型可以直接使用普通的逗号(.)查询,比如

{
  "query": {
    "term": {
      "inspector.id": {
        "value": "222"
      }
    }
  }
}

3、nested类型的查询需要使用nested查询:

{
  "query": {
    "nested": {
      "path": "inspector",
      "query": {
        "term": {
          "inspector.id": {
            "value": "222"
          }
        }
      }
    }    
  }
}

4、两种查询方式不兼容,如果大家想做改动的话,需要对java程序进行修改,风险比较大。

5、存储方式不同。对象数组在后台是扁平化存储,嵌套对象数组是每个对象独立成文档存储。因此,对象数据有时会有"且"条件查询出"或"结果,嵌套对象的文档聚合可能会多计数(除非加reverse_nested),想保持数组中对象的独立性,就需要使用嵌套字段类型。

二、Object类型字段

1:mapping

注意,如果没有写明type,比如categoryObj,ES会默认object类型,并且就算查看mapping,也不会显示出来:

		// 所属类目,对象类型,注意这里没有写明type,ES则会默认为object
        "categoryObj": {
        	//"type":"object",
          "properties": {
            "class1": {
              "type": "keyword"
            },
            "class2": {
              "type": "keyword"
            },
            "class3": {
              "type": "keyword"
            }
          }
        }

2:增加数据

PUT test_index_20211220/e-com/1
{
  "id": "1",
  "name": "L'oreal/欧莱雅复颜玻尿酸水光充盈导入膨润精华液",
  "brand": "欧莱雅",
  "price": 279,
  "desc": "补水 提拉紧致 淡化细纹",
  "categoryObj": {
    "class1": "欧莱雅",
    "class2": "补水",
    "class3": "面部护理"
  }
}

3:查询

在样例数据中,“categoryObj"字段被默认设置为object类型(没有显示设置type),对于对象类型,在查询时需要用”."号连接整个字段:

GET test_index_20211220/_search
{
  "query": {
    "term": {
      "categoryObj.class1": "欧莱雅"
    }
  }
}

4:对象数组特性

我们知道了嵌套字段中的对象被ES存储为了独立的文档,那对象字段呢?ES在后台将对象字段进行打平处理,后台其实存储的是扁平结构,以categoryObj字段为例:

"categoryObj": [
    {
      "class1": "欧莱雅",
      "class2": "补水",
      "class3": "面部护理"
    },
    {
      "class1": "欧莱雅",
      "class2": "补水",
      "class3": "面部精华"
    },
     {
      "class1": "雅诗兰黛",
      "class2": "美白",
      "class3": "面霜"
    }
]

后台存储的其实是:

{
	"categoryObj.class1": ["欧莱雅","欧莱雅","雅诗兰黛"],
	"categoryObj.class2": ["补水","补水","美白"],
	"categoryObj.class3": ["面部护理","面部精华","面霜"]
}

这就牺牲了对象之间的独立性,有时候会带来一些影响,具体就是某些情况下,对对象数组的"且"查询可能会变成"或"查询。
这个时候我们去同时查询"欧莱雅"和"美白"这两个关键词,正常来说是不应该差出来任何文档的,因为categoryObj中没有任何一个对象同时具备"欧莱雅"和"美白"这两个关键词,可事实确不是这样:

GET test_index_20211220/_search
{
  "query": {
    "bool": {
      // filter上下文
      "filter": {
        "bool": {
          "must": [
            {
              "term": {
                "categoryObj.class1": "欧莱雅"
              }
            },
            {
              "term": {
                "categoryObj.class2": "美白"
              }
            }
          ]
        }
      }
    }
  }
}

结果居然将文档查询出来了
所以当字段为数组的时候,建议使用nested类型字段。

三、Nested类型字段

1:mapping

 		// 所属类目,嵌套类型
        "categoryNst": {
          "type": "nested",
          "properties": {
            "class1": {
              "type": "keyword"
            },
            "class2": {
              "type": "keyword"
            },
            "class3": {
              "type": "keyword"
            }
          }
        }

2:增加数据

PUT test_index_20211220/e-com/1
{
  "id": "1",
  "name": "L'oreal/欧莱雅复颜玻尿酸水光充盈导入膨润精华液",
  "brand": "欧莱雅",
  "price": 279,
  "desc": "补水 提拉紧致 淡化细纹",
  "categoryNst": {
    "class1": "欧莱雅",
    "class2": "补水",
    "class3": "面部护理"
  }
}

3:查询

GET test_index_20211220/_search
{
  "query": {
    "nested": {
      "path": "categoryNst",       #nested对象的查询深度
      "query": {
        "term": {
         // 在以前的版本中直接写 "class2": "补水"也是可以的,因为已经在外部声明了path
         // 不知道从哪个版本改了,现在必须写 "categoryNst.class2": "补水",否则报错
          "categoryNst.class2": "补水"
        }
      }
    }
  }
}

4: 嵌套字段的特性

嵌套字段其实是把其内部成员当做了一条独立文档进行了索引。如何理解这句话呢?在上面的数据中,"categoryNst"数组已经有两个对象成员了
ES在后台其实将这两个对象成员当成了两条独立文档进行索引,所以ES一共索引了3条文档(一条外部文档,两条嵌套字段对象的文档),这点可以从对嵌套字段的terms聚合中看出来:

GET test_index_20211220/_search
{
  "query": {
    "nested": {
      "path": "categoryNst",
      "query": {
        "term": {
          "categoryNst.class2": "补水"
        }
      }
    }
  },
  "aggs": {
    "nestedAgg":{
      "nested": {
        "path": "categoryNst"
      },
      "aggs": {
        "termAgg": {
          "terms": {
          	// 这里一样不能写成"class2",否则虽不报错,但聚合无结果。
            "field": "categoryNst.class2"
          }
        }
      }
    }
  }
}

{
  "took": 6,
  "timed_out": false,
  "_shards": {
    "total": 2,
    "successful": 2,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 0.18232156,
    "hits": [
      
    ]
  },
  "aggregations": {
    "nestedAgg": {
      "doc_count": 2,
      "termAgg": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
          {
            "key": "补水",
            "doc_count": 2
          }
        ]
      }
    }
  }
}

明明只有一条整体的文档,但聚合结果却是2,岂不是结果错误了?如何才能得到我们需要的结果呢?这个时候就要用到反转嵌套(reverse_nested),改写上面查询语句的聚合部分:

GET test_index_20211220/_search
{
  "size":0,
  "query": {
    "nested": {
      "path": "categoryNst",
      "query": {
        "term": {
          "categoryNst.class2": "补水"
        }
      }
    }
  },
  "aggs": {
    "nestedAgg":{
      "nested": {
        "path": "categoryNst"
      },
      "aggs": {
        "termAgg": {
          "terms": {
            "field": "categoryNst.class2"
          },
          "aggs": {
            "reverseAgg": {
              "reverse_nested": {}
            }
          }
        }
      }
    }
  }
}

5:java查询

 public static void main(String[] args) {
        //创建ES客户端
        RestHighLevelClient esClient = new RestHighLevelClient(
                RestClient.builder(new HttpHost("localhost", 9200, "http"))
        );

        //创建搜索对象
        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices("user");

        //构建请求体
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //查询数据-对nested类型数据查询
        searchSourceBuilder.query(
                QueryBuilders.nestedQuery("check_error", QueryBuilders.termsQuery("check_error.errtype", errtype), ScoreMode.None)
        );

        //发送请求
        searchRequest.source(searchSourceBuilder);
        SearchResponse search = null;
        try {
            search = esClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //解析结果
        SearchHits hits = search.getHits();
        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }

        //关闭ES客户端
        esClient.close();
    }

四、数组类型字段

1:mapping

ES中没有专门的数组类型,默认情况下任何字段都可以包含一个或者多个值,但一个数组中的值必须是同一种类型。

 		// 数组类型
        "comments": {
          "type": "keyword"
        }

2:增加数据

当数组类型字段(comments)中只有一个数据时:

GET test_index_20211220/e-com/1
{
  "_index": "test_index_20211220",
  "_type": "e-com",
  "_id": "1",
  "_version": 1,
  "found": true,
  "_source": {
    "id": "1",
    "name": "L'oreal/欧莱雅复颜玻尿酸水光充盈导入膨润精华液",
    "brand": "欧莱雅",
    "price": 279,
    "desc": "补水 提拉紧致 淡化细纹",
    "comments": "还没有用,赠品跟欧莱雅旗舰店的同款赠品有差异。味道也不一样"
  }
}

可以看到此时的comments还不是数组,现在我们增加一条评论,覆盖写入一次:

PUT test_index_20211220/e-com/1
{
  "id": "1",
  "name": "L'oreal/欧莱雅复颜玻尿酸水光充盈导入膨润精华液",
  "brand": "欧莱雅",
  "price": 279,
  "desc": "补水 提拉紧致 淡化细纹",
  "comments": [
    "还没有用,赠品跟欧莱雅旗舰店的同款赠品有差异。味道也不一样",
    "只有这支玻璃尿酸水光充盈是真的"
  ]
}

重新查询,可以看到,"commts"在索引的时候,如果有多个值,则会自动转化成了数组,且文档版本号+1:

GET test_index_20211220/e-com/1 
{
  "_index": "test_index_20211220",
  "_type": "e-com",
  "_id": "1",
  "_version": 2,
  "found": true,
  "_source": {
    "id": "1",
    "name": "L'oreal/欧莱雅复颜玻尿酸水光充盈导入膨润精华液",
    "brand": "欧莱雅",
    "price": 279,
    "desc": "补水 提拉紧致 淡化细纹",
    "comments": [
      "还没有用,赠品跟欧莱雅旗舰店的同款赠品有差异。味道也不一样",
      "只有这支玻璃尿酸水光充盈是真的"
    ]
  }
}

3:查询

此时数组类型就当做正常的字段进行查询即可文章来源地址https://www.toymoban.com/news/detail-814665.html

GET my_test_index/_search
{
  "query": {
    "bool": {
      "must": [
        {"terms": {
          "label": [
            "10",
            "100"
          ]
        }},{
          "term": {
            "name": {
              "value": "旺仔33333"
            }
          }
        }
      ]
    }
  }
}

到了这里,关于Elasticsearch中object类型与nested类型以及数组之间的区别的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Elasticsearch 基于 array 结构 的nested类型的索引的聚合查询

    这几天在做es的聚合查询,对那种一对多的产品数据查询的时候遇到了一些问题,做一下记录 针对每个产品名称[ product_name ]进行分组,并对预算[ budget ]求和 产品名称 预算 电视机 4000 手机 851 相机 5000 扑克牌 2 es查询语句==简化版 es查询的结果==简化版 注意电视机的doc_count为

    2024年02月16日
    浏览(45)
  • Elasticsearch 8.X 如何依据 Nested 嵌套类型的某个字段进行排序?

    这是来自社区的一个真实企业场景问题。 https://elasticsearch.cn/question/13135 如下所示, 希望在查出的结果后, 对结果进行后处理,对tags列表,根据depth进行排序。 Elasticsearch 能支持的排序方式罗列如下: 包含但不限于: 基于特定字段的排序 基于Nested对象字段的排序 基于特定

    2024年02月02日
    浏览(42)
  • <Java>Map<String,Object>中解析Object类型数据为数组格式

    背景 : 前端:入参为字符串和数组类型;通过json字符串传给后台, 后台:后台通过工具解析为MapString,Object,然后需要解析出Map里面的数组值做操作; 需求: 入参: { “addOrModify”: “add”, “hrBdName”: “陕西省”, “hrBdCode”: “1001”, “hrBuName”: [“宝鸡市”,“咸阳市”

    2024年02月15日
    浏览(25)
  • ts定义对象类型Record<string, any>;和object、Object的区别

    Record 是 TS 内置的一个高级类型,是通过映射类型的语法来生成索引类型的 比如传入 \\\'a\\\' | \\\'b\\\' 作为 key,1 作为 value,就可以生成这样索引类型: 所以这里的 Recordstring, any 也就是 key 为 string 类型,value 为任意类型的索引类型,可以代替 object 来用,更加语义化一点: Record 与

    2024年02月16日
    浏览(25)
  • 【Elasticsearch教程12】Mapping字段类型之object

    首先给出结论: 在一个字段存储 一个 JSON对象,可以选择 object 类型 在一个字段存储 多个 JSON对象,可以选择 nested 类型 假设有一个人员信息如下: 建表时会建一个字段存一个值,它的缺点是字段 扁平化 , 无法直观的表现 层级关系 。 字段 值 region US manager_age 30 manager_firstn

    2024年02月09日
    浏览(22)
  • 关于C或C++,数组的强制类型转换,uint8_t与char的区别,uint8_t*与char*的兼容性问题以及一些指针的常见问题

    1.类型定义: uint8_t:这是一个无符号 8 位整数类型,定义在 stdint.h 或 inttypes.h 头文件中。它是标准的固定宽度整数类型之一,确保在所有平台上占用 8 位(1 字节)。 char:这是 C 语言的基本字符存储类型,用于存储单个字符。在不同的系统和编译器中,char 可以是有符号的

    2024年01月24日
    浏览(28)
  • Java 字符串类型的JSON数组转List<Object>或 List<实体类>

    1.依赖 2.代码 3.JSON数组 [     {         \\\"_object_version\\\": 4,         \\\"updateAuthorizers\\\": [         ],         \\\"RELATED_POOL\\\": \\\"网络云-大区金华可信11\\\",         \\\"CLOUD\\\": \\\"大区网络云\\\",         \\\"modifier\\\": \\\"easyops\\\",           },     {         \\\"_object_version\\\": 4,         \\\"updateAuthorizers\\\": [    

    2024年02月14日
    浏览(36)
  • 笔记本电脑内存条的类型有哪些?它们之间有什么区别?

    笔记本电脑内存条有几种常见的类型,包括: DDR4(Double Data Rate 4):DDR4 是目前最新的内存标准,它提供了更高的带宽和更低的电压。DDR4 内存条速度更快,能够处理更多数据,并且相对于旧的 DDR3 内存而言更节能。 DDR3(Double Data Rate 3):DDR3 内存条是较旧的内存标准,但仍

    2024年02月07日
    浏览(37)
  • Qt所有容器之间的区别,以及如何简单使用?

    Qt中常用的容器有 QList、QVector、QMap、QHash、QSet 等,它们都具有不同的特性和适用场景。 1. QList:动态数组,可以动态增加和删除元素,支持随机访问和迭代,适用于不需要频繁插入或删除元素的场景。 ```cpp QListint list; list.append(1); list.append(2); foreach(int val, list) {     qDebug()

    2024年01月19日
    浏览(27)
  • kafka和rabbitmq之间的区别以及适用场景

    Kafka 和 RabbitMQ 都是流行的消息传递系统,用于实现分布式系统中的消息传递、事件处理和数据流。它们在设计和适用场景上有一些不同,下面详细介绍它们之间的区别和适用场景。 特点和优势: 高吞吐量: Kafka 的设计目标是实现高吞吐量和低延迟的消息传递,适合处理大量

    2024年02月13日
    浏览(23)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包