ES 查询语句总结(2)内嵌对象查询

2023-10-27

背景

今年写了一个数据中心的项目,其中有相当一部分的数据查询,用的是ES来做的,涉及到dsl的查询语句,从最开始的简单查询,到后面的复杂的查询,逐步掌握了ES的常用写法,现在总结一下。
文章内的称呼,没有按照ES的官方称呼,例如sql那边的表叫type,sql那边的行叫documents,sql那边的列或者字段叫fields。为了方便起见,统一按照sql的叫法。

查询语句解释说明

书接上回

示例二:

{
    "size": 0,
    "query": {
        "bool": {
            "must": [
                {
                    "bool": {
                        "must": [
                            {
                                "terms": {
                                    "order_status": [
                                        2,
                                        5,
                                        9
                                    ]
                                }
                            },
                            {
                                "nested": {
                                    "path": "order_detail_list",
                                    "query": {
                                        "terms": {
                                            "order_detail_list.goods_id": [123,313,3123,324,5345]
                                        }
                                    }
                                }
                            },
                            {
                                "term": {
                                    "pay_type": 5
                                }
                            },
                            {
                                "range": {
                                    "order_time": {
                                        "gte": "2022-08-01 00:00:00",
                                        "lte": "2022-08-30 23:59:59"
                                    }
                                }
                            }
                        ]
                    }
                },
                {
                    "bool": {
                        "must_not": [
                            {
                                "match_phrase": {
                                    "user_remark": {
                                        "query": "换货单"
                                    }
                                }
                            }
                        ]
                    }
                }
            ]
        }
    },
    "aggs": {
        "total_order_count": {
            "cardinality": {
                "field": "union_pay_order_id",
                "precision_threshold": 50000000
            }
        },
        "order_detail": {
            "nested": {
                "path": "order_detail_list"
            },
            "aggs": {
                "group_by_goods": {
                    "filter": {
                        "terms": {
                            "order_detail_list.goods_id": [123,313,3123,324,5345]
                        }
                    },
                    "aggs": {
                        "total_money": {
                            "sum": {
                                "script": {
                                    "lang": "painless",
                                    "inline": "doc['order_detail_list.count'].value * doc['order_detail_list.price'].value"
                                }
                            }
                        },
                        "total_count": {
                            "sum": {
                                "field": "order_detail_list.count"
                            }
                        }
                    }
                }
            }
        }
    }
}

在这个代码中,对数据的内嵌的内容,做了条件查询,并对内层进行数据聚合。

查询背景:

ES数据的存储结构,不是sql的那种整齐的表格结构,ES由于自身特性,可以做数据嵌套的存储。
本次的查询对象,结构大概如下:

订单表
-订单时间
-订单状态
-订单金额
--订单商品列表
--订单商品1
---商品1的ID
---商品1的数量
---商品1的单价
--订单商品2
---商品2的ID
---商品2的数量
---商品2的单价
--订单商品3
---商品3的ID
---商品3的数量
---商品3的单价

订单表外层是订单的各种信息,例如订单时间,订单状态,收货地址,收货人信息等信息。
由于一个订单一般都不止一个商品,那就会有一个商品列表,对应的购买时商品的单价,商品的数量等信息。

1.查询条件增加内嵌过滤

在这里插入图片描述

上篇提到的加条件的方法,只能加在外层的订单信息的某个字段上,不能加在内层的商品信息上,使用“nested”进入订单明细,然后指定明细内的字段,例如代码中是“order_detail_list.goods_id”指定的商品ID,然后条件才生效。

如果以为这样查出来的结果,就是我们想要的了,那还有点为时尚早,因为这样只是将ES里的原始数据,进行了指定条件的过滤而已。此时在后面直接写聚合,依然还会出错。

2.聚合结果增加内嵌过滤

在这里插入图片描述
1是进入内嵌的商品明细里面,2是按照商品ID进行过滤。

前面在“query”里面加的过滤条件,只能过滤出符合这些条件的原始数据。
举个例子,商品ID为‘123’的商品,在一段时间的销量,就需要先在取出这些商品的数量以及单价,然后进行求和。

"query"阶段的过滤,只是取出来了包含了123商品的订单,这些订单也会包含456,789的商品。

举例订单:
订单1{
商品123,数量2,单价2.5
商品456,数量7,单价1.1
商品789,数量6,单价15.6
},
订单2{
商品123,数量5,单价2.6
商品145,数量7,单价3.1
商品348,数量5,单价9.4
}

如果只是在"query"加了条件,那么在聚合时,就会得到结果:
22.5+71.1+615.6+22.5+73.1+59.4
但是我们需要的是:
22.5+52.6
很显然这样的结果是不符合要求的。

所以在聚合的时候,也要加上商品的过滤条件,图中红框2部分。
顺便提一嘴红框3,这个功能是统计有多少去重后的union_pay_order_id。类似于上篇的统计去重之后的用户个数。

写到这里,有人可以会说,只在内嵌的商品ID加上过滤条件就可以了,就是只加在aggs这个部分,前面的“query”部分应该可以不加这个条件。没错,只在aggs部分加条件,就可以查出商品对应的金额,但是查不出来商品对应的订单的个数。两个查询语句对应的不同结果如下:
在这里插入图片描述
可以看到,query部分加了条件,订单个数统计是没有问题的,没加条件的,订单个数统计的就是全部。其他的求和件数和金额的数据是没有问题的。

3.内嵌对象 数据聚合

在这里插入图片描述
红框内的表示的是ES表的内嵌的字段,"order_detail_list"是一级的字段,“count"是内嵌的二级字段,两个字段用”."隔开。
需要注意到,绿色的框内是一个 乘法,就是说这个和sql一样可以在聚合之前,对两个字段进行相乘。
还有就是在"nested"之后,有两次aggs,第一次是按照goods_id进行聚合,第二次是对商品的金额进行聚合,这里可以类比于sql:

select  sum(count*price), sum(count)
from xxx
where goods_id in (123,313,3123,324,5345)


注意 【不是】 先按照goods_id聚合,后按照数量聚合,类似于这种:
select goods_id, sum(count*price), sum(count)
from xxx
where goods_id in (123,313,3123,324,5345)
group by goods_id
4.查询结果解释
在这里插入代码片

在这里插入图片描述
红框中标出的就是需要的结果的值:外层是订单的个数;内层是内嵌字段的聚合,对商品的金额和件数进行求和,这部分不用详细分析了。

5.扩展

如何实现类似于这个sql的功能呢:

select goods_id, sum(count*price), sum(count)
from xxx
where goods_id in (123,313,3123,324,5345)
group by goods_id

再次加上一个aggs,对内嵌的goods_id聚合就可以了
我的写法:

{
    "size": 0,
    "query": {
        "bool": {
            "must": [
                {
                    "bool": {
                        "must": [
                            {
                                "terms": {
                                    "order_status": [
                                        2,
                                        5,
                                        9
                                    ]
                                }
                            },
                            {
                                "nested": {
                                    "path": "order_detail_list",
                                    "query": {
                                        "terms": {
                                            "order_detail_list.goods_id": [123,313,3123,324,5345]
                                        }
                                    }
                                }
                            },
                            {
                                "term": {
                                    "pay_type": 5
                                }
                            },
                            {
                                "range": {
                                    "order_time": {
                                        "gte": "2022-01-01 00:00:00",
                                        "lte": "2022-08-30 23:59:59"
                                    }
                                }
                            }
                        ]
                    }
                },
                {
                    "bool": {
                        "must_not": [
                            {
                                "match_phrase": {
                                    "user_remark": {
                                        "query": "换货单"
                                    }
                                }
                            }
                        ]
                    }
                }
            ]
        }
    },
    "aggs": {
        "total_order_count": {
            "cardinality": {
                "field": "union_pay_order_id",
                "precision_threshold": 50000000
            }
        },
        "order_detail": {
            "nested": {
                "path": "order_detail_list"
            },
            "aggs": {
                "group_by_goods": {
                    "filter": {
                        "terms": {
                            "order_detail_list.goods_id": [123,313,3123,324,5345]
                        }
                    },"aggregations": {
                        "per_goods": {
                            "terms": {
                                "field": "order_detail_list.goods_id"
                            },
                            "aggs": {
                                "total_money": {
                                    "sum": {
                                        "script": {
                                            "lang": "painless",
                                            "inline": "doc['order_detail_list.count'].value * doc['order_detail_list.price'].value"
                                        }
                                    }
                                },
                                "total_count": {
                                    "sum": {
                                        "field": "order_detail_list.count"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

结尾

这一部分就先写到这里,这只是我对于ES的自己的总结,难免会有不完整以及错误的地方,欢迎指正。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ES 查询语句总结(2)内嵌对象查询 的相关文章

  • 导入 CSV 以更新表中的行

    大约有 26K 个产品 帖子 每个产品都有如下元值 post id 列是数据库中的产品 ID sku meta key 是每个产品的唯一 ID 我收到了一个新的 CSV 文件 该文件更新了每个产品的 sale price meta key
  • 为什么 sql 字段名称中不应该包含逗号?

    人们一直告诉我列名中不应包含空格 我只是想知道 这是为什么 这是我为学校创建的一些数据库表遇到的问题 字段名称包括 Preble 和 Darke 相反 它们需要是 普雷布尔县 俄亥俄州 和 达克县 俄亥俄州 如果它们是行名称 我只需创建一个
  • ASP.NET API:尚未为此 DbContext 配置数据库提供程序

    我正在尝试从我的 Net Core API 项目连接到 MySql 数据库 这是我的上下文类 public class MyContext DbContext public MyContext public MyContext DbCont
  • UNIX时间记录时区吗?

    我想问一下UNIX时间 UNIX时间是否记录时区 我将托管从美国芝加哥移至 JST 问题是我的整个 MySQL 数据库都有 UNIX 时间 芝加哥 美国时区 的记录 我有一个 PHP 代码来显示之前的时间 例如 3 天前 昨天等 当我搬到新
  • MySQL中是否有类似Oracle中“level”的函数[重复]

    这个问题在这里已经有答案了 我面临一个场景 如果输入是 10 我想要一个数字序列 1 2 3 10 在甲骨文中levelfunction 提供了该功能 我想知道如何在 MySQL 中执行相同的任务 谢谢 您可以在 mysql 中使用此查询
  • mySQL 返回可能有重复项的随机行

    我正在尝试随机化一定数量的行 但假设数据库中只有 4 行 而我需要获得 6 个随机行 我希望有可能 即使表中有超过 6 行 产生重复的行行 这在 mySQL 中很容易实现吗 我当前的查询是这样的 SELECT FROM winners OR
  • 按 MAX(time) WHERE time <= x 选择最近的 MySQL 行

    我正在选择 MySQL 表的最新条目 SELECT MAX time as most recent userID FROM TableName GROUP BY userID ORDER BY most recent DESC 我的问题是
  • MySQL 错误 1290 (HY000) --secure-file-priv 选项

    我试图在我的脚本中使用以下代码将 MySQL 脚本的结果写入文本文件 SELECT p title p content c name FROM post p LEFT JOIN category c ON p category id c i
  • 为 Mariadb 安装连接器 C

    所以 我想使用 Mariadb 有一个连接器 C https downloads mariadb org connector c https downloads mariadb org connector c 我该如何安装它 坦白说 它的文
  • Rails 多租户架构,限制多个租户的访问范围

    目前我们有一个单租户数据库架构 MySQL 运行着超过 100 个数据库 我们使用 Apartment gem 切换子域上的数据库连接 一切都很顺利 然而 我们现在需要创建所谓的 伞 客户端 它可以访问一组现有客户端的所有数据 我不认为这对
  • 使用 EXPLAIN 进行 MYSQL 存储过程调用

    如何分析和使用 EXPLAIN 来调用我的存储过程 我需要优化查询时间 但是似乎没有地方可以执行 EXPLAIN 调用 proc name 你可以试试 set profiling 1 call proc name show profiles
  • 自动将所有mysql表转储到单独的文件中?

    我想将每个 mysql 表转储到单独的文件中 手册指出其语法是 mysqldump options db name tbl name 这表明您事先知道表名称 我现在可以设置知道每个表名称的脚本 但是假设我在路上添加了一个新表并且忘记更新转储
  • 物理写入文件已满 - mysql 错误

    我正在使用xampp 每次启动mysql时 我都会在xampp中收到以下错误 Error MySQL shutdown unexpectedly 13 16 14 mysql This may be due to a blocked por
  • SQL 大表中的随机行(使用 where 子句)

    我有一个网站 人们可以在其中对汽车进行投票 向用户展示 4 辆汽车 他 她可以投票选出他们最喜欢的汽车 桌子cars有重要的列 car id int 10 not auto increment so has gaps views int 7
  • 弹性搜索限制类型的结果

    我有以下查询 queryDefinition query gt bool gt must gt query string gt default field gt all query gt term must no
  • Laravel Sum 列数据库 Eloquent

    尝试获取我的一个表中 int 字段的总和应该非常容易 不幸的是 事实并非如此 因为无论我使用 Laravel MySQL 还是 Excel 我都会得到不同的结果 Laravel 5 4 给了我20506 Table sum field na
  • 从 PDO 准备好的语句中获取原始 SQL 查询字符串

    在准备好的语句上调用 PDOStatement execute 时 有没有办法让原始 SQL 字符串执行 出于调试目的 这将非常有用 我假设您的意思是您想要最终的 SQL 查询 并将参数值插入其中 我知道这对于调试很有用 但这不是准备好的语
  • SQL Server 相当于 MySQL 的 USING

    在 MySQL 中 当您连接不同表中具有相同名称的列时 可以在连接中使用关键字 USING 例如 这些查询产生相同的结果 SELECT FROM user INNER JOIN perm USING uid SELECT FROM user
  • 如何使用 PHP 获取列中的所有值?

    我一直在到处寻找这个问题 但仍然找不到解决方案 如何从 mySQL 列中获取所有值并将它们存储在数组中 例如 表名称 客户 列名称 ID 名称 行数 5 我想获取此表中所有 5 个名称的数组 我该如何去做呢 我正在使用 PHP 我试图 SE
  • SQL:查找每个跑步者跑步之间的平均天数

    因此 如果我们给出下表 runner ran Carol 2011 02 01 Alice 2011 02 01 Bob 2011 02 01 Carol 2011 02 02 Bob 2011 02 02 Bob 2011 02 03 B

随机推荐

  • 最新综述:自动驾驶中的多模态三维目标检测

    PaperWeekly 原创 作者 张一帆 学校 华南理工大学本科生 研究方向 CV Causality Abstract 在过去几年 自动驾驶取得了蓬勃的发展 但是由于驾驶环境的复杂多变 实现完全自动依然是一个非常艰巨的任务 自动驾驶汽车
  • Linux 入侵痕迹清理技巧(仅限学习安全知识)

    vim bash history 查看历史操作命令 history history记录文件 more bash history history c echo gt bash history 使用vim打开一个文件 vi test txt 设
  • 键盘 Fn 键 的锁定与解锁

    Dell 笔记本 Fn Esc 锁定与解锁切换
  • Spring+ quartz 之 多任务动态定时(任务中起任务)

    参见上一篇Spring quartz 多任务定时 执行 与cronExpression表达式 可以知道如何设置多个规则的定时任务 但有时需要客户自己设置指定的时间来启动新的任务处理不同的事情 实现方式 用户在前台自行维护任务列表和任务执行时
  • 小程序上线发布后图片不显示

    造成的原因和解决办法 图片的url里面有中文 图片路径中文会造成解析乱码 发布线上就更加解析会有问题 及时将图片路径转成数字或者英文标题 再同步线上更新 图片的HTTP应为小写的http以及图片的后缀为小写的 png或者 jpg 微信小程序
  • 个人对爬虫框架Scrapy的理解

    Scrapy是一个为了爬取网站数据 提取结构性数据而编写的应用框架 我们只需要实现少量代码 就能够快速的抓取的数据内容 Scrapy使用了Twisted一部网络框架来处理网络通讯 可以加快我们的下载速度 不用自己去实现异步框架 并且包含了各
  • python模拟(验证码)登录

    模拟 验证码 登录流程 1 验证码的识别 获取验证码图片的文字数据 2 对post请求进行发送 处理请求参数 3 对响应数据进行持久化存储 示例网站 https www nowapi com app account login 云打码平台
  • 全面了解 Nginx 主要应用场景(转)

    作者 RayeWang www raye wang 2017 02 24 quan mian liao jie nginxdao di neng zuo shi yao 前言 本文只针对Nginx在不加载第三方模块的情况能处理哪些事情 由于
  • VBA下弹框打开excel文件并读取数据

    话不多说 直接上代码 Sub LoadExcelData Dim wkbk As Workbook 定义一个工作薄 Dim myFileName As String 定义要读取的文件路径 Dim dataRow As Integer 定义数
  • 小程序报错解决

    错误一 http localhost 3000 不在以下 request 合法域名列表中 点击详情勾选不校验https即可
  • mcu调试之日志格式化输出的一种方法

    简介 在日后的维护过程中也是很宝贵的东西 怎么能说删除就删除呢 这里提供日志格式化输出的一种方式 主要用于平时调试 那些调试信息是那么的宝贵 代码示例 include
  • 填充书架

    leetCode 1105 填充书架 附近的家居城促销 你买回了一直心仪的可调节书架 打算把自己的书都整理到新的书架上 你把要摆放的书books都整理好 叠成一摞 从上往下 第i本书的厚度为books i 0 高度为books i 1 按顺
  • 【OpenCV】 人脸识别

    目录 一 前言 二 人脸识别案例 实现步骤及完整代码 步骤1 灰度化处理 步骤2 将灰度图再次进行 行列压缩 步骤3 直方图均值化 步骤4 使用模型 对每一个像素点遍历 图像甄别 人脸识别案例 源码分享 结果测试 可对人脸框选识别 三 车辆
  • Oracle内存管理PGA详解

    当用户进程连接到数据库并创建一个对应的会话时 Oracle服务进程会为这个用户专门设置一个PGA区 用来存储这个用户会话的相关内容 当这个用户会话终止时 系统会自动释放这个PGA区所占用的内存 这个PGA区对于数据库的性能有比较大的影响 特
  • CCS:GEL文件

    gel文件的应用 GEL文件与CMD文件 GEL文件的功能同cmd的功能基本相同 用于初始化DSP 但它的功能比cmd的功能有所增强 GEL在CCS下有一个菜单 可以根据DSP的对象不同 设置不同的初始化程序 GEL 通用扩展语言 无类型语
  • 操作系统_05_调度算法(个人总结)

    声明 1 本文为我的个人复习总结 并非那种从零基础开始普及知识 内容详细全面 言辞官方的文章 2 由于是个人总结 所以用最精简的话语来写文章 3 若有错误不当之处 请指出 进程调度 调度算法的评价指标 CPU 利用率 确保 CPU 是始终匆
  • vue实现一个购物车全功能

    效果图 1 静态代码结构渲染 div class app container div class banner box img src http autumnfish cn static fruit jpg alt div div clas
  • SpringMVC注解式控制器的数据验证、类型转换及格式化

    7 1 简介 在编写可视化界面项目时 我们通常需要对数据进行类型转换 验证及格式化 一 在Spring3之前 我们使用如下架构进行类型转换 验证及格式化 流程 类型转换 首先调用PropertyEditor的setAsText String
  • win10计算机分盘怎么设置密码,Win10如何限制磁盘分区被访问 Win10自带磁盘加密功能BitLocker在哪里...

    Win10系统有EFS这个文件加密功能 也自带磁盘加密功能 能让保存在磁盘里的文件上锁 还能给U盘加锁 这个磁盘分区加密功能就是BitLocker驱动器加密 BitLocker驱动器加密是设备加锁工具 防止因为计算机物理丢失导致数据泄露 有
  • ES 查询语句总结(2)内嵌对象查询

    背景 今年写了一个数据中心的项目 其中有相当一部分的数据查询 用的是ES来做的 涉及到dsl的查询语句 从最开始的简单查询 到后面的复杂的查询 逐步掌握了ES的常用写法 现在总结一下 文章内的称呼 没有按照ES的官方称呼 例如sql那边的表