• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
孙龙 程序员
少时总觉为人易,华年方知立业难
博客园    首页    新随笔    联系   管理    订阅  订阅
elasticsearch--高级进阶篇5-高级聚合

1、正排索引

1.1 正排索引(doc values )和倒排索引

概念:从广义来说,doc values 本质上是一个序列化的 列式存储 。列式存储 适用于聚合、排序、脚本等操作,所有的数字、地理坐标、日期、IP 和不分词( not_analyzed )字符类型都会默认开启,不支持text和annotated_text类型

区别:

  • 倒排:倒排索引的优势是可以快速查找包含某个词项的文档有哪些。如果用倒排来确定哪些文档中是否包含某个词项就很鸡肋。
  • 正排:正排索引的优势在于可以快速的查找某个文档里包含哪些词项。同理,正排不适用于查找包含某个词项的文档有哪些。

倒排索引和正排索引均是在index-time时创建,保存在 Lucene文件中(序列化到磁盘)。

1.2 正排索引的数据结构

1.2.1 doc values

doc values是正排索引的基本数据结构之一,其存在是为了提升排序和聚合效率,默认true,如果确定不需要对字段进行排序或聚合,也不需要通过脚本访问字段值,则可以禁用doc values值以节省磁盘空间。

1.2.2 fielddata:

概念:查询时内存数据结构,在首次用当前字段聚合、排序或者在脚本中使用时,需要字段为fielddata数据结构,并且创建倒排索引保存到堆中。与 doc value 不同,当没有doc value的字段需要聚合时,需要打开fielddata,然后临时在内存中建立正排索引,fielddata 的构建和管理发生在 JVM Heap中。Fielddata默认是不启用的,因为text字段比较长,一般只做关键字分词和搜索,很少拿它来进行全文匹配和聚合还有排序。

语法:

PUT /<index>/_mapping
{
  "properties": {
    "tags": {
      "type": "text",
      "fielddata": true  //true:开启fielddata;        false:关闭fielddata
    }
  }
}

深层解读(独家):doc values是文档到词项的映射 inverted是词项到文档id的映射从原理上讲 先说倒排索引为什么不适合聚合,你无法通过倒排索引确定doc的总数量,并且因为倒排索引默认会执行analysis,即使聚合,结果也可能不准确,所以你还要创建not_analyzed字段,徒增磁盘占用,举个最简单的例子:假如有一张商品表,每个商品都有若干标签,我们执行了以下查询

GET product/_search
{
  "query": {
    "match": {
      "tags": "性价比"
    }
  },
  "aggs": {
    "tag_terms": {
      "terms": {
        "field": "tags.keyword"
      }
    }
  }
}

这段聚合查询的意思 查询包含“性价比”这个标签商品的所有标签,在执行agg的时候 我们使用倒排索引,那么语义将是这样的:在倒排索引中扫描逐个term,看看这个term对用的倒排表中对应的doc的标签 是否包含“性价比”,如果包含,则记录,由于我们不确定下面一个term是否符合条件,所以我们就要一个一个的判断,所以就造成了扫表。如果使用正排索引,而正排索引的指的是,doc中包含了哪些词项,也就是当前doc_id=>当前字段所包含的所有词项的映射,我们要查找的是符合条件的doc中所有的标签,那么我们直接根据key(doc_id)去拿values(all terms)就可以了,所以就不用扫表。所以聚合查询使用正排索引效率高本质是两种数据结构的区别 和结不结合倒排索引没有关系,结合倒排索引只是预先进行了数据筛选。以上是正排索引在原理上对聚合查询友好的原因 下面我说一下关于两种数据结构在数据压缩上的不同,doc values是一种序列化的列式存储结构,其values其中也包含了词频数据。而这种结构是非常有利于数据压缩的,参考第二版VIP课程中的FOR和RBM压缩算法,因为Lucene底层读取文件的方式是基于mmap的,原理是上是从磁盘读取到OS cache里面进行解码的,使用正排索引的数据结构,由于其列式存储的数据和posting list一样可以被高效压缩,所以这种方式极大的增加了从磁盘中读取的速度,因为体积小了,然后把数据在OS Cache中进行解码

2、三角选择原则

3、基数聚合:Cardinality

4、深度优先(DFS)和广度优先(BFS)

4.1 概念和基本原理

背景:Terms 桶基于我们的数据动态构建桶;它并不知道到底生成了多少桶。 大多数时候对单个字段的聚合查询还是非常快的, 但是当需要同时聚合多个字段时,就可能会产生大量的分组,最终结果就是占用 es 大量内存,从而导致 OOM 的情况发生。

在Elasticsearch中,对于具有许多唯一术语和少量所需结果的字段,延迟子聚合的计算直到顶部父级聚合被修剪会更有效。通常,聚合树的所有分支都在一次深度优先传递中展开,然后才会发生任何修剪。在某些情况下,这可能非常浪费,并且可能会遇到内存限制。

基本原理即:推迟子聚合的计算

4.2 原理

4.3 适用场景及基本用法

4.3.1 用法:Collect mode

"collect_mode": "{collect_mode.value}" 

4.3.2 参数

  • breadth_first:广度优先模式属于最上层桶的一组文档被缓存以备后续重播,因此执行此操作时内存开销与匹配文档的数量成线性关系。即:先做第一层聚合,逐层修剪。
  • depth_first:即:先构建完整的树,然后修剪无用节点。

4.4 注意

广度优先仅仅适用于每个组的聚合数量远远小于当前总组数的情况下,因为广度优先会在内存中缓存裁剪后的仅仅需要缓存的每个组的所有数据,以便于它的子聚合分组查询可以复用上级聚合的数据。

广度优先的内存使用情况与裁剪后的缓存分组数据量是成线性的。对于很多聚合来说,每个桶内的文档数量是相当大的。

5、邻接矩阵

 

 

 

##############################################################################
#数据(基础课中也给过)
DELETE product
PUT /product/_doc/1
{
    "name" : "小米手机",
    "desc" :  "手机中的战斗机",
    "price" :  3999,
    "lv":"旗舰机",
    "type":"手机",
    "createtime":"2020-10-01T08:00:00Z",
    "tags": [ "性价比", "发烧", "不卡顿" ]
}
PUT /product/_doc/2
{
    "name" : "小米NFC手机",
    "desc" :  "支持全功能NFC,手机中的滑翔机",
    "price" :  4999,
        "lv":"旗舰机",
    "type":"手机",
    "createtime":"2020-05-21T08:00:00Z",
    "tags": [ "性价比", "发烧", "公交卡" ]
}
PUT /product/_doc/3
{
    "name" : "NFC手机",
    "desc" :  "手机中的轰炸机",
    "price" :  2999,
        "lv":"高端机",
    "type":"手机",
    "createtime":"2020-06-20",
    "tags": [ "性价比", "快充", "门禁卡" ]
}
PUT /product/_doc/4
{
    "name" : "小米耳机",
    "desc" :  "耳机中的黄焖鸡",
    "price" :  999,
        "lv":"百元机",
    "type":"耳机",
    "createtime":"2020-06-23",
    "tags": [ "降噪", "防水", "蓝牙" ]
}
PUT /product/_doc/5
{
    "name" : "红米耳机",
    "desc" :  "耳机中的肯德基",
    "price" :  399,
    "type":"耳机",
        "lv":"百元机",
    "createtime":"2020-07-20",
    "tags": [ "防火", "低音炮", "听声辨位" ]
}
PUT /product/_doc/6
{
    "name" : "小米手机12",
    "desc" :  "充电贼快掉电更快,超级无敌望远镜,高刷电竞屏",
    "price" :  5999,
        "lv":"旗舰机",
    "type":"手机",
    "createtime":"2020-07-27",
    "tags": [ "120HZ刷新率", "120W快充", "120倍变焦" ]
}
PUT /product/_doc/7
{
    "name" : "挨炮 SE2",
    "desc" :  "除了CPU,一无是处",
    "price" :  3299,
        "lv":"旗舰机",
    "type":"手机",
    "createtime":"2020-07-21",
    "tags": [ "割韭菜", "割韭菜", "割新韭菜" ]
}
PUT /product/_doc/8
{
    "name" : "XS Max",
    "desc" :  "听说要出新款15手机了,终于可以换掉手中的4S了",
    "price" :  4399,
        "lv":"旗舰机",
    "type":"手机",
    "createtime":"2020-08-19",
    "tags": [ "5V1A", "4G全网通", "大" ]
}
PUT /product/_doc/9
{
    "name" : "小米电视",
    "desc" :  "70寸性价比只选,不要一万八,要不要八千八,只要两千九百九十八",
    "price" :  2998,
        "lv":"高端机",
    "type":"电视",
    "createtime":"2020-08-16",
    "tags": [ "巨馍", "家庭影院", "游戏" ]
}
PUT /product/_doc/10
{
    "name" : "红米电视",
    "desc" :  "我比上边那个更划算,我也2998,我也70寸,但是我更好看",
    "price" :  2999,
    "type":"电视",
        "lv":"高端机",
    "createtime":"2020-08-28",
    "tags": [ "大片", "蓝光8K", "超薄" ]
}
PUT /product/_doc/11
{
  "name": "红米电视",
  "desc": "我比上边那个更划算,我也2998,我也70寸,但是我更好看",
  "price": "2998",
  "type": "电视",
  "lv": "高端机",
  "createtime": "2020-08-28",
  "tags": [
    "大片",
    "蓝光8K",
    "超薄"
  ]
}

# 正排索引
# 二八定律:(buckets;metric:avg max min sum count;pipeline aggs)
# cardinality
GET product/_search
{
  "size": 0,
  "aggs": {
    "cardinality_aggs": {
      "cardinality": {
        "field": "type"
      }
    }
  }
}
# 三角选择原则:精准 实时 大数据 
GET product/_mapping
PUT product2
{
  "mappings": {
    "properties": {
      "type" : {
          "type" : "keyword",
          "doc_values": true, 
          "fields" : {
            "hash" : {
              "type" : "murmur3"
            }
          }
        }
    }
  }
}
#****************Top hits Aggregation
##较为常用的统计。获取到每组前n条数据。相当于sql 中 group by 后取出前n条。
GET product/_search
#按照type分组,按照文档数倒序排序,取前10个组,每组取前两条,组内按照价格由低到高排序
GET product/_search?size=0
{
  "aggs": {
    "top-tags": {
      "terms": {
        "field": "type",
        "size": 10,
        "order": {
          "_count": "desc"
        }
      },
      "aggs": {
        "top_tag_hits": {
          "top_hits": {
            "sort": [
              {
                "price": "asc"
              }
            ],
            "size": 2
          }
        }
      }
    }
  }
}

#Filter&Filters Agg
GET product/_search
{
  "size": 0,
  "aggs": {
    "agg_stats": {
      "filter": {
        "terms": {
          "type": ["耳机","手机","电视"]
        }
      },
      "aggs": {
        "avg": {
          "avg": {
            "field": "price"
          }
        }
      }
    }
  }
}

GET product/_search
{
  "size": 0,
  "aggs" : {
    "item_avg" : {
      "filters" : {
        "filters" : {
          "phone" :   { "term": { "type" : "手机"   }},
           "tv" :   { "term": { "type" : "电视"   }},
          "headset" : { "term" : { "type" : "耳机" }}
        }
      }
    }
  }
}

GET product/_search
{
  "size": 0,
  "aggs" : {
    "messages" : {
      "filters" : {
        "other_bucket_key": "other_type",
        "filters" : {
          "phone" :   { "term": { "type" : "手机"   }},
          "tv" :   { "term": { "type" : "电视"   }},
          "airpods" : { "term" : { "type" : "耳机" }}
        }
      }
    }
  }
}

#median_absolute_deviation:绝对中位差
GET product/_search
{
  "_source": "price", 
  "query": {
    "match_all": {}
  }
}
#MAD = median(|median(X) - Xi|)
#compression 精度参数 默认1000 设置的越高,内存消耗越高,精确度越高,误差0-5%
GET product/_search
{
  "size": 0,
  "aggs": {
    "review_average": {
      "avg": {
        "field": "price"
      }
    },
    "review_variability": {
      "median_absolute_deviation": {
        "field": "price" ,
        "compression": 1000
      }
    }
  }
}

#meta data
GET /product/_search
{
  "size": 0,
  "aggregations": {
    "my_agg": {
      "terms": {
        "field": "desc.keyword"
      },
      "meta": {
        "msb-newbee": "newbeenewbeenewbeenewbeenewbee"
      }
    }
  }
}




PUT /actor_films/_doc/1
{
  "name": "成龙",
  "films": [
    {
      "name": "A计划",
      "collect": 210
    },
    {
      "name": "B计划",
      "collect": 200
    },
    {
      "name": "C计划",
      "collect": 230
    },
    {
      "name": "D计划",
      "collect": 250
    }
  ]
}
PUT /actor_films/_doc/2
{
  "name": "李连杰",
  "films": [
    {
      "name": "功夫",
      "collect": 310
    },
    {
      "name": "少林寺",
      "collect": 400
    },
    {
      "name": "峨眉",
      "collect": 530
    }
  ]
}
PUT /actor_films/_doc/3
{
  "name": "吴京",
  "films": [
    {
      "name": "战狼",
      "collect": 210
    },
    {
      "name": "战狼2",
      "collect": 500
    },
    {
      "name": "流浪地球",
      "collect": 630
    }
  ]
}
GET actor_films/_search

GET actor_films/_search?size=0
{
  "aggs": {
    "actors": {
      "terms": {
        "field": "name.keyword",
        "size": 10,
        "order": {
          "collect_count": "desc"
        }
      },
      "aggs": {

      }
    }
  }
}

#深度优先和广度优先

# terms 桶基于我们的数据动态构建桶;它并不知道到底生成了多少桶。 大多数时候对单个字段的聚合查询还是非常快的, 但是当需要同时聚合多个字段时,就可能会产生大量的分组,最终结果就是占用 es 大量内存,从而导致 OOM 的情况发生。

#深度优先:先构建完整的树,然后修剪无用节点
#广度优先:先做第一层聚合,逐层修剪
#广度优先仅仅适用于每个组的聚合数量远远小于当前总组数的情况下,因为广度优先会在内存中缓存裁剪后的仅仅需要缓存的每个组的所有数据,以便于它的子聚合分组查询可以复用上级聚合的数据。

#广度优先的内存使用情况与裁剪后的缓存分组数据量是成线性的。对于很多聚合来说,每个桶内的文档数量是相当大的。 
GET test/_mapping
PUT test/_mapping
{
  "properties":{
    "actors":{
      "type":"text",
      "fielddata":true
    }
  }
}

GET /test/_search
{
  "aggs" : {
    "actors" : {
      "terms" : {
         "field" : "actors",
         "size" :  10
      },
      "aggs" : {
        "costars" : {
          "terms" : {
            "field" : "actors",
            "size" :  5
          }
        }
      }
    }
  }
}

#*****************************************************************************
#Adjacency Matrix Aggregation 邻接矩阵
DELETE emails
PUT /emails/_bulk?refresh
{ "index" : { "_id" : 1 } }
{ "accounts" : ["a", "f"]}
{ "index" : { "_id" : 2 } }
{ "accounts" : ["a", "b"]}
{ "index" : { "_id" : 3 } }
{ "accounts" : ["c", "b"]}

GET emails/_search
GET emails/_search?size=0
{
  "aggs" : {
    "interactions" : {
      "adjacency_matrix" : {
        "filters" : {
          "A" : { "terms" : { "accounts" : ["a", "d"] }},
          "B" : { "terms" : { "accounts" : ["b", "e"] }},
          "C" : { "terms" : { "accounts" : ["c", "f"] }}
        }
      }
    }
  }
}

 

本文来自博客园,作者:孙龙-程序员,转载请注明原文链接:https://www.cnblogs.com/sunlong88/p/17399621.html

posted on 2023-05-14 17:02  孙龙-程序员  阅读(91)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3