Mongodb 基于位置的服务系统中的跨场馆访客报告方法
我正在为我的客户寻找一种解决跨场馆vistor报告的方法,他需要一个HTTP API,该API可以返回他在一天内访问过多家店铺的客户的总唯一计数(该API必须在1-2秒内返回) 原始数据样本(现实中有数百万条记录): 现在,我想计算交叉访问者报告。海事组织的步骤如下: 步骤1:聚合第1天到第6天的原始数据Mongodb 基于位置的服务系统中的跨场馆访客报告方法,mongodb,
elasticsearch,redis,Mongodb,
elasticsearch,Redis,我正在为我的客户寻找一种解决跨场馆vistor报告的方法,他需要一个HTTP API,该API可以返回他在一天内访问过多家店铺的客户的总唯一计数(该API必须在1-2秒内返回) 原始数据样本(现实中有数百万条记录): 现在,我想计算交叉访问者报告。海事组织的步骤如下: 步骤1:聚合第1天到第6天的原始数据 -------------------------- CUSTOMER | VENUE VISIT -------------------------- cus_1 | [A, B,
--------------------------
CUSTOMER | VENUE VISIT
--------------------------
cus_1 | [A, B, C]
cus_2 | [A]
cus_3 | [A, C]
步骤2:生成最终结果
Total unique cross-customer: 2 (cus_1 and cus_3)
我尝试了一些解决方案:
提前感谢您可以通过Elasticsearch轻松实现这一点,方法是利用一个
日期(u直方图
按天聚合到bucket,两个术语
聚合(第一个bucket按客户
,然后按场馆
),然后在任何给定的一天仅选择访问过多个场馆的客户。看起来是这样的:
POST /sales/_search
{
"size": 0,
"aggs": {
"by_day": {
"date_histogram": {
"field": "date",
"interval": "day"
},
"aggs": {
"customers": {
"terms": {
"field": "customer.keyword"
},
"aggs": {
"venues": {
"terms": {
"field": "venue.keyword"
}
},
"cross_selector": {
"bucket_selector": {
"buckets_path": {
"venues_count": "venues._bucket_count"
},
"script": {
"source": "params.venues_count > 1"
}
}
}
}
}
}
}
}
}
在结果集中,您将获得预期的客户1和客户3
更新:
另一种方法是使用一个函数来自己实现逻辑。它有点复杂,根据您拥有的文档和硬件的数量,可能无法很好地执行,但以下算法将完全按照您的预期生成响应2:
POST sales/_search
{
"size":0,
"aggs": {
"unique": {
"scripted_metric": {
"init_script": "params._agg.visits = new HashMap()",
"map_script": "def cust = doc['customer.keyword'].value; def venue = doc['venue.keyword'].value; def venues = params._agg.visits.get(cust); if (venues == null) { venues = new HashSet(); } venues.add(venue); params._agg.visits.put(cust, venues)",
"combine_script": "def merged = new HashMap(); for (v in params._agg.visits.entrySet()) { def cust = merged.get(v.key); if (cust == null) { merged.put(v.key, v.value) } else { cust.addAll(v.value); } } return merged",
"reduce_script": "def merged = new HashMap(); for (agg in params._aggs) { for (v in agg.entrySet()) {def cust = merged.get(v.key); if (cust == null) {merged.put(v.key, v.value)} else {cust.addAll(v.value); }}} def unique = 0; for (m in merged.entrySet()) { if (m.value.size() > 1) unique++;} return unique"
}
}
}
}
答复:
{
"took": 1413,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 7,
"max_score": 0,
"hits": []
},
"aggregations": {
"unique": {
"value": 2
}
}
}
嗨,瓦尔,谢谢你的快速帮助。但是我只想要唯一的计数结果(在本例中:2个唯一计数),因为客户存储桶结果列表可能有50k条记录。所以我不想提取这个bucket json并获取其长度以在我的API中返回该数字。这是可能的吗?在这种情况下,另一种方法将涉及使用聚合来吐出该数字。我认为绝对可行。我已经更新了我的答案以提供第二种选择。我非常感谢您的帮助!现在我可以在亚秒的响应时间内产生我想要的结果。太棒了,很高兴它有帮助!我的算法相当愚蠢,因为我只关注可行性而不是性能,你可能可以改进它以更快。
{
"took": 1413,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 7,
"max_score": 0,
"hits": []
},
"aggregations": {
"unique": {
"value": 2
}
}
}