首先,这是我第一次来Mongo ...
概念:
我的文字文件(目前)如下(例子)
{
"date": "date it was inserted"
"reported": 0,
"image_id": "image id"
"image_name": "image name"
"user": "user _id"
"word": "awesome"
}
这些单词将被复制,以便每个单词都可以与用户相关联......
问题:我需要执行一个Mongo查询,以便让我知道不是由给定用户创建的最常用的单词(描述图像)。 (见上文第3点)
我见过MapReduce算法,但从我读到的内容中有几个问题:
我考虑过每天在给定时间运行任务以存储文档(在不同的集合中)列表,给定用户未用于描述给定图像的单词的等级。我必须将此限制为300个结果或其他内容(任何关于适当限制的想法),例如:
{
user_id: "the user id"
[
{word: test, count: 1000},
{word: test2, count: 980},
{word: etc, count: 300}
]
}
我在这个解决方案中遇到的问题是:
也许我的方法没有任何意义......也许我在Mongo中缺乏经验会让我指出错误的“架构设计”。
对这种问题有什么好办法的想法?
对不起,感谢您的时间和帮助!
若昂
答案 0 :(得分:3)
如前所述,您可以使用易于使用的group命令,但您需要在客户端对结果进行排序。此外,结果作为单个BSON对象返回,因此必须相当小 - 少于10,000个键,否则您将获得异常。
基于您的数据结构的代码示例:
db.words.group({
key : {"word" : true},
initial: {count : 0},
reduce: function(obj, prev) { prev.count++},
cond: {"user" :{ $ne : "USERNAME_TO_IGNORE"}}
})
另一种选择是使用新的Aggregation framework,它将在2.2版本中发布。这样的事情应该有效。
db.words.aggregate({
$match : { "user" : { "$ne" : "USERNAME_TO_IGNORE"} },
$group : {
_id : "$word",
count: { $sum : 1}
}
})
或者你仍然可以使用MapReduce。实际上你可以限制和排序输出,因为结果是 一个集合。只需在输出上使用.sort()和.limit()。您也可以使用增量 map-reduce输出选项,它将帮助您解决性能问题。请查看out中的MapReduce参数。
Bellow它是一个例子,它使用增量功能将现有集合与words_usage集合中的新数据合并:
m = function() {
emit(this.word, {count: 1});
};
r = function( key , values ){
var sum = 0;
values.forEach(function(doc) {
sum += doc.count;
});
return {count: sum};
};
db.runCommand({
mapreduce : "words",
map : m,
reduce : r,
out : { reduce: "words_usage"},
query : <query filter object>
})
# retrieve the top 10 words
db.words_usage.find().sort({"value.count" : -1}).sort({"value.count" : -1}).limit(10)
我猜你可以每隔几分钟/小时在cron中运行上面的MapReduce命令,这取决于你想要的结果。对于更新查询条件,您可以使用单词文档创建日期。
一旦你拥有系统顶级单词集合,你就可以构建每个用户的顶级单词或者只是实时计算它们(取决于系统大小)。
答案 1 :(得分:1)
group
函数应该是MapReduce
的更简单版本。您可以像这样使用它来获得每个单词的总和:
db.coll.group(
{key: { a:true, b:true },
cond: { active:1 },
reduce: function(obj,prev) { prev.csum += obj.c; },
initial: { csum: 0 }
});