{
"_id" : ObjectId("59b7d232cb4ddc345c3bcef4"),
"user_device_id" : ObjectId("59b7d21017c8a62f3a40c0bf"),
"generated_at" : ISODate("2017-09-12T12:24:48.182Z"),
"game_id" : ObjectId("59b683d4dd30770001513c75"),
"device_type" : "iPhone 8 android sdk",
"session_duration": 1000, /* in milliseconds */
"device_os" : "iOS android sdk",
"event_type" : "level_increase" /* new_user, game_session, ....*/
} // events collection
{
"_id" : ObjectId("59b7d21017c8a62f3a40c0bf"),
"generated_at" : ISODate("2017-09-12T12:24:48.182Z"),
"game_id" : ObjectId("59b683d4dd30770001513c75"),
"device_type" : "iPhone 8 android sdk",
"device_os" : "iOS android sdk"
} // user_devices collection
我有一个' 活动'具有类似上述结构的集合。我正在 mongo 作为大数据分析平台,以便在几毫秒内获得聚合查询的最佳速度,或者如果没有,那么在几秒钟内我应该将任何想法编入索引。文件总量可能约为10-100亿。
聚合查询基本上在两个日期之间,即每个游戏的用户保留,每个游戏的平均用户会话,每个游戏的总用户数,基于 device_type 或 device_os 的查询游戏。
ATM我将日期字段编入索引。
以下是第1天用户保留查询的示例:
UserDevice.aggregate(
[
{$match: {generated_at: {$gte: first_date, $lt: end_date}, game_id: "some game_id"}},
{
$lookup: {
from: "events",
localField: "_id",
foreignField: "user_device_id",
as: "event_docs"
}
},
{
$group: {
_id: { day: { $dayOfMonth: {$add: ["$generated_at", 1000*3600*24*1]}}, month: {$month: {$add: ["$generated_at", 1000*3600*24*1]}}, year: { $year: {$add: ["$generated_at", 1000*3600*24*1]} } }, total_users: {$sum: 1},
returned_users: {
$sum: {
$cond: { if: { $eq: [
{
$filter: {
input: "$event_docs",
as: "ed",
cond: {
$and: [
{$eq: [{ $dayOfMonth: {$add: ["$generated_at", 1000*3600*24*1]}}, { $dayOfMonth: "$$ed.generated_at" }]},
{$eq: [{ $month: {$add: ["$generated_at", 1000*3600*24*1]}}, { $month: "$$ed.generated_at" }]},
{$eq: [{ $year: {$add: ["$generated_at", 1000*3600*24*1]}}, { $year: "$$ed.generated_at" }]},
{$ne: ["$$ed.event_type", "new_user"]}
]
}
}
}, []
]}, then: 0, else: 1
}
}
}
}
}, {
$sort: {"_id.year": 1, "_id.month": 1, "_id.day": 1}
}
]).exec(function(err, results) {
if (err) throw err;
var latency = Date.now() - startTime;
console.log("RETENTION RESULTS", JSON.stringify(results), "| latency:", latency,"ms");
});
Mongo版本: 3.4.7
答案 0 :(得分:1)
首先,只使用MongoDB 3.2对聚合中的索引进行全部聚合。
在版本3.2中更改:从MongoDB 3.2开始,索引可以覆盖 聚合管道。在MongoDB 2.6和3.0中,索引无法覆盖 一个聚合管道,因为即使管道使用索引, 聚合仍然需要访问实际文档。 https://docs.mongodb.com/manual/core/aggregation-pipeline/#pipeline-operators-and-indexes
确保您拥有此版本或更新版本。
通常,您可以为查询的$match
部分中的所有字段创建索引。
我还建议通过mongodb docs的'Aggregation Pipeline Optimization'部分。它可能会有所帮助
对于前者您可以使用explain
选项查看如何执行查询,并了解是否可以优化查询。