映射减少查询以计数标记



我有一个用关键字标记的文档数据库。我正在尝试查找(然后计算(彼此一起使用的唯一标签。因此,对于任何给定的标签,我想知道哪些标签与该标签一起使用。

例如,如果我有一个带有标签的文档[fruit, apple, plant]那么当我查询[apple]时,我应该得到[fruit, plant]。如果另一个文档有标签[apple, banana]那么我对[apple]的查询会给我[fruit, plant, banana]

这是我的地图函数,它发出所有标签及其邻居:

function(doc) {
  if(doc.tags) {
    doc.tags.forEach(function(tag1) {
      doc.tags.forEach(function(tag2) {
        emit(tag1, tag2);
      });
    });
  }
}

所以在我上面的例子中,它会发出

apple -- fruit
apple -- plant
apple -- banana
fruit -- apple
fruit -- plant
...
我的

问题是:我的reduce函数应该是什么?reduce函数本质上应该过滤掉重复项并将它们全部分组在一起。

我已经尝试了许多不同的尝试,但是我的数据库服务器(CouchDB(一直给我一个错误:reduce_overflow_error。减少产量必须更快地缩小


编辑:我发现了一些似乎有效的东西,但我不确定为什么。我看到reduce函数调用有一个可选的"rereduce"参数。如果我忽略这些特殊情况,那么它就会停止抛出reduce_overflow_errors。谁能解释为什么?而且,我应该忽略这些,还是以后会咬我的屁股?

function(keys, values, rereduce) {
  if(rereduce) return null; // Throws error without this.
  var a = [];
  values.forEach(function(tag) {
    if(a.indexOf(tag) < 0) a.push(tag);
  });
  return a;
}

你的回答很好,正如我在评论中所说,如果它对你有用,那就是你应该关心的。这是另一种实现,以防您遇到性能问题。

CouchDB 喜欢高列表,而不是胖列表。此解决方案不是将视图行保留一个包含每个先前标记的数组,而是将"同级"标记保留在视图行的中,然后将它们组合在一起以保证每行有一个唯一的同级标记。每一行只有两个标签,但可能有数千或数百万行:一个高列表,CouchDB 更喜欢。

主要思想是发出一个 2 个标签对数组。假设我们有一个文档,标记为 fruit, apple, plant .

// Pseudo-code visualization of view rows (before reduce)
// Key         , Value
[apple, fruit ], 1
[apple, plant ], 1 // Basically this is every combination of 2 tags in the set.
[fruit, apple ], 1
[fruit, plant ], 1
[plant, apple ], 1
[plant, fruit ], 1

接下来,我标记了一些apple, banana.

// Pseudo-code visualization of view rows (before reduce)
// Key         , Value
[apple, banana], 1 // This is from my new doc
[apple, fruit ], 1
[apple, plant ], 1 // This is also from my new doc
[banana, apple], 1
[fruit, apple ], 1
[fruit, plant ], 1
[plant, apple ], 1
[plant, fruit ], 1

为什么值总是1?因为我可以做一个非常简单的内置reduce函数:_sum告诉我所有标签对的计数。接下来,使用 ?group_level=2 和 CouchDB 进行查询将为您提供唯一的对,以及它们的总数。

用于生成此类视图的映射函数可能如下所示:

function(doc) {
  // Emit "sibling" tags, keyed on tag pairs.
  var tags = doc.tags || []
  tags.forEach(function(tag1) {
    tags.forEach(function(tag2) {
      if(tag1 != tag2)
        emit([tag1, tag2], 1)
    })
  })
}

我找到了一个正确的解决方案,我对此感到非常满意。诀窍是 CouchDB 必须设置为 reduce_limit = false,以便它停止针对您的查询检查其启发式方法。

您可以通过 http://localhost:5984/_utils/config.html query_server_config设置下的 Futon 进行设置,方法是双击该值。

完成后,这是我的新地图函数,它与reduce函数的"rereducing"部分配合得更好:

function(doc) {
  if(doc.tags) {
    doc.tags.forEach(function(tag1) {
      doc.tags.forEach(function(tag2) {
        emit(tag1, [tag2]); // Array with single value
      });
    });
  }
}

这是reduce函数:

function(keys, values) {
  var a = [];
  values.forEach(function(tags) {
    tags.forEach(function(tag) {
      if(a.indexOf(tag) < 0) a.push(tag);
    });
  });
  return a;
}

希望这对某人有所帮助!

相关内容

  • 没有找到相关文章

最新更新