需要一些有关MongoDB聚合/ mapreduce查询的帮助/指导

时间:2014-02-16 23:19:17

标签: mongodb

我有以下格式导入MongoDB的主机扫描数据:

{
    "_id" : ObjectId("52fd928c62c9815b36f66e68"),
    "date" : "1/1/2014",
    "scanner" : "123.9.74.172",
    "csp" : "aws",
    "ip" : "126.34.44.38",
    "port" : 445,
    "latt" : 35.685,
    "long" : 139.7514,
    "country" : "Japan",
    "continent" : "AS",
    "region" : 40,
    "city" : "Tokyo"
}
{
    "_id" : ObjectId("52fd928c62c9815b36f66e69"),
    "date" : "1/1/2014",
    "scanner" : "119.9.74.172",
    "csp" : "aws",
    "ip" : "251.252.216.196",
    "port" : 135,
    "latt" : -33.86150000000001,
    "long" : 151.20549999999997,
    "country" : "Australia",
    "continent" : "OC",
    "region" : 2,
    "city" : "Sydney"
}
{
    "_id" : ObjectId("52fd928c62c9815b36f66e6a"),
    "date" : "1/1/2014",
    "scanner" : "143.9.74.172",
    "csp" : "aws",
    "ip" : "154.248.219.132",
    "port" : 139,
    "latt" : 35.685,
    "long" : 139.7514,
    "country" : "Japan",
    "continent" : "AS",
    "region" : 40,
    "city" : "Tokyo"
}

由于我是mongo的新手,我一直在研究聚合框架和mapreduce来弄清楚如何创建一些查询。但是,我不能为我的生活找出如何做事情简单如:

  1. 使用“port”445计算不同的“ip”地址,其“日期”为“1/1/2014”

  2. 使用最开放的“端口”返回“ip”地址,按“日期”

  3. 为1月份的每个“日期”计算“csp”的不同“ip”地址

  4. 非常感谢任何帮助。我一直在阅读和阅读,但查询仍然超过16MB的限制。如下所示,我有很多条目:

    {
        "ns" : "brisket.my_models",
        "count" : 117715343,
        "size" : 25590813424,
        "avgObjSize" : 217.3957342502073,
        "storageSize" : 29410230112,
        "numExtents" : 33,
        "nindexes" : 1,
        "lastExtentSize" : 2146426864,
        "paddingFactor" : 1,
        "systemFlags" : 1,
        "userFlags" : 0,
        "totalIndexSize" : 3819900784,
        "indexSizes" : {
            "_id_" : 3819900784
        },
        "ok" : 1
    }
    

2 个答案:

答案 0 :(得分:0)

1)db.my_models.distinct( "ip", { "port": "445", "date": "1/1/2014" } )
2)

db.my_models.aggregate([
    { $group: 
        {
            _id: { ip: "$ip", date: "$date" },
            open_ports: { $addToSet: "$port" }
        }
    },
    { $unwind: "$open_ports" },
    { $group: 
        {
            _id: "$_id",
            open_ports_count: { $sum: 1 }
        }
    },
    { $sort: { "open_ports_count": -1 },
    { $limit: 10 }  
])

3)db.my_models.distinct( "ip", { "csp": <some_value>, "date": <RegExp_for_January> } )

在第3点,您可以在1月的任何一天使用正则表达式。您可以阅读有关JavaScript RegExp的信息来创建它 可能是我没有在第2点中找到你想要的内容。对“按日期”的另一个疑问是:

db.my_models.aggregate([
    { $match: { "date": <Your_date> } },
    { $group: 
        {
            _id: "$_id",
            open_ports: { $addToSet: "$port" }
        }
    },
    { $unwind: "$open_ports" },
    { $group: 
        {
            _id: "$_id",
            open_ports_count: { $sum: 1 }
        }
    },
    { $sort: { "open_ports_count": -1 },
    { $limit: 10 }  
])

答案 1 :(得分:0)

首先,我想首先说看看你提供的数据,你的日期对你来说将是一个问题,因为它们似乎是字符串而不是日期对象。因此,要在进一步的响应中添加任何内容,您应该查看(如果可能的话)将在 import 上转换的日期变为日期类型,或者至少使日期变为词汇。

对于您想要实现的某些结果,您可以在当前“日期”值上使用$substr操作,但这对您可能需要的初始过滤非常有帮助大数据。

ISO 8601样式日期是词汇,带有格式。当然,所有都是“01”中的2位数。但转换到日期会更好。

所有查询中的下一个案例是,如果您要点击 100MB ,那么您正在做的任何事情的第一阶段应该是尝试$match您专门查看的文档。如果测试中有必要,那么还要添加$limit阶段以保持设置大小。

如果 $ match 在一天结束时真的不适合你,那么MongoDB的下一个版本可以选择在aggregate的每个阶段使用磁盘上的临时存储。如果您正在评估/开发而不是生产,那么查看当前的开发分支版本(2.5.5)和installing可能是值得的。

因此,对于以下内容,我要记住日期是日期类型,我们正在使用聚合:

对于您的第一个问题(1)最重要的是过滤工作集,在日期范围(或绝对值为字符串)之间进行选择,如下所示:

db.collection.aggregate([

    // Limit if you really have to for a working set
    //{$limit: 10000 },

    // Filter with $match just the date and port needed
    {$match: 
        date: {$gte: new Date("2014-01-01"), $lt: new Date("2014-01-02")},
        port: "445"
    },

    // Group on "ip" 
    {$group: { _id: "$ip", count: {$sum: 1} } },

    // Optionally sort the results
    {$sort: { count: -1 } }

])

对于第二个问题(2),您可能希望将其分解为日期范围,并且使用实际日期或词汇字符串将有助于该范围。

db.collection.aggregate([
    // Limit if you really have to for a working set
    //{$limit: 10000 },

    // Filter with $match just the dates needed
    {$match: 
        date: {$gte: new Date("2014-01-01"), $lt: new Date("2014-01-31")},
    },

    // Moving things that can be some time of day to a whole date
    {$project:
        date: { 
            year: {$year: "$date"},
            month: {$month: "$date"},
            day: {$dayOfMonth: "$date" }  
        },
        ip: 1,
        port: 1
    },

    /* Optional for "unique" ports if required
    {$group: { _id: { date: "$date", ip: "$ip" }, ports: {$addToSet: "$port"} }},
    {$unwind: "$ports" },
    {$project: { date: "$_id.date", ip: "$_id.ip" } }
    */

    // Grouping on "date" and "ip" 
    {$group: { _id: { date: "$date", ip: "$ip" }, count: {$sum: 1} }},

    // Sort the results by date and 
    {$sort: { 
        "_id.date.year": -1, "_id.date.month": -1, "_id.date.day": -1, "count": -1 
    }},

    // Get the "first" count for each date. With nice dates
    {$group: {
        _id: {
            date: {$concat: [
                {$substr: [ "$_id.date.year", 0, 4 ] },
                "-",
                {$substr: [ "$_id.date.month", 0, 2 ] },
                "-",
                {$substr: [ "$_id.date.day", 0, 2 ] }
            ]},
            ip: "$_id.ip"
        },
        count: {$first: "$count" }
    }},

    // Optionally make the documents nicer
    {$project: { _id: 0, date: "$_id.date", ip: "$_id.ip", count: 1 } }

])

对于第三个问题(3),您希望在进入时过滤日期和相关文档:

db.collection.aggregate([
    // Limit if you really have to for a working set
    //{$limit: 10000 },

    // Filter with $match just the dates needed
    {$match: 
        date: {$gte: new Date("2014-01-01"), $lt: new Date("2014-01-31")},
    },

    // Moving things that can be some time of day to a whole date
    {$project:
        date: { 
            year: {$year: "$date"},
            month: {$month: "$date"},
            day: {$dayOfMonth: "$date" }  
        },
        ip: 1,
        csp: 1
    },

    // Get the set of "unique ip" per "date" and "csp"
    {$group: {
        _id: {
            date: {$concat: [
                {$substr: [ "$date.year", 0, 4 ] },
                "-",
                {$substr: [ "$date.month", 0, 2 ] },
                "-",
                {$substr: [ "$date.day", 0, 2 ] }
            ]},
            csp: "$csp"
        },
        ips: {$addToSet: "$ip" }
    }},

    // Unwind the *set* for the next stage
    {$unwind: "$ips" },

    // Count on the current *key*
    {$group: { _id: "$_id", count: {$sum: 1} }},

    // Clean up the documents
    {$project: { _id: 0, date: "$_id.date", csp: "$_id.csp", count: 1 } }

])

希望 $ match 的使用可以使您的工作集大小保持在限制之下,并且如果需要,请查看减少这些日期范围,将结果组合到另一个集合中并再次运行聚合而不是这些减少的结果。即使考虑到即将推出的允许磁盘使用的功能,这仍然是使用非常大的集合的最高性能方法。