2011-05-24 1 views
1

J'ai une collection avec un tas de poteaux. Par exemple:Essayer d'obtenir un compte de chaque mot dans un champ MongoDB est-ce un travail pour MapReduce?

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

Je voudrais savoir comment faire une boucle à travers chaque document de la collection et porter un décompte de chaque mot dans chaque corps après.

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

Je ne l'ai jamais utilisé MapReduce et je suis encore très frais à mongo, mais je suis à la recherche à la documentation sur 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}); 

un peu comme une difficulté supplémentaire, je Je le fais dans node.js (avec node-mongo-native, mais je suis prêt à passer à faire la requête reduce s'il y a un moyen plus simple).

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}); 
      }); 
    }); 

Jusqu'à présent, je vais avoir du mal à ce nœud me dit ReferenceError: post_word_frequency is not defined (j'ai essayé de créer dans la coquille, mais encore n'a pas aidé).

Alors, est-ce que quelqu'un a fait un mapreduce avec node.js? Est-ce la mauvaise utilisation de la carte? peut-être une autre façon de le faire? (peut-être juste boucle et upsert dans une autre collection?)

Merci pour vos commentaires et conseils! :)

EDIT Ryanos ci-dessous était correct (merci!) Une chose qui manque à ma solution basée sur MongoDB était de trouver la collection et de la convertir en tableau.

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) { 

Répondre

2

Theres un bug avec {out: post_word_frequency} peut-être vous voulez {out: "post_word_frequency"} mais il devrait fonctionner sans cette variable out.

En utilisant underscore, cela peut être fait simplement.

/* 
    [{"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

c'est génial! Merci. Je vais vérifier la réponse quand je rentrerai du travail et je vous dirai si ça va. Je n'ai jamais vu de trait de soulignement avant, peut-il être chargé dans node.js? –

+0

@AlexC juste 'npm install underscore' &&' var _ = require ("soulignement"); ' – Raynos

+0

génial! ça marche vraiment dans ton exemple - j'essaye toujours de rassembler tous les points sur le mongo, mais je suis sûr que ça viendra bientôt. Merci une tonne! :) –

Questions connexes