ES聚合算法原理深入解读:深度优先算法(DFS)和广度优先算法(BFS)(一)

简介: ES聚合算法原理深入解读:深度优先算法(DFS)和广度优先算法(BFS)(一)

1、引言

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


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


而本文所讲的内容即通过 DFS 和 BFS 提升检索效率和提升聚合性能,基本原理即:推迟子聚合的计算。


2、案例

假设有索引actor_films,存储信息为某些演员和其出演过的一些电影。


2.1 数据

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
    }
  ]
}


2.2 假设有如下需求:

统计演员列表中总票房最高的前十位演员每个人票房最高的前五部电影

因为无法导入大量数据,并且聚合代码本身非本文所讲解重点,因此下面代码采用伪代码方式,即跳过具体的逻辑部分。


伪代码如下:

GET actor_films/_search
{
  "size": 0,
  "aggs": {
    "actors_agg": {
      "terms": {
        "field": "name.keyword",
        "size": 10 // 这里跳过了计算过程,假设默认排序就是票房排序倒序排列
      },
      "aggs": {
        "movies_agg": {
          "terms": {
            "field": "movies.name.keyword",
            "size": 5 // 假设默认就是票房排序
          }
        }
      }
    }
  }
}


2.3 性能痛点

首先,上述代码描述的问题可用下图表示,假设演员数据有M个,M是一个很大的数值,比如1万、10万或者更多。每位演员出演过N部电影,每个M对应的N可能不同,N 大于5。

a8836329c4224c4aa956f9c462067ba5.png

按照上述需求,我们最终要返回的桶数量最大值为 50。默认情况下,ES 会先构建完整的树,然后修剪无用节点。下图中表示即先遍历 演员1,然后遍历演员一的第一个分支,直至第一个分支没有子节点,回溯值演员一的第二个分支,直至遍历完演员1 的所有分支,回溯至Entry,然后遍历演员2。最终遍历节点数为 MN。如果演员数量有1万,平均每个演员10部电影,此时遍历所产生的的计算为10万次,而我们真正需要的只有50次!


3 解决方式

3.1 Collect mode

ES 中允许设置参数collect_mode

"collect_mode": "{collect_mode.value}"


3.2 参数

breadth_first:即使用广度优先算法。即:先做第一层聚合,逐层修剪。广度优先仅仅适用于每个组的聚合数量远远小于当前总组数的情况下,因为广度优先会在内存中缓存裁剪后的仅仅需要缓存的每个组的所有数据,以便于它的子聚合分组查询可以复用上级聚合的数据。广度优先的内存使用情况与裁剪后的缓存分组数据量是成线性的。对于很多聚合来说,每个桶内的文档数量是相当大的。


depth_first:使用深度优先算法,即:先构建完整的树,然后修剪无用节点。


3.3 完整代码如下

GET actor_films/_search
{
  "size": 0,
  "aggs": {
    "actors_agg": {
      "terms": {
        "field": "name.keyword",
        "size": 10, // 这里跳过了计算过程,假设默认排序就是票房排序倒序排列
        "collect_mode": "breadth_first" // 使用广度优先搜索
      },
      "aggs": {
        "movies_agg": {
          "terms": {
            "field": "movies.name.keyword",
            "size": 5 // 假设默认就是票房排序
          }
        }
      }
    }
  }
}


相关文章
|
1月前
|
算法 测试技术 定位技术
数据结构与算法——DFS(深度优先搜索)
数据结构与算法——DFS(深度优先搜索)
|
3月前
|
算法
DFS算法的实现
DFS算法的实现
58 3
|
5月前
|
算法 Java
Java数据结构与算法:图算法之深度优先搜索(DFS)
Java数据结构与算法:图算法之深度优先搜索(DFS)
|
5月前
|
算法 索引
DFS算法及应用(二)
回溯:回溯就是DFS的一种,在搜索探索过程中寻找问题的解,当发现不满足求解条件时,就回溯返回,尝试其他路径。
|
12天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
1月前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于MSER和HOG特征提取的SVM交通标志检测和识别算法matlab仿真
### 算法简介 1. **算法运行效果图预览**:展示算法效果,完整程序运行后无水印。 2. **算法运行软件版本**:Matlab 2017b。 3. **部分核心程序**:完整版代码包含中文注释及操作步骤视频。 4. **算法理论概述**: - **MSER**:用于检测显著区域,提取图像中稳定区域,适用于光照变化下的交通标志检测。 - **HOG特征提取**:通过计算图像小区域的梯度直方图捕捉局部纹理信息,用于物体检测。 - **SVM**:寻找最大化间隔的超平面以分类样本。 整个算法流程图见下图。
|
9天前
|
人工智能 算法 数据安全/隐私保护
基于遗传优化的SVD水印嵌入提取算法matlab仿真
该算法基于遗传优化的SVD水印嵌入与提取技术,通过遗传算法优化水印嵌入参数,提高水印的鲁棒性和隐蔽性。在MATLAB2022a环境下测试,展示了优化前后的性能对比及不同干扰下的水印提取效果。核心程序实现了SVD分解、遗传算法流程及其参数优化,有效提升了水印技术的应用价值。
|
11天前
|
机器学习/深度学习 算法 数据安全/隐私保护
基于贝叶斯优化CNN-LSTM网络的数据分类识别算法matlab仿真
本项目展示了基于贝叶斯优化(BO)的CNN-LSTM网络在数据分类中的应用。通过MATLAB 2022a实现,优化前后效果对比明显。核心代码附带中文注释和操作视频,涵盖BO、CNN、LSTM理论,特别是BO优化CNN-LSTM网络的batchsize和学习率,显著提升模型性能。