3

假设我有来自 Twitter API 的流数据,并且我将数据作为文档存储在 MongoDB 中。我试图找到的是screen_nameunder的计数entities.user_mentions

{
    "_id" : ObjectId("50657d5844956d06fb5b36c7"),
    "contributors" : null,
    "text" : "",
    "entities" : {
        "urls" : [ ],
        "hashtags" : [
            {
                "text" : "",
                "indices" : [
                    26,
                    30
                ]
            },
            {
                "text" : "",
                "indices" : []
            }
        ],
        "user_mentions" : [ 
                {
                    "name":"Twitter API", 
                    "indices":[4,15], 
                    "screen_name":"twitterapi", 
                    "id":6253282, "id_str":"6253282"
                }]
    },
    ...

我尝试使用 map reduce:

map = function() {
    if (!this.entities.user_mentions.screen_name) {
        return;
    }

    for (index in this.entities.user_mentions.screen_name) {
        emit(this.entities.user_mentions.screen_name[index], 1);
    }
}

reduce = function(previous, current) {
    var count = 0;

    for (index in current) {
        count += current[index];
    }

    return count;
}

result = db.runCommand({
    "mapreduce" : "twitter_sample",
    "map" : map,
    "reduce" : reduce,
    "out" : "user_mentions"
});

但它并不完全工作......

4

1 回答 1

4

由于entities.user_mentions是一个数组,因此您希望为每个 screen_name 发出一个值map()

var map = function() {
    this.entities.user_mentions.forEach(function(mention) {
        emit(mention.screen_name, { count: 1 });
    })
};

然后按以下中的唯一 screen_name 计算值reduce()

var reduce = function(key, values) {
    // NB: reduce() uses same format as results emitted by map()
    var result = { count: 0 };

    values.forEach(function(value) {
        result.count += value.count;
    });

    return result;
};

注意:要调试您的 map/reduce JavaScript 函数,您可以使用print()printjson()命令。输出将出现在您的mongod日志中。

编辑:为了比较,这里是一个在 MongoDB 2.2 中使用新聚合框架的例子:

db.twitter_sample.aggregate(
    // Project to limit the document fields included
    { $project: {
        _id: 0,
        "entities.user_mentions" : 1
    }},

    // Split user_mentions array into a stream of documents
    { $unwind: "$entities.user_mentions" },

    // Group and count the unique mentions by screen_name
    { $group : {
        _id: "$entities.user_mentions.screen_name",
        count: { $sum : 1 }
    }},

    // Optional: sort by count, descending
    { $sort : {
        "count" : -1
    }}
)

原始的 Map/Reduce 方法最适合大型数据集,正如 Twitter 数据所暗示的那样。有关 Map/Reduce 与聚合框架限制的比较,请参阅 StackOverflow 问题MongoDB group()、$group 和 MapReduce的相关讨论。

于 2012-09-30T04:50:34.867 回答