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()andprintjson()コマンドを使用できます。出力はmongodログに表示されます。

編集: 比較のために、MongoDB 2.2 で新しいAggregation Frameworkを使用した例を次に示します。

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 と Aggregation Framework の制限の比較については、StackOverflow の質問MongoDB group(), $group および MapReduceに関する関連する議論を参照してください。

于 2012-09-30T04:50:34.867 に答える