我正在尝试在mongodb中使用mapreduce运行pagerank。
我的文档采用以下格式:
{
"_id" : "u: 10000",
"value" : [
[
"u: 10000",
"s: 985272",
1
],
[
"s: 985272",
"u: 10000",
1
],
[
"u: 10000",
"s: 303770",
1
],
[
"s: 303770",
"u: 10000",
1
]
]
}
现在我认为第一步是按键收集链接。但是,每个文档都有几个出站链接。(这些恰好都是双向的)。
这是我的map和reduce函数:
m = function () {
for (var i = 0; i < this.value.length; i++){
var out = {};
out.out = this.value[i][1];
out.weight = this.value[i][2];
emit(this.value[i][0], [out]);
}
}
r = function(key, values){
var result = {
value: []
};
values.forEach(function(val) {
result.value.push({out: val.out, weight: val.weight});
});
return result;
}
问题是我不确定 emit 是否在每个文档中产生多个排放。当我得到的结果如下:
{
"_id" : "s: 1000082",
"value" : [
{
"out" : "u: 37317",
"weight" : 1
}
]
}
当我期望每个文档有多个项目时。
有人有什么想法吗?帮助将不胜感激!
编辑:
我并不完全满意,例如这样的事情是如何工作的?reduce结果看起来根本不像发射输出。
问题是您没有映射数组,但您的reduce正在尝试推送到数组。
如果你想让每个键映射到一个"out"和"weight"对的数组,那么你需要发出一个包含它的数组,在你的reduce中,你需要将这些数组连接在一起。
请记住,reduce 函数返回的对象的结构必须与映射函数发出的值的结构相同。
这意味着当你的映射发出(键,值)时,"value"的结构必须与reduce函数返回的结构相同。
如果将映射函数更改为此函数,则该值是具有字段"value"的文档,该字段是一个文档数组,每个文档都有字段"out"和字段"weight":
function () {
for (var i = 0; i < this.value.length; i++) {
key = this.value[i][0];
value = {value:[{out:this.value[i][1], weight:this.value[i][2]}]};
emit(key, value);
}
}
以及您的reduce函数,该函数构造的结果与您上面发出的值具有相同的结构(因为它只是连接了每个键传递的内容):
function (key, values) {
result = {value:[]};
for (var i in values) {
result.value = values[i].value.concat(result.value);
}
return result;
}
然后你会得到你所期望的。
{
"_id" : "s: 303770",
"value" : {
"value" : [
{
"out" : "u: 10000",
"weight" : 1
}
]
}
}
{
"_id" : "s: 985272",
"value" : {
"value" : [
{
"out" : "u: 10000",
"weight" : 1
}
]
}
}
{
"_id" : "u: 10000",
"value" : {
"value" : [
{
"out" : "s: 303770",
"weight" : 1
},
{
"out" : "s: 985272",
"weight" : 1
}
]
}
}