Создание функции приведения, которая игнорирует дочерние элементы узла - PullRequest
0 голосов
/ 23 февраля 2020

У меня есть набор документов на диване БД, которые действуют как дерево. Каждый документ содержит поле ancestors, которое включает в себя список идентификаторов, которые представляют местоположение в дереве текущего документа. У некоторых документов есть значение, связанное с ними (число).

Если у документа нет собственного значения, его неявное значение является максимальным из всех его дочерних элементов. Но когда у документа есть своя собственная ценность, значение любого потомка игнорируется. Например,

  • Root (без значения, без предков) эффективное значение 7
    • Child1 (значение 5, предки = Root) эффективное значение 5
      • Внук 1 (значение 9, предки = Root, Child1) эффективное значение 9
    • Child2 (без значения, предки = Root) эффективное значение 7
      • Grandchild2 ( значение 3, предки = Root, Child2) эффективное значение 3
      • Grandchild3 (значение 7, предки = Root, Child2) эффективное значение 7
    • Child3 ( значение 6, предки = Root) эффективное значение 6

Я пытаюсь построить представление, которое позволяет мне получить эффективное значение для данного узла (я буду иметь полный путь, чтобы можно было указать путь или идентификатор). Итак, я пытаюсь сделать следующее:

  1. Излучить все, что имеет явное значение, в моей функции карты
  2. Создать функцию приведения, которая возвращает явное значение для узла, если он имеет один или находит максимальное число его дочерних элементов, если это не так.

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

  1. Grandchild 1 (значение 9) и Grandchild 3 (значение 7) попадают в один и тот же раздел, поэтому сначала уменьшаются, что приводит к значению 9
  2. Child Значение 1 (значение 5) уменьшается для ребенка 3 (значение 6), в результате чего значение 6 становится выигрышным, а знания о ребенке 1
  3. уменьшаются. Повторное уменьшение происходит для уменьшения ребенка 3 (значение 6) и внука 1 (значение 9), а результирующее значение равно 9, поскольку дочерний элемент 1 не участвует в этом уменьшении, мы не знаем, что на самом деле следует заменить 9 на 5, поэтому мы получаем неправильный результат.

Возможно ли реализовать эту логику c в функции уменьшения вида дивана?

Мои текущие реализации:

Функция карты

function (doc) {
  if (doc.ancestors && doc.data) {
    // For anything with a value emit it with the full path as the key
    var path = doc.ancestors.concat([doc._id]);
    emit(path, {data: doc.data, path: path})
  }
}

Функция уменьшения

function (keys, values, rereduce) {
  // build a tree of the values currently being reduced
  // by reassembling the paths and putting the value
  // at the targeted location
  var tree = {children: {}};
  function addValueToTree(value) {
    var parent = tree;
    value.path.forEach(function(docId) {
      var newParent = parent.children[docId] || {children: {}};
      parent.children[docId] = newParent;
      parent = newParent;
    });
    parent.value = value;
  }
  values.forEach(addValueToTree);

  // Object.entries isn't supported in Couch JS
  // engine so simple polyfill
  function entries(obj) {
    var entries = [];
    for (k in obj) {
      entries.push([k, obj[k]]);
    }
    return entries;
  }

  // Determine the value of the tree selecting
  // the one "winning" value to return from the
  // reduce function
  function reduceTree(tree, path) {
    // If the node of the tree we're reducing has an
    // explicit value then return that since it should
    // take precedence over any children
    if (tree.value) {
      return tree.value;
    }

    // Otherwise reduce the children of the current node
    // to get the "winning" node from 
    var toCombine = entries(tree.children).map(function (entry) {
      return reduceTree(entry[1], path.concat([entry[0]]));
    });

    // Find the winning child by picking the one with
    // the maximum value and return that
    var ret = toCombine[0];
    toCombine.forEach(function(child) {
      if (child.data > ret.data)
        ret = child;
    });
    return ret;
  }
  var ret = reduceTree(tree, []);

  log({values: values, ret: ret})
  return ret;
}

Это работает до тех пор, пока потомки сокращаются в одном и том же вызове с любыми родительскими узлами, которые должны иметь приоритет, но когда родительский элемент в конечном итоге удаляется из уменьшить (как в примере выше) означает, что потомок не заменяется и может в конечном итоге повлиять на окончательный расчет, что приведет к неверному результату.

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

Возможно ли это даже с функцией уменьшения или это принципиально нарушает ограничения функции сокращения?

...