如果我理解正确,您的查询会执行以下操作:
- 按
key对所有条目进行分组
- 删除
count <= c 所在的所有分组条目
- 计算所有剩余的分组条目
那么SELECT key, count(*) 就没有用了,因为它再也不会被使用了。你可以简单地使用SELECT 1。
这个查询根本不需要排序。
基本上有3种方法可以加速这个查询:
获取更多服务器!这种聚合可以很容易地由 ES 在多个节点上并行执行。
不要在需要时聚合数据,而是使用每天执行一次的后台任务。此后台任务将基本上创建与您在下面的STORE 2 中看到的相同的数据。当然,这样一来,您将始终需要交付旧数据,但它会加快速度!
-
预聚合您的数据!使用一些简单的 Key-Value Storage(或者甚至可能只是坚持使用 ES 进行此操作),然后执行以下操作:
插入新文档时:获取其密钥,并增加数字。
当一个文档被删除时:获取它的键,并减少计数器。
那么你基本上有 2 个存储:1 个用于实际文档,1 个用于聚合数据,即
STORE 1:
[
{id: 1, key: foo, ...},
{id: 2, key: foo, ...},
{id: 3, key: bar, ...},
{id: 4, key: baz, ...}
]
STORE 2:
[
{id: foo, counter: 2},
{id: bar, counter: 1},
{id: baz, counter: 1}
]
这样您在从STORE 1 插入/删除文档时进行聚合。这在插入/删除时当然会更耗时,因为您每次都必须触摸 2 个数据存储。
但是现在您可以简单地计算来自STORE 2 的条目来获得您的结果。这将大大提高此操作的查询性能。
你看:这总是一个权衡。你必须决定你需要什么:
实时数据 + 高插入/删除性能 + 慢聚合
非实时数据+高插入/删除性能+快速聚合
实时数据 + 慢速插入/删除 + 快速聚合