MongoDB中的MapReduce不会一次减少所有具有相同密钥的k-v对

时间:2018-10-30 13:20:14

标签: mongodb mapreduce

我已经从csv导入了具有以下信息的数据库:

  • 国家
  • 地区
  • 商品
  • 价格
  • 日期

(这是csv:https://www.kaggle.com/jboysen/global-food-prices

csv中的字符串按以下方式排序:

  • 国家1,区域1.1,商品X,价格,dateA
  • 国家1,区域1.1,商品X,价格,dateB
  • 国家1,区域1.1,商品Y,价格,dateA
  • 国家1,区域1.1,商品Y,价格,dateB
  • ...
  • 国家1,地区1.2,商品X,价格,dateA
  • 国家1,区域1.2,商品X,价格,dateB
  • 国家1,区域1.2,商品Y,价格,dateA
  • 国家1,区域1.2,商品Y,价格,dateB
  • ...
  • 国家2,区域2.1,商品X,价格,dateA
  • ...

我需要针对每个国家/地区,每种产品显示最高价格。

我写道:

1)包含关键国家/地区和商品以及价格价格的地图

var map = function() {
   emit({country: this.country_name, commodity: this.commodity_name}, {price: this.price});
};

2)一种减少功能,可扫描与钥匙相关的价格并查看最高价格

var reduce = function(key, values) {

   var maxPrice = 0.0;

   values.forEach(function(doc) {
      var thisPrice = parseFloat(doc.price);
      if( typeof doc.price != "undefined") {
            if (thisPrice > maxPrice) {
               maxPrice = thisPrice; 
            }
      }
   });

   return {max_price: maxPrice};
};

3)我将地图的约简发送到集合“ mr”

db.prices.mapReduce(map, reduce, {out: "mr"});

问题:

例如,如果我打开csv并通过以下方式手动订购:

  • 国家(升序)
  • 商品(升序)
  • 价格(降序)

我可以检查一下(以举例说明)在阿富汗,商品面包的最高价格是65.25

但是,当我检查M-R时,得出阿富汗面包最高价格为0。

发生了什么

csv中有10个区域记录了为阿富汗记录的面包。 我在reduce的最后一行添加了:

print("reduce with key: " + key.country + ", " + key.commodity + "; max price: " + maxPrice);

从理论上讲,如果我在mongodb日志中进行搜索,则应该只找到一个带有“减少键:阿富汗,面包;最高价格:???”的入口。 取而代之的是,我看到十行(区域的相同编号),每行具有不同的最高价格。 最后一个具有“最高价格0”。

我的假设:

似乎在发出之后,当调用reduce时,它不是在寻找具有相同密钥的所有k-v对,而是考虑了混杂的子组。

因此,回顾一下我在c​​sv结构上的入门示例:

  • 直到reduce扫描发出与“ afghanista,区域1,面包”相关的输出,然后对它们进行缩减
  • 然后减少与“阿富汗,区域1,商品X”有关的输出
  • 然后再次减少与“阿富汗,区域2,面包”相关的输出(而不是一次减少所有带有阿富汗尼+面包的k-v对)

我是否必须进行重新缩减以处理所有部分归约作业?

1 个答案:

答案 0 :(得分:0)

我设法解决了这个问题。 MongoDB不一定要一口气就减少所有具有相同密钥的k-v对。

可能发生(在这种情况下)MongoDB将对与特定键相关的kv对的子集执行约简,然后在对第二个约简进行第二次约简时将发送该第一个约简的输出与同一键相关的子集。

我的代码无法正常工作,因为:

  • MongoDB对与键“阿富汗面包”相关的k-v对子集进行了归约,其输出变量为“ maxPrice”
  • MongoDB将继续减少其他子集
  • MongoDB遇到“阿富汗面包”的另一个子集时,将采用第一个reduce的输出,并将其用作值
  • reduce的输出名为“ maxPrice”,而其他值名为“ price”
  • 因为我要求输入值“ doc.price”,所以当我扫描包含“ maxPrice”的文档时,它将被忽略

有2种方法可以解决此问题:

1)您为reduce输出变量使用与发出输出值相同的名称

2)您索引选择为键的属性,并在mapReduce()上使用“ sort”选项,以便与键相关的所有k-v对都可以一次性减少

第二种方法是,如果您不想放弃使用其他名称作为化简输出的名称(另外,由于每个键只进行一个化简,它具有更好的性能)。