elasticsearch - 按百分位数过滤
elasticsearch - filter by 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 个,即 a
从 1 到 10。然后我需要按 [=14 对这些结果进行排序=]降序排列,然后取分页后的结果(如第2页,每页10条)
想到的一个解决方案是:
获取文档总数。
将文档按a
排序,取对应的_id
,限制为0.1 * total_count
编写最终查询,类似id in (...) order by b
但是缺点也很明显:
如果我们谈论的是亚秒级延迟,那么似乎效率不高
如果我们在第一个查询中返回了太多 _id
,第二个查询可能无法工作(ES 默认只允许 1000。我当然可以更改配置,但总是有一个极限)。
如果事先不知道 a
的确切值,我怀疑是否有一种方法可以在一个查询中执行此操作,尽管我认为一种非常有效的方法是可行的。
我建议做一个 percentiles
aggregation as first query and 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
}
}
}
}
现在我们可以使用边界来执行 range
查询:
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
]
}
]
}
}
请注意,percentiles
聚合的结果是近似值。
总的来说,这看起来像是 pandas or a Spark 工作更好地解决的任务。
希望对您有所帮助!
假设我想按第 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 个,即 a
从 1 到 10。然后我需要按 [=14 对这些结果进行排序=]降序排列,然后取分页后的结果(如第2页,每页10条)
想到的一个解决方案是:
获取文档总数。
将文档按
a
排序,取对应的_id
,限制为0.1 * total_count
编写最终查询,类似
id in (...) order by b
但是缺点也很明显:
如果我们谈论的是亚秒级延迟,那么似乎效率不高
如果我们在第一个查询中返回了太多
_id
,第二个查询可能无法工作(ES 默认只允许 1000。我当然可以更改配置,但总是有一个极限)。
如果事先不知道 a
的确切值,我怀疑是否有一种方法可以在一个查询中执行此操作,尽管我认为一种非常有效的方法是可行的。
我建议做一个 percentiles
aggregation as first query and 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
}
}
}
}
现在我们可以使用边界来执行 range
查询:
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
]
}
]
}
}
请注意,percentiles
聚合的结果是近似值。
总的来说,这看起来像是 pandas or a Spark 工作更好地解决的任务。
希望对您有所帮助!