在大数据的应用环境中,往往使用反范式设计来提高读写性能。
假设我们有个类似简书的系统,系统里有文章,用户也可以对文章进行赞赏。在关系型数据库中,如果按照数据库范式设计,需要两张表:一张文章表和一张赞赏历史记录表,赞赏历史记录表包括了赞赏者姓名和赞赏金额。
在Elastic search中,由于都是json格式存储,则可以在一个index存储系统中的文章及其赞赏记录,这种情况下需要在elastic search中使用nested类型的内嵌对象。因为如果使用数组或者object对象的话,赞赏者姓名和赞赏金额是相互独立的进行存储,不能被正确的关联。

建立index

PUT articles
{
"mappings": {
"doc": {
"properties": {
"payment": {
"type": "nested",
"properties": {
"amount": {
"type": "integer"
},
"name": {
"type": "keyword"
}
}
}
}
}
}
}

这样articles就有了payment这个nested类型的字段,payment里面的对象有amount和name,表示金额和姓名。

产生数据

产生如下数据,表示jack给文章1赞赏了29元,ross给文章1赞赏30元,ross给文章2赞赏31元。

POST articles/doc/1
{
"payment": [
{
"name": "jack",
"amount": 29
},
{
"name": "ross",
"amount": 30
}
]
} POST articles/doc/2
{
"payment": [
{
"name": "ross",
"amount": 31
}
]
}

根据内嵌对象进行查询

现在想查询ross赞赏过的文章,需要使用nested query

GET articles/_search
{
"query": {
"nested": {
"path": "payment",
"query": {
"term": {
"payment.name": {
"value": "ross"
}
}
}
}
}
}

path表示了nested字段的名称,需要注意的是,查询语句中要指定查询字段的全名,所以赞赏者姓名要用"payment.name"
如果在多个index上进行nested查询,没有nested字段的index会报错,这时可以将ignore_unmapped设置为true

nested对象聚合

如果想查看赞赏的平均金额,需要用nested aggregation

GET articles/_search
{
"size": 0,
"aggs": {
"nested": {
"nested": {
"path": "payment"
},
"aggs": {
"amount_avg": {
"avg": {
"field": "payment.amount"
}
}
}
}
}
}

同样注意要用path指定字段名称。返回的数据中,比普通的聚合查询多了一层嵌套
返回结果为

{
"took": 1,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 2,
"max_score": 0,
"hits": []
},
"aggregations": {
"nested": {
"doc_count": 3,
"amount_avg": {
"value": 30
}
}
}
}

nested对象聚合和过滤

如果想看ross赞赏过的总金额,一开始写出query如下

GET articles/_search
{
"size": 0,
"query": {
"nested": {
"path": "payment",
"query": {
"term": {
"payment.name": {
"value": "ross"
}
}
}
}
},
"aggs": {
"nested": {
"nested": {
"path": "payment"
},
"aggs": {
"sum": {
"sum": {
"field": "payment.amount"
}
}
}
}
}
}

此时结果并不是正确的,因为上面的query过滤的是ross赞赏过的文章,下面的聚合操作sum的是文章里所有的赞赏,包括了jack的赞赏。
所以需要在sum聚合操作之前,需要用Filter Aggregation筛选ross的赞赏。

GET articles/_search
{
"size": 0,
"query": {
"nested": {
"path": "payment",
"query": {
"term": {
"payment.name": {
"value": "ross"
}
}
}
}
},
"aggs": {
"payment": {
"nested": {
"path": "payment"
},
"aggs": {
"payer": {
"filter": {
"term": {
"payment.name": {
"value": "ross"
}
}
},
"aggs": {
"sum": {
"sum": {
"field": "payment.amount"
}
}
}
}
}
}
}
}

最外层的query筛选出ross赞赏过的文章。
第一层的aggs表示进行内嵌聚合。
第二层的aggs用Filter Aggregation筛选出表示ross赞赏行为的nested对象。
第三层的aggs进行聚合。

作者:大神带我来搬砖
链接:https://www.jianshu.com/p/d685b7b6c9d1
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Elastic search中使用nested类型的内嵌对象的更多相关文章

  1. freemarker 中可以直接使用的内置对象

    freemarker 中可以直接使用的内置对象 需要配置一下:springboot中配置 ## Freemarker \u914D\u7F6E ## \u6587\u4EF6\u914D\u7F6E\ ...

  2. 关于js函数解释(包括内嵌,对象等)

    常用写法: function add(a,b) { return a + b; } alert(add(1,2)); // 结果 3 当我们这么定义函数的时候,函数内容会被编译(但不会立即执行,除非我 ...

  3. elastic search 日期为string类型导致视图无法展示时间的解决办法

    尝试将结构化的json数据发送到es(elastic search)上,然后创建视图,这样就能以小时维度查看数据,直接使用post发送到es后,创建索引,结果提示 没有date类型的字段(field) ...

  4. Elastic Search中Document的CRUD操作

    一. 新增Document在索引中增加文档.在index中增加document.ES有自动识别机制.如果增加的document对应的index不存在.自动创建,如果index存在,type不存在自动创 ...

  5. Elastic Search中filter的理解

    在ES中,请求一旦发起,ES服务器是按照请求参数的顺序依次执行具体的搜索过滤逻辑的.如何定制请求体中的搜索过滤条件顺序,是一个经验活.类似query(指search中的query请求参数),也是搜索的 ...

  6. Elastic Search中mapping的问题

    Mapping在ES中是非常重要的一个概念.决定了一个index中的field使用什么数据格式存储,使用什么分词器解析,是否有子字段,是否需要copy to其他字段等.Mapping决定了index中 ...

  7. JSP中的Java代码和内置对象

    一.JSP中的Java代码 (一)JSP页面中有三种方式嵌入java代码: 1.java的表达式 格式:<%= java表达式 %> 2.java的语句 格式:<% java语句&g ...

  8. Word中高效输入公式:内嵌公式和Mathtype

    Word中高效输入公式:内嵌公式和Mathtype 前言:对于理工科学生而言,公式输入必不可缺.LaTeX相比Word,在公式输入及排版方面更强大.但是对于轻量级的任务,用Word而言更加轻便(起码不 ...

  9. js之数据类型(对象类型——单体内置对象——Math)

    Math是一个内置对象,它具有数学常数和函数的属性和方法.Math对象用于执行数学任务,和其它对象不同,Math只是一个静态对象并没有Math()构造函数,实际上,Math()只是一个由js设置的对象 ...

随机推荐

  1. Kattis - heapsoffun Heaps of Fun (概率密度函数+dp)

    题意:有一棵含有n个结点(n<=300)的根树,树上每个结点上的权值是从[0,ai](ai<=1e9)区间内随机的一个实数,问这棵树能形成一个最小堆的概率. 由于结点取值范围是1e9而且是 ...

  2. POJ - 2689 Prime Distance (区间筛)

    题意:求[L,R]中差值最小和最大的相邻素数(区间长度不超过1e6). 由于非素数$n$必然能被一个不超过$\sqrt n$的素数筛掉,因此首先筛出$[1,\sqrt R]$中的全部素数,然后用这些素 ...

  3. 微信小程序轮播图的制作与跳转

    <!--轮播图 --> <view class='swiperBanner'> <swiper indicator-dots='{{indicatorDots}}' au ...

  4. idea无法创建javaclass文件

    一直用pycharm和jupyter. 今天发现打开IDEA 创建一个新的java项目(maven)后无法在里面的module中创建相应的java class文件 解决方案: (1)选择 File—— ...

  5. php的$_get,$_post用法

    $_GET 可以被收藏, 可以被缓存, 可以保存在历史记录中, 可以提交请求但是很不安全, 长度有限制在2000个字符,其实get请求就是一个url;$_GET['user_name'] $_POST ...

  6. 动软生成器 Liger model生成模板

    <#@ template language="c#" HostSpecific="True" #> <#@ output extension= ...

  7. Python CGI编程Ⅳ

    使用POST方法传递数据 使用POST方法向服务器传递数据是更安全可靠的,像一些敏感信息如用户密码等需要使用POST传输数据. 以下同样是hello_get.py ,它也可以处理浏览器提交的POST表 ...

  8. conda退出base 环境

    安装conda后取消命令行前出现的base,取消每次启动自动激活conda的基础环境   方法一: 每次在命令行通过conda deactivate退出base环境回到系统自动的环境 方法二 1,通过 ...

  9. Open Cascade:计算体积

    TopoDS_Shape shape; ... GProp_GProps System; BRepGProp::LinearProperties(shape, System); BRepGProp:: ...

  10. numpy.bincount()

    numpy.bincount详解 numpy.bincount(x, weights=None,minlength=0) 参数中要求x是一个array_like,一维的并且包含非负整数. In [19 ...