我有以下格式导入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来弄清楚如何创建一些查询。但是,我不能为我的生活找出如何做事情简单如:
使用“port”445计算不同的“ip”地址,其“日期”为“1/1/2014”
使用最开放的“端口”返回“ip”地址,按“日期”
为1月份的每个“日期”计算“csp”的不同“ip”地址
非常感谢任何帮助。我一直在阅读和阅读,但查询仍然超过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
}
答案 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 的使用可以使您的工作集大小保持在限制之下,并且如果需要,请查看减少这些日期范围,将结果组合到另一个集合中并再次运行聚合而不是这些减少的结果。即使考虑到即将推出的允许磁盘使用的功能,这仍然是使用非常大的集合的最高性能方法。