我有一个用关键字标记的文档数据库。我试图找到(然后计算)彼此并排使用的唯一标签。因此,对于任何给定的标签,我想知道哪些标签与该标签一起使用。
例如,如果我有一个标记为[fruit, apple, plant]
的文档,那么当我查询[apple]
时,我应该[fruit, plant]
。如果其他文档包含标记[apple, banana]
,那么我对[apple]
的查询会给我[fruit, plant, banana]
。
这是我的map函数,它会发出所有标签及其邻居:
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函数应该基本上过滤掉重复项并将它们组合在一起。
我尝试了许多不同的尝试,但我的数据库服务器(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;
}
答案 0 :(得分:4)
你的答案很好,正如我在评论中所说,如果它适合你,那就是你应该关心的。如果遇到性能问题,这是一个替代实现。
CouchDB喜欢高大的名单,而不是胖名单。这个解决方案保留了#34; sibling&#34;而不是查看行保持数组与之前看到的每个标记。标记在视图行的键中,然后group them together以保证每行一个唯一的兄弟标记。每行只有两个标签,但可能有数千或数百万行:一个很高的列表,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)
})
})
}
答案 1 :(得分:1)
我找到了一个正确的解决方案,我感到非常高兴。诀窍是必须将CouchDB设置为reduce_limit = false
,以便它停止针对您的查询检查其启发式。
您可以通过点击该值,在{strong> query_server_config 设置下的http://localhost:5984/_utils/config.html上通过Futon进行设置。
完成后,这是我的新地图功能,它可以更好地与reduce函数的“重新缩小”部分配合使用:
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;
}
希望这有助于某人!