MongoDB聚合日期匹配(100M +文档)

时间:2016-08-05 14:38:39

标签: mongodb aggregation-framework

我有一个记录所有用户操作的系统,如日志系统。我想执行一个聚合,按照其id对所有用户进行分组,并创建一个包含其操作的列表。

使用 110M文档的数据库,其中包含注册用户操作的以下结构:

user_action
{
    id_user: ObjectId(...),
    created_at: Date(...),
    action: {object},
}

(id_user和created_at都有索引。)

以下聚合尝试按给定日期对所有用户操作进行分组:

db.user_action.aggregate([
{ '$match': {'created_at': { $gte:ISODate("2016-06-05"), $lt:ISODate("2016-06-06")}}},
{ '$group': {
    '_id' :{'id_user': '$id_user'},
    actions: {
        $push: '$action'
    }
}}])

此汇总需要 2h和3h完成,但当天只有~3M文档:

db.count({'created_at': { $gte:ISODate("2016-06-05"), $lt:ISODate("2016-06-06")}})
2,7 M 

(计数持续5秒执行)

汇总结果如下:

{
    id_user: ObjectId(...),
    date: day_requested,
    actions:[action, action, ...]
}

汇总解释说查询正在使用IXSCAN。

{
    "waitedMS" : NumberLong(0),
    "stages" : [
        {
            "$cursor" : {
                "query" : {
                    "created_at" : {
                        "$gte" : ISODate("2016-06-05T00:00:00Z"),
                        "$lt" : ISODate("2016-06-06T00:00:00Z")
                    }
                },
                "fields" : {
                    "action" : 1,
                    "id_user" : 1,
                    "_id" : 0
                },
                "queryPlanner" : {
                    "plannerVersion" : 1,
                    "namespace" : "database1.collection1",
                    "indexFilterSet" : false,
                    "parsedQuery" : {
                        "$and" : [
                            {
                                "created_at" : {
                                    "$lt" : ISODate("2016-06-06T00:00:00Z")
                                }
                            },
                            {
                                "created_at" : {
                                    "$gte" : ISODate("2016-06-05T00:00:00Z")
                                }
                            }
                        ]
                    },
                    "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "created_at" : -1
                            },
                            "indexName" : "created_at",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "created_at" : [
                                    "(new Date(1465171200000), new Date(1465084800000)]"
                                ]
                            }
                        }
                    },
                    "rejectedPlans" : [ ]
                }
            }
        },
        {
            "$group" : {
                "_id" : {
                    "id_user" : "$id_user"
                },
                "actions" : {
                    "$push" : "$action"
                }
            }
        }
    ],
    "ok" : 1
}

如果我使用$限制管道而不是$ match,则查询最后 1 minut而不是3hours 。上一个查询有什么问题吗? 如何在合理的时间内执行该大小的聚合?

提前谢谢

0 个答案:

没有答案