专栏首页颇忒脱的技术博客Elasticsearch中将Doc根据A字段排序获得第一个Doc的B字段值的方法

Elasticsearch中将Doc根据A字段排序获得第一个Doc的B字段值的方法

注:本文基于Elasticsearch 6.1.2编写

最近遇到这样一个需求,要通过Elasticsearch将Doc根据A字段降序,然后获得B字段的值,最终根据B字段的值再去做Pipeline Aggregation

先尝试了Max Aggregation,但是Max Aggregation只能获得A字段的最大值。

然后尝试了Top Hits Aggregation,但是Top Hits Aggregation的结果无法被Pipeline Aggregation使用。

最终尝试Scripted Metric Aggregation成功。下面举例说明

比如现在我们有一堆股票价格数据,我们现在需要获得股票每天的收盘价比前一天的差值(Delta)。下面先倒入一段股票数据,date字段代表时间戳,price字段代表当时的价格:

POST /_bulk

{"index":{"_index":"stock-price","_type":"data"}}
{"date":"2018-01-01T10:00:00","price":10}
{"index":{"_index":"stock-price","_type":"data"}}
{"date":"2018-01-01T10:30:00","price":15}
{"index":{"_index":"stock-price","_type":"data"}}
{"date":"2018-01-02T10:00:00","price":20}
{"index":{"_index":"stock-price","_type":"data"}}
{"date":"2018-01-02T10:30:00","price":19}
{"index":{"_index":"stock-price","_type":"data"}}
{"date":"2018-01-03T10:00:00","price":30}
{"index":{"_index":"stock-price","_type":"data"}}
{"date":"2018-01-03T10:30:00","price":35}
{"index":{"_index":"stock-price","_type":"data"}}
{"date":"2018-01-04T10:00:00","price":40}
{"index":{"_index":"stock-price","_type":"data"}}
{"date":"2018-01-04T10:30:00","price":20}
{"index":{"_index":"stock-price","_type":"data"}}
{"date":"2018-01-05T10:00:00","price":10}

先分解一下看这个查询如何实现:

  1. 把股票数据按照“天”分bucket,这个会用到Date Histogram Aggregation
  2. 获得每个bucket里的最后一次的价格数据,这个会用到Scripted Metric Aggregation
  3. 最后根据算每个bucket的差值,这个会用到Serial Differencing Aggregation

下面是查询代码:

GET /stock-price/_search

{
  "size": 0,
  "aggs": {
    "minute_histo": {
      "date_histogram": {
        "field": "date",
        "interval": "day"
      },
      "aggs": {
        "latest_price": {
          "scripted_metric": {
            "init_script": "params._agg.tmp_rs = ['latest_date': 0, 'latest_price' : -1];",
            "map_script": "def tmp_rs = params._agg.tmp_rs; boolean newer = doc['date'].value.millis > tmp_rs['latest_date']; if (newer) { tmp_rs['latest_date'] = doc['date'].value.millis; tmp_rs['latest_price'] = doc.price.value; }",
            "combine_script": "return params._agg.tmp_rs;",
            "reduce_script": "long rs_date = 0; long rs_price = -1; for (a in params._aggs) {  if (a == null) { continue; } boolean newer = a['latest_date'] > rs_date;   if (newer) {     rs_date = a['latest_date'];     rs_price = a['latest_price'];   } } return rs_price;"
          }
        },
        "delta_price": {
          "serial_diff": {
            "buckets_path": "latest_price.value",
            "lag": 1
          }
        }
      }
    }
  }
}

最后得到的结果是:

{
  ...
  "aggregations": {
    "minute_histo": {
      "buckets": [
        {
          "key_as_string": "2018-01-01T00:00:00.000Z",
          "key": 1514764800000,
          "doc_count": 2,
          "latest_price": {
            "value": 15
          }
        },
        {
          "key_as_string": "2018-01-02T00:00:00.000Z",
          "key": 1514851200000,
          "doc_count": 2,
          "latest_price": {
            "value": 19
          },
          "delta_price": {
            "value": 4.0
          }
        },
        {
          "key_as_string": "2018-01-03T00:00:00.000Z",
          "key": 1514937600000,
          "doc_count": 2,
          "latest_price": {
            "value": 35
          },
          "delta_price": {
            "value": 16.0
          }
        },
        {
          "key_as_string": "2018-01-04T00:00:00.000Z",
          "key": 1515024000000,
          "doc_count": 2,
          "latest_price": {
            "value": 20
          },
          "delta_price": {
            "value": -15.0
          }
        },
        {
          "key_as_string": "2018-01-05T00:00:00.000Z",
          "key": 1515110400000,
          "doc_count": 1,
          "latest_price": {
            "value": 10
          },
          "delta_price": {
            "value": -10.0
          }
        }
      ]
    }
  }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 多种认证、授权模型的比较

    本文主要列举在如今前后端分离、手机App大行其道的现状下,用户认证、授权的几种做法及对比。

    颇忒脱
  • Servlet 3.0 异步处理详解

    Servlet 3.0 开始提供了AsyncContext用来支持异步处理请求,那么异步处理请求到底能够带来哪些好处?

    颇忒脱
  • CPU & Memory, Part 4: NUMA support

    原文:What every programmer should know about memory, Part 4: NUMA support

    颇忒脱
  • 基于python的冒泡排序和选择排序

    装饰器是python的高级用法,初学者需要单独学习1天才能理解并且熟练运用。 读者如果不理解本节内容,不影响后续内容的理解。 此装饰器只是计算函数运行花费的...

    潇洒坤
  • 大数据上市企业财报分析:亿玛在线

    <数据猿导读> 2015年,亿玛在线实现营业总收入为66342.6万元,同比增45.24%;有机构预测2016年亿玛在线的营收规模将超过10亿元,但从刚公布的上...

    数据猿
  • ROS与PCL中点云数据之间的转换

    应小伙伴们后台留言,想要了解ROS中如何使用PCL,本篇文章就将具体介绍一下。文章中如有错误,欢迎留言指出。也期待大家能够积极分享和讨论。

    点云PCL博主
  • leetcode-121-Best Time to Buy and Sell Stock

    Say you have an array for which the ith element is the price of a given stock on...

    chenjx85
  • 带你入门 DissCode,从而攻克大厂面试题!

    今年七月份,我开始写公众号。有两个目的,第一是为了增加自己在技术圈内的影响力,第二是促进更多人来重视算法。于是我写了一系列文章来讲解一些大学课本上有的但是被很多...

    用户2932962
  • 程序员必备的分析解决问题能力:案例分享

    无论工作还是面试,都要求有解决问题的能力,这里给大家分享下,帮助咱们成员解决生产实践中,遇到的实际问题。通过此小案例的分享,希望大家能够面对问题的时候,更容易找...

    用户1410343
  • 如何在ROS中使用PCL—数据格式(1)

    关于PCL在ros的数据的结构,具体的介绍可查 看 wiki.ros.org/pcl/Overview

    点云PCL博主

扫码关注云+社区

领取腾讯云代金券