我正在测试CouchDB以了解它如何处理记录某些搜索结果。我想做的是生成一个视图,我可以从结果中生成最顶层的查询。目前我有这样的事情:
示例文档部分
{
"query": "+dangerous +dogs",
"hits": "123"
}
地图功能 (不完全是我需要/想要的,但它足以进行测试)
function(doc) {
if (doc.query) {
var split = doc.query.split(" ");
for (var i in split) {
emit(split[i], 1);
}
}
}
减少功能
function (key, values, rereduce) {
return sum(values);
}
现在,这将以一种格式显示结果,其中查询字词是关键字,右边是该字词的计数,这很好。但我希望它按价值排序,而不是钥匙。从它的声音来看,CouchDB尚不可能。
所有人都有任何想法,我如何获得一个视图,我有一个订购版本的查询条款&他们的相关数量?我对CouchDB很新,我想不出我是如何编写所需的函数的。
答案 0 :(得分:24)
确实没有简单的答案。但是有几种模式。
http://wiki.apache.org/couchdb/View_Snippets#Retrieve_the_top_N_tags。我个人并不喜欢这样,因为他们承认这是一个脆弱的解决方案,代码并不是放松的。
Avi的答案,就是在您的应用程序中对内存进行排序。
couchdb-lucene似乎每个人最终都会发现自己需要的东西!
我喜欢的是克里斯在Avi的报价中所说的话。放松。在CouchDB中,数据库是轻量级的,并且擅长为您提供独特的数据视角。目前,嗡嗡声是关于过滤复制的全部内容,这些都是关于将数据的子集切成单独的数据库。
无论如何,基础很简单。从视图输出中取出.rows
,然后将其插入到一个单独的数据库中,该数据库只需键入计数键。另一个技巧是编写一个非常简单的_list
函数。列表将原始沙发输出“渲染”为不同的格式。您的_list
函数应输出
{ "docs":
[ {..view row1...},
{..view row2...},
{..etc...}
]
}
这样做会完全按照_bulk_docs
API的要求格式化视图输出。现在你可以将卷曲直接卷曲成另一个卷曲:
curl host:5984/db/_design/myapp/_list/bulkdocs_formatter/query_popularity \
| curl -X POST host:5984/popularity_sorter/_design/myapp/_view/by_count
事实上,如果您的列表函数可以处理所有文档,您可以让它自己对它们进行排序并将它们返回到已排序的客户端。
答案 1 :(得分:13)
CouchDB用户邮件列表中的came up和主要开发人员之一Chris Anderson写道:
这是一个常见的请求,但CouchDB不直接支持 视图 - 要执行此操作,您需要将group-reduce查询复制到 另一个数据库,并构建一个按值排序的视图。
这是我们做出的权衡,支持动态范围查询和 增量指数。
我最近也需要这样做,最后我在我的应用层中做了这件事。这在JavaScript中很容易做到:
db.view('mydesigndoc', 'myview', {'group':true}, function(err, data) {
if (err) throw new Error(JSON.stringify(err));
data.rows.sort(function(a, b) {
return a.value - b.value;
});
data.rows.reverse(); // optional, depending on your needs
// do something with the data…
});
此示例在Node.js中运行并使用node-couchdb,但它可以轻松地适应在浏览器或其他JavaScript环境中运行。当然,这个概念可以移植到任何编程语言/环境中。
HTH!
答案 2 :(得分:3)
这是一个老问题,但我觉得它仍然值得一个体面的答案(我花了至少20分钟寻找正确的答案......)
我对这里的答案中的其他建议表示不满,并认为这些建议并不令人满意。特别是我不喜欢在应用层中对行进行排序的建议,因为它不能很好地扩展,也不会处理需要限制数据库中结果集的情况。
我在this thread中提出了我遇到的更好的方法,它假定如果您需要对查询中的值进行排序,则应将它们添加到密钥集中,然后使用范围查询密钥 - 指定一个所需的键并放宽了值范围。例如,如果您的密钥由国家/地区,州和城市组成:
emit([doc.address.country,doc.address.state, doc.address.city], doc);
然后您只查询国家/地区并对其余关键组件进行免费排序:
startkey=["US"]&endkey=["US",{}]
如果您还需要撤消订单 - 请注意,简单定义descending: true
是不够的。您实际上需要反转开始和结束键顺序,即:
startkey=["US",{}]&endkey=["US"]
在这篇伟大的source上查看更多参考资料。
答案 3 :(得分:2)
答案 4 :(得分:2)
根据Avi的回答,我想出了满足我需求的Couchdb列表功能,它只是一个关于最受欢迎事件的报告(key =事件名称,值=与会者)。
ddoc.lists.eventPopularity = function(req, res) { start({ headers : { "Content-type" : "text/plain" } }); var data = [] while(row = getRow()) { data.push(row); } data.sort(function(a, b){ return a.value - b.value; }).reverse(); for(i in data) { send(data[i].value + ': ' + data[i].key + "\n"); } }
供参考,这是相应的视图功能:
ddoc.views.eventPopularity = { map : function(doc) { if(doc.type == 'user') { for(i in doc.events) { emit(doc.events[i].event_name, 1); } } }, reduce : '_count' }
列表功能的输出(剪切):
165: Design-Driven Innovation: How Designers Facilitate the Dialog 165: Are Your Customers a Crowd or a Community? 164: Social Media Mythbusters 163: Don't Be Afraid Of Creativity! Anything Can Happen 159: Do Agencies Need to Think Like Software Companies? 158: Customer Experience: Future Trends & Insights 156: The Accidental Writer: Great Web Copy for Everyone 155: Why Everything is Amazing But Nobody is Happy
答案 5 :(得分:0)
我认为上面的每个解决方案都会破坏couchdb的性能。我对这个数据库很新。据我所知,couchdb视图在查询之前准备结果。我们似乎需要手动准备结果。例如,每个搜索项将驻留在具有命中计数的数据库中。当有人搜索时,会查找其搜索字词并增加点击次数。当我们想要查看搜索词流行时,它会发出(hitcount,searchterm)对。
答案 6 :(得分:0)
Link Retrieve_the_top_N_tags似乎已被破坏,但我找到了另一种解决方案here。
引用编写该解决方案的开发人员:
而不是在地图步骤中返回由标记键入的结果,而是发出每个标记的每个匹配项。然后在reduce步骤中,我将使用哈希计算按标签分组的聚合值,将其转换为数组,对其进行排序,然后选择前3个。
正如评论中所述,唯一的问题是长尾的情况:
问题是你必须小心你获得的标签数量;如果结果大于500字节,那么你就会抱怨couchdb,因为“reduce必须有效减少”。但是,3或6或甚至20个标签应该不是问题。
它非常适合我,请查看链接以查看代码!