【问题标题】:Trouble Pivoting data with Map Reduce使用 Map Reduce 透视数据时遇到问题
【发布时间】:2013-08-18 08:00:48
【问题描述】:

我在使用 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 函数应该返回一个与键关联的值数组... 减少函数(用 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;
}
""")

但是,结果返回的评分比总评分少一个。事实上,有些用户没有返回 None,这是不可能的。一些条目如下所示:

{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。这将返回 [business, rating, business, rating] 的数组。知道如何输出 [business, rating] 数组而不是一个巨大的数组吗?

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

【问题讨论】:

    标签: javascript mongodb for-loop mapreduce


    【解决方案1】:

    这是一个测试示例:

    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) 运行 map reduce:

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

    替代方案 - 使用 aggregation framework:

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

    【讨论】:

      猜你喜欢
      • 2018-02-21
      • 2012-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-25
      • 1970-01-01
      • 2020-10-05
      相关资源
      最近更新 更多