2011-05-24 16 views
1

我收藏了一大堆身體帖子。例如:試圖獲得MongoDB字段中每個單詞的計數是MapReduce的一項工作嗎?

posts = { { id: 0, body: "foo bar baz", otherstuff: {...} }, 
      { id: 1, body: "baz bar oof", otherstuff: {...} }, 
      { id: 2, body: "baz foo oof", otherstuff: {...} } 
     }; 

我想弄清楚如何遍歷集合中的每個文檔並對每個帖子主體中的每個單詞進行計數。

post_word_frequency = { { foo: 2 }, 
         { bar: 2 }, 
         { baz: 3 }, 
         { oof: 2 }, 
         }; 

我從來沒有使用MapReduce和我還是很新鮮蒙戈,但我對http://cookbook.mongodb.org/patterns/unique_items_map_reduce/

map = function() { 
    words = this.body.split(' '); 
    for (i in words) { 
     emit({ words[i] }, {count: 1}); 
    } 
}; 

reduce = function(key, values) { 
    var count = 0; 
    values.forEach(function(v) { 
      count += v['count']; 
    }); 
    return {count: count}; 
}; 

db.posts.mapReduce(map, reduce, {out: post_word_frequency}); 

看文檔作爲一個有點額外的困難的,我m在node.js中執行(使用node-mongo-native,但如果有更簡單的方法,則願意切換到reduce查詢)。

var db = new Db('mydb', new Server('localhost', 27017, {}), {native_parser:false}); 
    db.open(function(err, db){ 
      db.collection('posts', function(err, col) { 
       db.col.mapReduce(map, reduce, {out: post_word_frequency}); 
      }); 
    }); 

到目前爲止,我有在該節點的告訴我ReferenceError: post_word_frequency is not defined困難(我試過在shell創建它,但仍然沒有幫助)。

那麼有沒有人用node.js做過mapreduce?這是地圖縮小的錯誤用法嗎?也許另一種方式來做到這一點? (也許只是循環和插入另一個集合?)

感謝您的任何反饋意見和建議! :)

EDIT Ryanos下面是正確的(謝謝!)我的基於MongoDB的解決方案中缺少的一件事是找到集合並將其轉換爲數組。

db.open(function(err, db){ 
    db.collection('posts', function(err, col) { 
      col.find({}).toArray(function(err, posts){ // this line creates the 'posts' array as needed by the MAPreduce functions. 
        var words= _.flatten(_.map(posts, function(val) { 

回答

2

即使世界中的錯誤與{out: post_word_frequency}也許你想{out: "post_word_frequency"}但應該沒有這個out的變量。

使用underscore它可以簡單地完成。

/* 
    [{"word": "foo", "count": 1}, ...] 
*/ 
var words = _.flatten(_.map(posts, function(val) { 
    return _.map(val.body.split(" "), function(val) { 
     return {"word": val, "count": 1}; 
    }); 
})); 

/* 
    { 
    "foo": n, ... 
    } 
*/ 
var count = _.reduce(words, function(memo, val) { 
    if (_.isNaN(++memo[val.word])) { 
     memo[val.word] = 1; 
    } 
    return memo; 
}, {}); 

Live Example

_.reduce_.map_.isNaN_.flatten

+0

這是真棒!謝謝。當我下班回家時,我會檢查答案,並讓你知道它是否會發生。我從來沒有見過下劃線,可以加載到node.js中嗎? – 2011-05-24 18:24:55

+0

@AlexC只是'npm install underscore' &&'var _ = require(「underscore」);' – Raynos 2011-05-24 18:34:25

+0

太棒了!這絕對是你的榜樣 - 我仍然試圖收集mongo位上的所有點,但我相信很快就會到來。謝謝! :) – 2011-05-25 00:35:32

相關問題