MongoDB并发计数



我有一个集合,其中start_time和end_time表示会话我需要在给定的小时内计算最大并发会话。

类似于按小时聚合和分组。

最有效的方法是什么?

您的查询将这样做:

db.collection_name.aggregate ([{$组:{_id: $小时no_of_sessions:{$金额:1}}}))

$hour是您的时间变量(假设您只是存储小时,如果不是,您可以应用(hour: {$hour: "$date"})函数从date中获取它)。

如果时间是1:01到2:59,那么您需要将_id定义为复合键。例如:_id: {start_time: $start_time, end_time: $end_time}.

为了得到更具体的答案,请给出确切的情况。

干杯!

这种聚合类型的问题在于,具有"start_time"one_answers"end_time"的"会话"实际上因此可以"发出"跨越每个分组小时的小时数,因此它在多个小时时间段内存在,直到会话结束。这可能会持续数小时

这里的另一个主要问题是会话可能确实在您想要查看的时间段之前"开始",或者甚至在指定范围之后"结束",例如一天。在这里,您需要考虑通常要寻找的"start_time"小于您正在查看的一天的结束时间,而"end_time"大于您正在查看的一天的开始时间。

即使如此,也有其他的考虑,比如在分析的时候是否有一个"end_time"?通常,处理这个问题的最佳方法是考虑一个合理的"会话寿命"值,并将其考虑到基本查询选择中。

所以有了几个变量,我们基本上得出了选择的"基本标准":

  var startDay = new Date("2015-08-30"),
      endDay  = new Date("2015-08-31"),
      oneHour = 1000*60*60,
      sessionTime = 3*oneHour;
  var query = {
    "start_time": { 
      "$gte": new Date(startDay.valueOf()-sessionTime),
      "$lt": endDay
    },
    "$or": [
      { "end_time": { "$exists": false } },
      { "end_time": null },
      { "end_time": { 
        "$lt": new Date(endDay.valueOf()+sessionTime),
        "$gte": startDay
      }}
    ]
  };

以3小时的窗口为例,在"可能的"输出中也包括当前日期以外的日期。

接下来考虑一些要处理的数据作为示例:

  { "_id": 1, "start_time": new Date("2015-08-29T23:30"), "end_time": new Date("2015-08-29T23:45") },
  { "_id": 2, "start_time": new Date("2015-08-29T23:30"), "end_time": new Date("2015-08-30T00:45") },
  { "_id": 3, "start_time": new Date("2015-08-30T00:30"), "end_time": new Date("2015-08-30T01:30") },
  { "_id": 4, "start_time": new Date("2015-08-30T01:30"), "end_time": new Date("2015-08-30T01:45") },
  { "_id": 5, "start_time": new Date("2015-08-30T01:30"), "end_time": new Date("2015-08-30T03:45") },
  { "_id": 6, "start_time": new Date("2015-08-30T01:45"), "end_time": new Date("2015-08-30T02:30") },
  { "_id": 7, "start_time": new Date("2015-08-30T23:30"), "end_time": null },
  { "_id": 8, "start_time": new Date("2015-08-30T23:30") },
  { "_id": 9, "start_time": new Date("2015-08-31T01:30") }

如果我们查看日期范围和常规查询选择的标准,那么您可以预期记录2到8将在我们正在查看的当天被考虑,因为它们要么在当天"结束",要么在当天"开始"。"会话窗口"主要是因为一些数据没有"end_time",要么是null,要么不存在。这个"窗口"有助于过滤掉其他不相关的数据,这些数据可能来自比正在查看的数据更近的日期,并保持大小合理。

一个快速的视觉扫描应该告诉你每小时的计数应该是这样的:

  0: 2
  1: 4,
  2: 2,
  3: 1
  23: 2

使用mapReduce比使用其他聚合介质更好地处理实际过程。这是因为所需的条件逻辑允许将"单个文档"作为多个周期有效的值"发出"。所以这里需要一个固有的"循环"

  db.sessions.mapReduce(
    function() {
      var oneHour = 1000*60*60,
          start = (this.start_time > startDay)
            ? ( this.start_time.valueOf() - ( this.start_time.valueOf() % oneHour ))
            : startDay,
          end = (this.hasOwnProperty("end_time") && this.end_time != null)
            ? ( this.end_time.valueOf() - ( this.end_time.valueOf() % oneHour ))
            : endDay;
      // Uncomment to Emit blank values for each hour on first iteration
      /*
      if ( count == 0 ) {
        for ( var x = 1; x <= 24; x++ ) {
          emit(x,0);
        }
        count++;
      }
      */
      for ( var y = start; y <= end && (y-startDay)/oneHour < 24; y+= oneHour) {
        emit(
          (y-startDay ==0) ? 0 : ((y-startDay)/oneHour)
          ,1
        );
      }
    },
    function(key,values) {
      return Array.sum(values);
    },
    { 
      "out": { "inline": 1 },
      "scope": { 
        "startDay": startDay.valueOf(),
        "endDay": endDay.valueOf(),
        "count": 0
      },
      "query": query
    }
  )

结合前面设置的变量,这将正确地计算每小时内当前运行的会话数:

"results" : [
    {
        "_id" : 0,
        "value" : 2
    },
    {
        "_id" : 1,
        "value" : 4
    },
    {
        "_id" : 2,
        "value" : 2
    },
    {
        "_id" : 3,
        "value" : 1
    },
    {
        "_id" : 23,
        "value" : 2
    }
],

每个记录的基本操作如下:

  • 将开始和结束时间分别四舍五入为1小时

  • 将每个值替换为正在查看的日期的startDay或开始时间在当前日期之前的endDay,或者end_time不存在

  • 从开始时间开始,以一个小时的增量循环,直到到达结束时间或到达差一天的时间。

  • 每次排放都是一个"计数",表示与起始日的小时差。
  • 减少到每小时总数

有一个可选的部分,也将发出0值每小时的一天,因此,如果没有数据被记录,那么至少有输出该小时作为0

相关内容

  • 没有找到相关文章