假设 ES 索引中的文档有两个字段,user_id
和 action_id
。如何统计用户,使得同时存在action_id = 1
和action_id = 2
的文档?
等效的 SQL 是
SELECT COUNT(DISTINCT `a`.`uuid`)
FROM `action` AS `a`
JOIN `action` AS `b` ON `a`.`user_id` = `b`.`user_id`
WHERE `a`.`action_id` = 1
AND `b`.`action_id` = 2
我找到了这样做的唯一方法:使用这些 action_id
请求两次所有唯一的 user_id
并在 ES 客户端上找到结果集的交集。然而,这种方法需要从 ES 传输数兆字节的数据,所以我正在寻找替代方法。
最佳答案
你可以这样做:
- 首先,您有一个查询仅使用
1
和2
操作来过滤您的文档(我不知道您是否可以使用其他操作类型) - 那么神奇的是聚合
- 第一个聚合是针对
user_id
的terms
,这样您就可以每个用户 进行单独计算
- 然后您使用
基数
子聚合来计算每个用户的不同操作数。由于查询是针对1
和2
的操作,因此该数字只能是 1 或 2 - 然后您使用
bucket_selector
子聚合来仅保留基数结果为2
的用户。
- 第一个聚合是针对
{
"size": 0,
"query": {
"bool": {
"should": [
{
"terms": {
"action_id": [
1,
2
]
}
}
]
}
},
"aggs": {
"users": {
"terms": {
"field": "user_id",
"size": 10
},
"aggs": {
"actions": {
"cardinality": {
"field": "action_id"
}
},
"actions_count_bucket_filter": {
"bucket_selector": {
"buckets_path": {
"totalActions": "actions"
},
"script": "totalActions >= 2"
}
}
}
}
}
}
结果如下所示:
"aggregations": {
"users": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 1,
"doc_count": 2,
"actions": {
"value": 2
}
},
{
"key": 5,
"doc_count": 2,
"actions": {
"value": 2
}
}
]
}
}
key
是其操作为1
和 2
的user_id。 bucket_selector
聚合在 ES 的 2.x+ 版本中可用。
关于join - 在 ElasticSearch 中模拟连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38266745/