2015-09-14 2 views
1

У меня есть таблица с 604 строками, и я пытаюсь запустить mapreduce, но я получаю некоторые странные результаты. Это упрощенная версия, команда result.total = values.length должна быть возвращена 604 вместо 5. Не могли бы вы помочь мне получить ошибку в этом коде?Я теряю строки в процессе сокращения карты?

db.foo.mapReduce(
     function() { 
      emit("ALL" , this.libres) 
     }, 
     function(key, values) { 
      result = {total: 0,count:0}; 
      result.total=values.length; 
      for (var i= 0; i < values.length; i++) { 
        if (values[i]==0){result.count++} 
      } 
      return result 
     }, 
     {out:{inline:1}}) 



    { 
    "results" : [ 
      { 
        "_id" : "ALL", 
        "value" : { 
          "total" : 5, 
          "count" : 0 
        } 
      } 
    ], 
    "timeMillis" : 26, 
    "counts" : { 
      "input" : 604, 
      "emit" : 604, 
      "reduce" : 7, 
      "output" : 1 
    }, 
    "ok" : 1 
} 

ответ

2

С MongoDB mapReduce docs,

Поскольку возможно для вызова уменьшить функцию более одного раза того же ключа, следующие свойства должны быть верно:

того типа возвращаемый объект должен быть идентичен типу значения , испускаемого функцией карты.

функция уменьшения должна быть ассоциативной. Следующее утверждение должно быть истинным:

reduce(key, [ C, reduce(key, [ A, B ]) ]) == reduce(key, [ C, A, B ]) 

функция снижения должна быть идемпотентна. Убедитесь в том, что следующий утверждение верно:

reduce(key, [ reduce(key, valuesArray) ]) == reduce(key, valuesArray) 

Ваш уменьшить функцию не удовлетворяет этим условиям, и в соответствии с выходным "reduce" : 7, функция снижения был назван в 7 раз.

Ваш картограф выводит только 1 ключ, "ALL", поэтому функция уменьшения вызывала 7 раз для этого ключа, а последующие вызовы принимали выходы предыдущих вызовов в качестве входных данных.

Таким образом, вы видите неожиданные результаты для подсчета, потому что вход последнего вызова сокращения не является полным результатом картографии из 604 строк. Вместо этого вход является выходом некоторых предыдущих вызовов функции уменьшения.

Чтобы исправить это, вам нужно вернуться к вашей функции карты и изменить вывод на формат, который редуктор также может использовать в качестве выхода. Он может быть того же формата, что и текущий выход редуктора, но значения являются сводкой только для одного документа. Попробуйте следующее в вашей функции карты:

emit("ALL" , {total : 1, count : this.libres == 0 ? 1 : 0}) 

Тогда ваш редуктор должен суммировать значения total и count, всегда возвращая объект в том же формате, и вы должны получить ожидаемые значения.

result = { total: 0, count:0 }; 
for (var i = 0; i < values.length; i++) { 
    result.total += values[i].total; 
    result.count += values[i].count; 
} 
return result; 
Смежные вопросы