繁体   English   中英

使用Map Reduce旋转数据时遇到问题

[英]Trouble Pivoting data with Map Reduce

我在使用map reduce旋转数据集时遇到麻烦。 我一直在使用MongoDB食谱寻求帮助,但是却遇到了一些奇怪的错误。 我想采用以下集合并对其进行透视,以便每个用户都有所有评论评分的列表。

我的收藏看起来像这样:

{
  'type': 'review',
  'business_id': (encrypted business id),
  'user_id': (encrypted user id),
  'stars': (star rating),
  'text': (review text),
}

地图函数(包装在Python中):

map = Code(""""
function(){
key = {user : this.user_id};
value = {ratings: [this.business_id, this.stars]};

emit(key, value);
}
""")

map函数应返回与键关联的值的数组... Reduce函数(包装在Python中):

reduce = Code("""
function(key, values){
var result = { value: [] };
temp = [];

for (var i = 0; i < values.length; i++){
temp.push(values[i].ratings);
}
result.value = temp;
return result;
}
""")

然而,返回的结果不是总少了一个等级。 实际上,某些用户没有返回任何值,这是不可能发生的。 一些条目如下所示:

{u'_id': {u'user: u'zwZytzNIayFoQVEG8Xcvxw'}, u'value': [None, [u'e9nN4XxjdHj4qtKCOPQ_vg', 3.0], None, [...]...]

我无法查明是什么原因导致了这个问题。 如果有3条评论,则它们在文档中都具有业务ID和等级。 另外,由于某种原因,在我的循环条件中使用'values.length + 1'会破坏values [i]。

编辑1

我已经接受了reduce本身被多次调用的事实,因此下面是我的新reducer。 这将返回[业务,等级,业务,等级]数组。 知道如何输出[业务,评级]数组而不是一个巨型数组吗?

function(key, value){
var result = { ratings:[] };
var temp = [];
values.forEach(function(value){
    value.ratings.forEach(function(rating){
        if(temp.indexof(rating) == -1){
            temp.push(rating);
        }
    });
});

result. rartings = temp;
return result;
}

这是一个测试示例:

1)添加一些示例数据:

db.test.drop();
db.test.insert(
  [{
    'type': 'review',
    'business_id': 1,
    'user_id': 1,
    'stars': 1,
  },
  {
    'type': 'review',
    'business_id': 2,
    'user_id': 1,
    'stars': 2,
  },
  {
    'type': 'review',
    'business_id': 2,
    'user_id': 2,
    'stars': 3,
  }]
);

2)地图功能

var map = function() {
  emit(this.user_id, [[this.business_id, this.stars]]);
};

在这里,我们设置结果,就像我们希望它们在过程结束时一样。 为什么? 因为如果用户只进行过一次审核(我们所依据的键),那么结果将不会经过简化阶段。

3)缩小功能

var reduce = function(key, values) {
  var result = { ratings: [] };
  values.forEach(function(value){
    result.ratings.push(value[0]);
  });

  return result;
};

在这里,我们收集了所有值,并记住我们将它们嵌套在map方法中,因此我们只需为每组结果选择第一个值即可。

4)运行地图reduce:

db.test.mapReduce(map, reduce, {finalize: final, out: { inline: 1 }});

替代方法-使用聚合框架

db.test.aggregate({
  $group: {
    _id: "$user_id", 
    ratings: {$addToSet: {business_id: "$business_id", stars: "$stars"}}
  }
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM