如何规范化/减少mongoDB中的时间数据?

如何规范化/减少mongoDB中的时间数据?,mongodb,mapreduce,Mongodb,Mapreduce,我在MongoDB中存储每分钟的性能数据,每个集合都是一种性能报告,每个文档都是阵列上端口在该时间点的度量值: { "DateTime" : ISODate("2012-09-28T15:51:03.671Z"), "array_serial" : "12345", "Port Name" : "CL1-A", "metric" : 104.2 } 每个“阵列\串行”最多可以有128个不同的“端口名”条目 随着数据的老化,我希望能够在不断增加的时间跨度内对其进行平均: 最多1

我在MongoDB中存储每分钟的性能数据,每个集合都是一种性能报告,每个文档都是阵列上端口在该时间点的度量值:

{
  "DateTime" : ISODate("2012-09-28T15:51:03.671Z"),
  "array_serial" : "12345",
  "Port Name" : "CL1-A",
  "metric" : 104.2
}
每个“阵列\串行”最多可以有128个不同的“端口名”条目

随着数据的老化,我希望能够在不断增加的时间跨度内对其进行平均:

  • 最多1周:分钟
  • 1周至1个月:5分钟
  • 1-3个月:15分钟
等等。。 以下是我计算时间平均值的方法,以便减少时间:

var resolution = 5; // How many minutes to average over     
var map = function(){
        var coeff = 1000 * 60 * resolution;
        var roundTime = new Date(Math.round(this.DateTime.getTime() / coeff) * coeff);
        emit(roundTime, { value : this.metric, count: 1 } );
 };
我将对reduce函数中的值和计数求和,并在finalize函数中得到平均值

正如您所看到的,这将在不考虑“端口名”值的情况下对数据进行平均,并且我需要对每个“数组_序列”上的每个“端口名”的值随时间进行平均

那么如何在上面的映射函数中包含端口名呢?emit的键应该是我稍后拆分的复合“array\u serial,PortName,DateTime”值吗?或者我应该使用查询功能来查询每个不同的串行、端口和时间?我是否正确地将此数据存储在数据库中

另外,据我所知,这些数据会保存到它自己的集合中,用这些平均数据替换集合中的数据的标准做法是什么


这就是你的意思吗?因为它没有将文档四舍五入到较低的5分钟(顺便说一句,我将“DateTime”改为“DateTime”):

据我所知,“$mod”操作符将返回分钟的剩余部分除以5,对吗

如果我可以让聚合框架而不是mapreduce执行此操作,这将对我非常有帮助。

用此平均数据替换集合中的数据的标准做法是什么

标准做法是保留原始数据并单独存储所有衍生数据

在您的情况下,它意味着:

  • 不要删除原始数据
  • 使用另一个集合(在同一MongoDB数据库中)存储平均值

以下是如何在聚合框架中实现这一点。我使用了一个小的简化——我只根据年、月和日期进行分组——在您的情况下,您需要为更细粒度的计算添加小时和分钟。如果得到的数据样本中的点分布不均匀,您还可以选择是否进行加权平均

project={"$project" : {
        "year" : {
            "$year" : "$DateTime"
        },
        "month" : {
            "$month" : "$DateTime"
        },
        "day" : {
            "$dayOfWeek" : "$DateTime"
        },
        "array_serial" : 1,
        "Port Name" : 1,
        "metric" : 1
    }
};
group={"$group" : {
        "_id" : {
            "a" : "$array_serial",
            "P" : "$Port Name",
            "y" : "$year",
            "m" : "$month",
                    "d" : "$day"
        },
        "avgMetric" : {
            "$avg" : "$metric"
        }
    }
};

db.metrics.aggregate([project, group]).result
我用一些随机样本数据运行了这个程序,得到了以下格式:

[
    {
        "_id" : {
            "a" : "12345",
            "P" : "CL1-B",
            "y" : 2012,
            "m" : 9,
            "d" : 6
        },
        "avgMetric" : 100.8
    },
    {
        "_id" : {
            "a" : "12345",
            "P" : "CL1-B",
            "y" : 2012,
            "m" : 9,
            "d" : 7
        },
        "avgMetric" : 98
    },
    {
        "_id" : {
            "a" : "12345",
            "P" : "CL1-A",
            "y" : 2012,
            "m" : 9,
            "d" : 6
        },
        "avgMetric" : 105
    }
]
如您所见,这是每个阵列、端口名、年/月/日期组合的一个结果。您可以使用$sort将它们放入要从那里处理它们的顺序中

以下是如何将项目步骤扩展到包括小时和分钟,同时将分钟四舍五入到每五分钟的平均值:

{
    "$project" : {
        "year" : {
            "$year" : "$DateTime"
        },
        "month" : {
            "$month" : "$DateTime"
        },
        "day" : {
            "$dayOfWeek" : "$DateTime"
        },
        "hour" : {
            "$hour" : "$DateTime"
        },
        "fmin" : {
            "$subtract" : [
                {
                    "$minute" : "$DateTime"
                },
                {
                    "$mod" : [
                        {
                            "$minute" : "$DateTime"
                        },
                        5
                    ]
                }
            ]
        },
        "array_serial" : 1,
        "Port Name" : 1,
        "metric" : 1
    }
}

希望您能够将其扩展到您的特定数据和需求。

您确实应该使用聚合框架,而不是映射/减少。您可以使用map/reduce来完成此操作,您只需要将端口和时间值作为键来发出。聚合框架将使其更加简单。你在使用2.2吗?我在使用2.2,我还没有开始研究聚合框架,我来看看。谢谢你的数据点是统一的吗?i、 e.超过60分钟是否保证获得相同数量的测量?测量是绝对的吗?与上一个或下一个数据点无关,是吗?数据点是否一致?i、 e.超过60分钟是否保证获得相同数量的测量?测量是绝对的吗?不是相对于上一个或下一个,是吗?你看到问题了吧?如果你在一小时内得到一次高测量值和10次低测量值,如果不是在同一时间段内,那么你应该称量它们,而不是直接进行平均。每个数据点是该时间段内的绝对平均值(在本例中为1分钟)。你是对的,尽管我可能每小时得不到60个数据点(有时收集器会漏掉一个点而不存储它),那么我应该在时间点上扔掉它,给它一个零的值,或者平均掉缺失值两边的值并分配该值吗?@AsyaKamsky-在聚合框架中如何做到这一点?我不确定我是否理解得足够好。在哪里可以平均到间隔的时间,并获得每个时间的平均度量?当然,这适用于每小时或每月的平均时间,但这项技术可以用于五分钟周期的平均吗?你能将$project中的日期时间舍入到平均值吗?当然。在投影中,对$hour做同样的事情,但对$minute使用$mod操作符和$mod:[“$min”,5]将所有分钟“舍入”到下一个较低的5或0分钟。啊,太好了,我来试一试。感谢您对ASIA的持续帮助!您使用“$min”是指$min运算符还是$min运算符?我想我看不出这将如何“舍入”一分钟的值。。。你能说得更详细一点吗?Asya,我已经为上述问题添加了更多细节,我认为$mod不是正确的方法。。。我需要将分钟向下舍入到最接近的5分钟值,在聚合框架中有没有办法做到这一点?数学地板($minute)/5)*5
{
    "$project" : {
        "year" : {
            "$year" : "$DateTime"
        },
        "month" : {
            "$month" : "$DateTime"
        },
        "day" : {
            "$dayOfWeek" : "$DateTime"
        },
        "hour" : {
            "$hour" : "$DateTime"
        },
        "fmin" : {
            "$subtract" : [
                {
                    "$minute" : "$DateTime"
                },
                {
                    "$mod" : [
                        {
                            "$minute" : "$DateTime"
                        },
                        5
                    ]
                }
            ]
        },
        "array_serial" : 1,
        "Port Name" : 1,
        "metric" : 1
    }
}