IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> 深耕ElasticSearch - 过滤和聚合/多桶排序 -> 正文阅读

[大数据]深耕ElasticSearch - 过滤和聚合/多桶排序

1. 数据准备

1、创建索引映射mapping :

PUT /cars 
{
  "mappings": {
    "properties": {
      "price":{
        "type": "integer"
      },
      "color":{
        "type": "keyword"
      },
      "make":{
        "type": "keyword"
      },
      "sold":{
        "type": "date"
      }
    }
  }
}

2、索引文档:

POST /cars/_bulk
{ "index": {}}
{ "price" : 10000, "color" : "red", "make" : "honda", "sold" : "2014-10-28" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }
{ "index": {}}
{ "price" : 30000, "color" : "green", "make" : "ford", "sold" : "2014-05-18" }
{ "index": {}}
{ "price" : 15000, "color" : "blue", "make" : "toyota", "sold" : "2014-07-02" }
{ "index": {}}
{ "price" : 12000, "color" : "green", "make" : "toyota", "sold" : "2014-08-19" }
{ "index": {}}
{ "price" : 20000, "color" : "red", "make" : "honda", "sold" : "2014-11-05" }
{ "index": {}}
{ "price" : 80000, "color" : "red", "make" : "bmw", "sold" : "2014-01-01" }
{ "index": {}}
{ "price" : 25000, "color" : "blue", "make" : "ford", "sold" : "2014-02-12" }

2. 过滤和聚合

2.1 过滤

如果我们想找到售价在 $10,000 美元之上的所有汽车同时也为这些车计算平均售价, 可以简单地使用一个 constant_score 查询和 filter 约束:

GET /cars/_search
{
  "size": 0,
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "price": {
            "gte": 2000
          }
        }
      }
    }
  },
  "aggs": {
    "avg_agg": {
      "avg": {
        "field": "price"
      }
    }
  }
}

从根本上讲,使用 non-scoring 查询和使用 match 查询没有任何区别。查询(包括了一个过滤器)返回一组文档的子集,聚合正是操作这些文档。使用 filtering query 会忽略评分,并有可能会缓存结果数据等等。

{
  "aggregations" : {
    "avg_agg" : {
      "value" : 26500.0
    }
  }
}

2.2 过滤桶

但是如果我们只想对聚合结果过滤怎么办? 假设我们正在为汽车经销商创建一个搜索页面, 我们希望显示用户搜索的结果,但是我们同时也想在页面上提供更丰富的信息,包括(与搜索匹配的)上个月度汽车的平均售价。

这里我们无法简单的做范围限定,因为有两个不同的条件。搜索结果必须是 ford ,但是聚合结果必须满足 ford AND sold > now - 1M

为了解决这个问题,我们可以用一种特殊的桶,叫做 filter 。 我们可以指定一个过滤桶,当文档满足过滤桶的条件时,我们将其加入到桶内。

GET /cars/_search
{
  "size": 0,
  "query": {
    "match": {
      "make": "ford"
    }
  },
  "aggs": {
    "recent_sales": {
      "filter": {    // 使用过滤桶在查询范围基础上应用过滤器 
        "range": {
          "sold": {
            "from": "now-1M"
          }
        }
      },
      "aggs": {      // avg度量只会对ford和上个月售出的文档计算平均售价
        "avg_price": {
          "avg": {       
            "field": "price"
          }
        }
      }
    }
  }
}

3. 多桶排序

多值桶( termshistogramdate_histogram )动态生成很多桶。 Elasticsearch 是如何决定这些桶展示给用户的顺序呢?

默认的,桶会根据 doc_count 降序排列。这是一个好的默认行为,因为通常我们想要找到文档中与查询条件相关的最大值:售价、人口数量、频率。但有些时候我们希望能修改这个顺序,不同的桶有着不同的处理方式。

3.1 内置排序

这些排序模式是桶固有的能力:它们操作桶生成的数据 ,比如 doc_count 。 它们共享相同的语法,但是根据使用桶的不同会有些细微差别。

让我们做一个 terms 聚合但是按 doc_count 值的升序排序:

GET /cars/_search
{
  "size": 0,
  "aggs": {
    "group_by_agg": {
      "terms": {
        "field": "color",
        "order": {
          "_count": "asc"
        }
      }
    }
  }
}

我们为聚合引入了一个 order 对象, 它允许我们可以根据以下几个值中的一个值进行排序:

  • _count:按文档数排序。对 termshistogramdate_histogram 有效。
  • _term:按词项的字符串值的字母顺序排序。只在 terms 内使用。
  • _key:按每个桶的键值数值排序。 只在 histogramdate_histogram 内使用。
{
  "aggregations" : {
    "group_by_agg" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "blue",
          "doc_count" : 2
        },
        {
          "key" : "green",
          "doc_count" : 2
        },
        {
          "key" : "red",
          "doc_count" : 4
        }
      ]
    }
  }
}

3.2 按度量排序

有时,我们会想基于度量计算的结果值进行排序。我们可能想按照汽车颜色创建一个销售条状图表,但按照汽车平均售价的升序进行排序。我们可以增加一个度量,再指定 order 参数引用这个度量即可:

GET /cars/_search
{
  "size": 0,
  "aggs": {
    "group_by_agg": {
      "terms": {
        "field": "color",
        "order": {
          "avg_price": "asc"  // 桶按照计算平均值的升序排序 
        }
      },
      "aggs": {
        "avg_price": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}
{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 8,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "group_by_agg" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "blue",
          "doc_count" : 2,
          "avg_price" : {
            "value" : 20000.0
          }
        },
        {
          "key" : "green",
          "doc_count" : 2,
          "avg_price" : {
            "value" : 21000.0
          }
        },
        {
          "key" : "red",
          "doc_count" : 4,
          "avg_price" : {
            "value" : 32500.0
          }
        }
      ]
    }
  }
}

4. 近似聚合

如果所有的数据都在一台机器上,那么也就不需要像 Elasticsearch 这样的分布式软件了。不过一旦我们开始分布式存储数据,就需要小心地选择算法。

有些算法可以分布执行,到目前为止讨论过的所有聚合都是单次请求获得精确结果的。这些类型的算法通常被认为是高度并行的,因为它们无须任何额外代价,就能在多台机器上并行执行。 复杂的操作则需要在算法的性能和内存使用上做出权衡。对于这个问题,我们有个三角因子模型:大数据、精确性和实时性。我们需要选择其中两项:

  • 精确 + 实时:数据可以存入单台机器的内存之中,我们可以随心所欲,使用任何想用的算法。结果会 100% 精确,响应会相对快速。
  • 大数据 + 精确:传统的 Hadoop。可以处理 PB 级的数据并且为我们提供精确的答案,但它可能需要几周的时间才能为我们提供这个答案。
  • 大数据 + 实时:近似算法为我们提供准确但不精确的结果。

Elasticsearch 目前支持两种近似算法( cardinalitypercentiles )。 它们会提供准确但不是 100% 精确的结果。 以牺牲一点小小的估算错误为代价,这些算法可以为我们换来高速的执行效率和极小的内存消耗。

Elasticsearch 提供的首个近似聚合是 cardinality 度量。 它提供一个字段的基数,即该字段的 distinct 或者 unique 值的数目。 你可能会对 SQL 形式比较熟悉:

SELECT COUNT(DISTINCT color) FROM cars

去重是一个很常见的操作,可以回答很多基本的业务问题:

  • 网站独立访客是多少?
  • 卖了多少种汽车?
  • 每月有多少独立用户购买了商品?

我们可以用 cardinality 度量确定经销商销售汽车颜色的数量:

GET /cars/_search
{
  "size": 0,
  "aggs": {
    "distinct_color": {
      "cardinality": {
        "field": "color"
      }
    }
  }
}
{
  "aggregations" : {
    "distinct_color" : {
      "value" : 3
    }
  }
}

可以让我们的例子变得更有用:每月有多少颜色的车被售出?为了得到这个度量,我们只需要将一个 cardinality 度量嵌入一个 date_histogram

GET /cars/_search
{
  "size": 0,
  "aggs": {
    "month_agg": {
      "date_histogram": {
        "field": "sold",
        "interval": "month",
        "min_doc_count": 1
      },
      "aggs": {
        "color_agg": {
          "cardinality": {
            "field": "color"
          }
        }
      }
    }
  }
}
{
  "aggregations" : {
    "month_agg" : {
      "buckets" : [
        {
          "key_as_string" : "2014-01-01T00:00:00.000Z",
          "key" : 1388534400000,
          "doc_count" : 1,
          "color_agg" : {
            "value" : 1
          }
        },
        {
          "key_as_string" : "2014-02-01T00:00:00.000Z",
          "key" : 1391212800000,
          "doc_count" : 1,
          "color_agg" : {
            "value" : 1
          }
        },
        {
          "key_as_string" : "2014-05-01T00:00:00.000Z",
          "key" : 1398902400000,
          "doc_count" : 1,
          "color_agg" : {
            "value" : 1
          }
        },
        {
          "key_as_string" : "2014-07-01T00:00:00.000Z",
          "key" : 1404172800000,
          "doc_count" : 1,
          "color_agg" : {
            "value" : 1
          }
        },
        {
          "key_as_string" : "2014-08-01T00:00:00.000Z",
          "key" : 1406851200000,
          "doc_count" : 1,
          "color_agg" : {
            "value" : 1
          }
        },
        {
          "key_as_string" : "2014-10-01T00:00:00.000Z",
          "key" : 1412121600000,
          "doc_count" : 1,
          "color_agg" : {
            "value" : 1
          }
        },
        {
          "key_as_string" : "2014-11-01T00:00:00.000Z",
          "key" : 1414800000000,
          "doc_count" : 2,
          "color_agg" : {
            "value" : 1
          }
        }
      ]
    }
  }
}
  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2022-01-01 13:58:47  更:2022-01-01 13:59:01 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 13:29:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码