Своеобразная карта / Уменьшить результат от CouchDB - PullRequest
1 голос
/ 24 июня 2011

Я использую CouchDB довольно долго без каких-либо проблем. Это до сих пор. Недавно я увидел на своей карте что-то / уменьшил результаты, которые я пропустил!

Это перед выполнением sum для переменной "avgs". Я в основном пытаюсь найти среднее значение всех значений, относящихся к определенному ключу. Ничего фантастического. Результат, как и ожидалось.

Обратите внимание на результат для отметки времени 1308474660000 (4-я строка в таблице): Before summing avgs


Теперь я sum массив "avgs". Теперь вот что-то особенное в результате. Сумма для ключа с отметкой времени 1308474660000 составляет null !! Почему CouchDB выплевывает null с для простого sum? Я попытался с пользовательской функцией сложения и ее же проблема.

enter image description here Может кто-нибудь объяснить мне, почему эта проблема связана с моей картой / уменьшить результат?

Версия CouchDB: 1.0.1


UPDATE:

После восстановления я получаю ошибку уменьшения переполнения!

Error: reduce_overflow_error

Reduce output must shrink more rapidly: Current output: '["001,1,1,1,1,1,11,1,1,1,1,1,1,11,1,1,1,1,1,1,11,1,1,1,1,1,1,11,1,1,1,1,1,101,1,1,1,1,1,1,11,1,1,1,1'... (first 100 of 396 bytes)

Это моя модифицированная функция уменьшения:

function (key, values, rereduce) {
  if(!rereduce) {
    var avgs = [];
    for(var i=values.length-1; i>=0 ; i--) {
      avgs.push(Number(values[i][0])/Number(values[i][1]));
    }
    return avgs;
  } else {
    return sum(values);
  };
}

ОБНОВЛЕНИЕ 2:

Ну, теперь стало еще хуже. Его выборочно уменьшать. Кроме того, те, которые были восстановлены, показывают неправильные результаты. Длина значения в 4-й строке для отметки времени (1308474660000) должна быть 2, а не 3.

enter image description here

ОБНОВЛЕНИЕ 3:

Я наконец получил его на работу. Я не понял специфику восстановления правильно. AFAIK, Couchdb сама решает, как / когда переопределить. В этом примере всякий раз, когда массив был достаточно длинным для обработки, Couchdb отправлял его для восстановления. Таким образом, я в основном должен был sum дважды. Однажды в уменьшении, и снова в уменьшении.

function (key, values, rereduce) {
  if(!rereduce) {
    var avgs = [];
    for(var i=values.length-1; i>=0 ; i--) {
      avgs.push(Number(values[i][0])/Number(values[i][1]));
    }
    return sum(avgs);
  } else {
    return sum(values); //If my understanding of rereduce is correct, it only receives only the avgs that are large enough to not be processed by reduce.
  }
}

Ответы [ 3 ]

2 голосов
/ 25 июня 2011

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

Вы ожидаете массив из двух кортежей:

// Expectation
values = [ [value1, total1]
         , [value2, total2]
         , [value3, total3]
         ];

Во время повторного уменьшения функция получит старые результаты от себя раньше.

// Re-reduce values
values = [ avg1
         , avg2
         , avg3
         ]

Поэтому я бы начал с изучения того, как работает ваш код, если и когда rereduce истинно. Возможно, что-то простое исправит это (хотя часто мне приходится log() вещи, пока я не нахожу проблему.)

function(keys, values, rereduce) {
  if(rereduce)
     return sum(values);

  // ... then the same code as before.
}
1 голос
/ 25 июня 2011

Я уточню свой комментарий по счету / сумме, на случай, если вам интересно.

Этот код не тестировался, но, надеюсь, вы поймете идею.Конечным результатом всегда является простой объект {"count":C, "sum":S}, и вы знаете среднее значение, вычисляя S / C.

function (key, values, rereduce) {
  // Reduce function
  var count = 0;
  var sum = 0;
  var i;

  if(!rereduce) {
    // `values` stores actual map output
    for(i = 0; i < values.length; i++) {
      count += Number(values[i][1]);
      sum += Number(values[i][0]);
    }

    return {"count":count, "sum":sum};
  }

  else {
    // `values` stores count/sum objects returned previously.
    for(i = 0; i < values.length; i++) {
      count += values[i].count;
      sum   += values[i].sum;
    }

    return {"count":count, "sum":sum};
  }
}
0 голосов
/ 04 апреля 2012

Я использую следующий код для усреднения.Надеюсь, это поможет.

function (key, values) {
    return sum(values)/values.length;    
}
...