一、什么是 ES Nested 嵌套

Elasticsearch 有很多数据类型,大致如下:

  • 基本数据类型:

    • string 类型。ES 7.x 中,string 类型会升级为:text 和 keyword。keyword 可以排序;text 默认分词,不可以排序。
    • 数据类型:integer、long 等
    • 时间类型、布尔类型、二进制类型、区间类型等
  • 复杂数据类型:
    • 数组类型:Array
    • 对象类型:Object
    • Nested 类型
  • 特定数据类型:地理位置、IP 等

注意:tring/nested/array 类型字段不能用作排序字段。因此 string 类型会升级为:text 和 keyword。keyword 可以排序,text 默认分词,不可以排序。

2.1 那什么是 Nested 类型?

Elasticsearch 7.x 文档中,这样写到:

The nested type is a specialised version of the object datatype that allows arrays of objects to be indexed in a way that they can be queried independently of each other.

Nested (嵌套)类型,是特殊的对象类型,特殊的地方是索引对象数组方式不同,允许数组中的对象各自地进行索引。目的是对象之间彼此独立被查询出来。

2.2 如何使用 Nested 类型?

在 ES 的 my_index 索引中存储 users 字段。比如说:

{
  "group" : "fans",
  "users" : [
    {
      "name" : "John",
      "age" :  "23"
    },
    {
      "name" : "Alice",
      "age" :  "18"
    }
  ]
}

其实存储看上去跟 Object 类型一样,只不过底层原理对数组 users 字段索引方式不同。设置 users 字段的索引方式 Nested 嵌套类型:

curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "users": {
        "type": "nested"
      }
    }
  }
}
'

二、Nested Query 应用场景或案例

比如小老弟我有一波小粉丝,users 字段类型是 object。存储如下:

{
  "group" : "bysocket_fans",
  "users" : [
    {
      "name" : "John",
      "age" :  "23"
    },
    {
      "name" : "Alice",
      "age" :  "18"
    }
  ]
}

{
  "group" : "路人甲_fans",
  "users" : [
    {
      "name" : "Alice",
      "age" :  "22"
    },
    {
      "name" : "Jeff",
      "age" :  "18"
    }
  ]
}

比如 18 岁大姑娘 Alice 是小老弟我的粉丝,她也可能是周杰伦的粉丝。那这边就有一个需求,即应用场景:

如何找到 18 岁大姑娘 Alice {"name" : "Alice","age" :  "18"} 关注的所有明星呢?

如果用老的查询语句是这样搜索的:

GET /my_index/_search?pretty
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "users.name": "Alice"
          }
        },
        {
          "match": {
            "users.age": 18
          }
        }
      ]
    }
  }
}

结果发现结果是不对的,路人甲 这条记录也出现了。
因为匹配到了第一个 Alice + 第二个 Jeff 的 18。所以这种查询不满足这个场景

那么需要使用 Nested 类型并用 Nested 查询,即让数组中的对象各自地进行索引。目的是对象之间彼此独立被查询出来。

三、Nested Query 实战

3.1 设置 Nested 类型

根据 2.2 如何使用 Nested 类型,将 users 字段类型从 object 修改为 nested:

curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "properties": {
      "users": {
        "type": "nested"
      }
    }
  }
}
'

3.2 Nested Query

修改后,对应的 Nested Query ,如下:

GET /my_index/_search?pretty
{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "users",
            "query": {
              "bool": {
                "must": [
                  {
                    "match": {
                      "users.name": "Alice"
                    }
                  },
                  {
                    "match": {
                      "users.age": 18
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

语法很简单就是:

  • key 以 "nested" 开头
  • path 就是嵌套对象数组的字段名
  • 其他
    • score_mode (可选的)匹配子对象的分数相关性分数。avg (默认,使用所有匹配子对象的平均相关性分数)
    • ignore_unmapped (可选的)是否忽略 path 未映射,不返回任何文档而不是错误。默认为 false,如果 path 不对就报错

这样查询得结果就是对的。

四、Nested Query 性能

这边测试过,给大家一个测试报告和建议。

压测环境:3 个 server ,6 个 ES 节点

压测结论: 使用上小节查询语句,50 并发情况下,导致千兆网卡被打满了。TPS 4000 左右,如果提高并发,就会增加 RT。所以如果高性能大流量情况下,必须用 Nested 应该从网络流量方向进行优化。二者,尽量减少大数据对象的返回

建议:泥瓦匠建议,你听听看

  • 性能:Common Query 远远大于 Nested Query 远远大于 Parent/Child Query
  • 性能优化:首先考虑减少后面两种 Query
  • 性能优化:Nested Query 业务可以优化下。比如上一小节完全可以多存一个 fanIds 数组。搜索两次,第一次查确定 18 岁大姑娘 Alice 的 fanId,第二次根据 fanId 搜索即可
  • 性能优化:实在没办法,高性能大流量情况下,必须用 Nested 应该从网络流量方向进行优化。二者,尽量减少大数据对象的返回

(完)

参考资料:

Elasticsearch 7.x Nested 嵌套类型查询 | ES 干货的更多相关文章

  1. 使用ElasticSearch完成百万级数据查询附近的人功能

    上一篇文章介绍了ElasticSearch使用Repository和ElasticSearchTemplate完成构建复杂查询条件,简单介绍了ElasticSearch使用地理位置的功能. 这一篇我们 ...

  2. [ES]Python查询ES导出数据为Excel

    版本 elasticsearch==5.5.0 python==3.7 说明 用python查询es上存储的状态数据,将查询到的数据用pandas处理成excel code # -*- coding: ...

  3. RestHighLevelClient查询es

    本篇分享的是es官网推荐的es客户端组件RestHighLevelClient的使用,其封装了操作es的crud方法,底层原理就是模拟各种es需要的请求,如put,delete,get等方式:本篇主要 ...

  4. 解决 Elasticsearch 超过 10000 条无法查询的问题

    解决 Elasticsearch 超过 10000 条无法查询的问题 问题描述 分页查询场景,当查询记录数超过 10000 条时,会报错. 使用 Kibana 的 Dev Tools 工具查询 从第 ...

  5. elasticsearch 嵌套对象之嵌套类型

    nested类型是一种特殊的对象object数据类型(specialised version of the object datatype ),允许对象数组彼此独立地进行索引和查询. 1. 对象数组如 ...

  6. 第三百六十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的bool组合查询

    第三百六十六节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的bool组合查询 bool查询说明 filter:[],字段的过滤,不参与打分must:[] ...

  7. Elasticsearch DSL语句之连接查询

    传统数据库支持的full join(全连接)查询方式. 这种方式在Elasticsearch中使用时非常昂贵的.因此,Elasticsearch提供两种操作可以支持水平扩展 更多内容请参考Elasti ...

  8. elasticsearch的5种分片查询优先级

    elasticsearch可以使用preference参数来指定分片查询的优先级,使用时就是在请求url上加上preference参数,如:http://ip:host/index/_search?p ...

  9. Elasticsearch笔记五之java操作es

    Java操作es集群步骤1:配置集群对象信息:2:创建客户端:3:查看集群信息 1:集群名称 默认集群名为elasticsearch,如果集群名称和指定的不一致则在使用节点资源时会报错. 2:嗅探功能 ...

随机推荐

  1. 谷歌推出全新Android开发语言Sky:让App更流畅

    土豆网同步更新:http://www.tudou.com/plcover/VHNh6ZopQ4E/   使用HTML 创建Mac OS App 视频教程. 官方QQ群: (1)App实践出真知 434 ...

  2. 新玩法,CentOS7中LVM通过扩展逻辑卷扩展swap空间

    在我们日常运维工作中,偶尔也会遇到需要扩展swap空间的操作.扩展swap空间的方法很多,现在让我们一起来探讨一下,在LVM下扩展swap空间的方法. 1.查看一下卷组,是否还有空闲空间能用于扩展sw ...

  3. 使用熔断器仪表盘监控(hystrix)

    概述 在 Ribbon 和 Feign 项目增加 Hystrix 仪表盘功能,两个项目的改造方式相同. 在 pom.xml 中增加依赖 <dependency> <groupId&g ...

  4. 用java打印日历

    来自<java核心技术卷一> /** * Created by wangbin10 on 2019/1/3. * 打印当月日历 */ public class CalendarTest { ...

  5. Angular4.0从入门到实战打造在线竞拍网站学习笔记之二--路由

    Angular4.0基础知识之组件 Angular4.0基础知识之路由 Angular4.0依赖注入 Angular4.0数据绑定&管道 路由 简介 接下来学习路由的相关知识 本来是不准备写下 ...

  6. 私服 Nexus 的配置 (转)

    https://www.cnblogs.com/yuanermen/p/4574473.html 一.概述 1.概要 现在的项目基本都是用Maven来管理工程,这样一来在公司内容搭建一个私服就非常有必 ...

  7. hexo + next搭建博客

    使用hexo和next主题搭建GitHub博客 安装node.js 在node.js 官网下载, 相应系统位数的软件包. 可以选择LTS长期支持版, 或者Current当前版本. 我这里选择的是Win ...

  8. vSphere 5.5.0 U1配置问题:主机的快速统计信息不是最新的(转载)

    最近公司新购置了几台DELL服务器用来上桌面虚拟化,前期搭建测试环境进行功能验证,底层自然而然的选择VMware ESXi,当前最新版本为ESXi 5.5.0 U1,单独数据库安装,相对5.1来说,5 ...

  9. django启动入口源码分析

    manage.py是启动入口,在里面调用execute_from_command_line(sys.argv)方法 def execute_from_command_line(argv=None): ...

  10. 2018.10.1 2018NOIP冲刺之立体图

    2008NOIP普及组立体图 请自行百度(事实上放不下了) 图不是很清楚 下面有 [输入] 输入文件 drawing.in 第一行有用空格隔开的 2 个整数 m 和 n,表示有 m*n  个格子 (1 ...