elasticsearch - 按百分位数过滤

标签 elasticsearch percentile

假设我想按 10% 到 20% 内的某个字段过滤文档。我想知道是否可以通过一些简单的查询来实现,例如 {"fieldName":{"percentile": [0.1, 0.2]}}

假设我有这些文件:

[{"a":1,"b":101},{"a":2,"b":102},{"a":3,"b":103}, ..., {"a":100,"b":200}]

我需要通过a(升序)过滤其中的前10个,即从1到10的a。然后我需要对这些结果进行排序按b降序排列,然后取分页结果(如第2页,每页10条)。

想到的一个解决方案是:

  1. 获取文档总数。

  2. a对文档进行排序,取相应的_id,限制为0.1 * Total_count

  3. 编写最终查询,例如 id in (...) order by b

但是缺点也很明显:

  1. 如果我们谈论亚秒级延迟,似乎效率不高

  2. 如果我们在第一个查询中返回太多 _id ,第二个查询可能不起作用(ES 默认情况下只允许 1000 个。我当然可以更改配置,但总会有一个限制)。

最佳答案

如果事先不知道 a 的确切值,我怀疑是否有一种方法可以在一个查询中执行此操作,尽管我认为一种非常有效的方法是可行的。

我建议做 percentiles aggregation作为第一个查询和 range query作为第二个。

在我的示例索引中,我只有 14 个文档,因此出于解释原因,我将尝试查找占字段 a 30% 到 60% 的文档,并按字段 对它们进行排序b 以相反的顺序(以确保排序有效)。

这是我插入的文档:

{"a":1,"b":101}
{"a":5,"b":105}
{"a":10,"b":110}
{"a":2,"b":102}
{"a":6,"b":106}
{"a":7,"b":107}
{"a":9,"b":109}
{"a":4,"b":104}
{"a":8,"b":108}
{"a":12,"b":256}
{"a":13,"b":230}
{"a":14,"b":215}
{"a":3,"b":103}
{"a":11,"b":205}

让我们找出字段 a 在 30% 和 60% 百分位数之间的界限:

POST my_percent/doc/_search
{
    "size": 0,
    "aggs" : {
        "percentiles" : {
            "percentiles" : {
                "field" : "a",
                "percents": [ 30, 60, 90 ]
            }
        }
    }
}

使用我的示例索引,它看起来像这样:

{
...
  "hits": {
    "total": 14,
    "max_score": 0,
    "hits": []
  },
  "aggregations": {
    "percentiles": {
      "values": {
        "30.0": 4.9,
        "60.0": 8.8,
        "90.0": 12.700000000000001
      }
    }
  }
}

现在我们可以使用边界来执行范围查询:

POST my_percent/doc/_search
{
    "query": {
      "range": {
            "a" : {
                "gte" : 4.9,
                "lte" : 8.8
            }
        }
    },
    "sort": {
      "b": "desc"
    }
}

结果是:

{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 4,
    "max_score": null,
    "hits": [
      {
        "_index": "my_percent",
        "_type": "doc",
        "_id": "vkFvYGMB_zM1P5OLcYkS",
        "_score": null,
        "_source": {
          "a": 8,
          "b": 108
        },
        "sort": [
          108
        ]
      },
      {
        "_index": "my_percent",
        "_type": "doc",
        "_id": "vUFvYGMB_zM1P5OLWYkM",
        "_score": null,
        "_source": {
          "a": 7,
          "b": 107
        },
        "sort": [
          107
        ]
      },
      {
        "_index": "my_percent",
        "_type": "doc",
        "_id": "vEFvYGMB_zM1P5OLRok1",
        "_score": null,
        "_source": {
          "a": 6,
          "b": 106
        },
        "sort": [
          106
        ]
      },
      {
        "_index": "my_percent",
        "_type": "doc",
        "_id": "u0FvYGMB_zM1P5OLJImy",
        "_score": null,
        "_source": {
          "a": 5,
          "b": 105
        },
        "sort": [
          105
        ]
      }
    ]
  }
}

请注意,百分位数聚合的结果是近似值。

总的来说,这看起来像是 pandas 更好地解决的任务。或 Spark工作。

希望有帮助!

关于elasticsearch - 按百分位数过滤,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50166949/

相关文章:

matlab - 使用 accumarray MATLAB 时改进代码/删除 for-loop

elasticsearch - Elasticsearch转义斜线

elasticsearch - ElasticSearch和嵌套查询

c# - 使用 LINQ 计算百分位数

python - 使用 Numeric Python 的数组的逐元素中值和百分位数

python - 使用python如何计算四分位数/百分位数并给出创建新列进行分析的标准?

elasticsearch - 如何使用同义词模糊搜索?

elasticsearch - 列表字段上针对自身的重要术语聚合

ruby - rubygem elasticsearch的语法错误