#mongodb #node.js #mapreduce
#mongodb #node.js #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, и я все еще новичок в mongo, но я просматриваю документацию по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});
В качестве дополнительной сложности я делаю это в 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
(я пытался создать его в командной строке, но это все равно не помогло).
Итак, кто-нибудь делал mapreduce с node.js ? Это неправильное использование map reduce? может быть, другой способ сделать это? (возможно, просто зациклить и вставить в другую коллекцию?)
Спасибо за любые отзывы и советы! 🙂
ПРАВКА 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) {
Ответ №1:
Есть ошибка с {out: post_word_frequency}
maybe you want {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;
}, {});
Комментарии:
1. это потрясающе! Спасибо. Я проверю ответ, когда вернусь домой с работы, и дам вам знать, если он сработает. Я никогда раньше не видел подчеркивания, это можно загрузить в node.js ?
2. @AlexC просто
npm install underscore
amp;amp;var _ = require("underscore");
3. отлично! в вашем примере это определенно работает — я все еще пытаюсь собрать все точки в бите mongo, но я уверен, что это скоро произойдет. Огромное спасибо! 🙂