elasticsearch,redis,Mongodb,elasticsearch,Redis" /> elasticsearch,redis,Mongodb,elasticsearch,Redis" />

Mongodb 基于位置的服务系统中的跨场馆访客报告方法

Mongodb 基于位置的服务系统中的跨场馆访客报告方法,mongodb,elasticsearch,redis,Mongodb,elasticsearch,Redis,我正在为我的客户寻找一种解决跨场馆vistor报告的方法,他需要一个HTTP API,该API可以返回他在一天内访问过多家店铺的客户的总唯一计数(该API必须在1-2秒内返回) 原始数据样本(现实中有数百万条记录): 现在,我想计算交叉访问者报告。海事组织的步骤如下: 步骤1:聚合第1天到第6天的原始数据 -------------------------- CUSTOMER | VENUE VISIT -------------------------- cus_1 | [A, B,

我正在为我的客户寻找一种解决跨场馆vistor报告的方法,他需要一个HTTP API,该API可以返回他在一天内访问过多家店铺的客户的总唯一计数(该API必须在1-2秒内返回)

原始数据样本(现实中有数百万条记录):

现在,我想计算交叉访问者报告。海事组织的步骤如下:

步骤1:聚合第1天到第6天的原始数据

--------------------------
 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)
我尝试了一些解决方案:

  • 我首先使用MongoDB存储数据,然后使用Flask编写一个使用MongoDB实用程序的API:聚合、addToSet、组、计数。。。但API的响应时间是不可接受的
  • 然后,我在ElasticSearch的聚合命令集上切换到了hope,但它们不支持第一次“术语”聚合的输出结果上的管道组命令
  • 在那之后,我读了关于Redis集合,排序集合,。。。但是他们帮不上忙
  • 你能给我一个解决问题的线索吗


    提前感谢

    您可以通过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
        }
      }
    }