按值sortingCouchDB视图
我正在testingCouchDB,看看它如何处理日志logging一些search结果。 我想要做的是产生一个视图,我可以从结果中产生最高的查询。 目前我有这样的事情:
示例文档部分
{ "query": "+dangerous +dogs", "hits": "123" }
地图function (不完全是我需要/想要的,但它足够testing)
function(doc) { if (doc.query) { var split = doc.query.split(" "); for (var i in split) { emit(split[i], 1); } } }
减lessfunction
function (key, values, rereduce) { return sum(values); }
现在这将使我得到一个格式的结果,其中一个查询项是关键和右边的这个术语的计数,这是很好的。 但我希望按价值sorting,而不是按键。 从它的声音,这是不可能与CouchDB。
那么,有没有人有任何想法,我怎样才能得到一个视图,我有一个有序的查询条款及其相关计数版本? 我对CouchDB非常陌生,我不能想到如何编写所需的function。
诚然,没有简单的答案。 有几种模式。
-
http://wiki.apache.org/couchdb/View_Snippets#Retrieve_the_top_N_tags 。 我个人不喜欢这个,因为他们承认这是一个脆弱的解决scheme,而且代码看起来并不轻松。
-
Avi的答案是在应用程序的内存中sorting。
-
couchdb-lucene ,似乎大家发现自己最终需要!
-
我喜欢的是Chris在Avi的报价中所说的话。 放松。 在CouchDB中,数据库是轻量级的,擅长给你一个独特的数据视angular。 这些日子里,关于过滤复制的所有内容都是关于将您的数据的子集切片以放入单独的数据库。
无论如何,基础很简单。 您从视图输出中取出
.rows
,并将其插入到单独的数据库中,该数据库仅在键盘上发出数字。 另外一个技巧是编写一个非常简单的_list
函数。 列表“渲染”原始沙发输出成不同的格式。 你的_list
函数应该输出{ "docs": [ {..view row1...}, {..view row2...}, {..etc...} ] }
那么将会完全按照
_bulk_docs
API的要求格式化视图输出。 现在你可以直接curl到另一个curl:curl host:5984/db/_design/myapp/_list/bulkdocs_formatter/query_popularity \ | curl -X POST host:5984/popularity_sorter/_design/myapp/_view/by_count
-
事实上,如果你的列表函数可以处理所有的文档,你可以直接将它们sorting,并将它们返回给sorting后的客户端。
这发生在CouchDB用户邮件列表上,主要开发者之一Chris Anderson写道:
这是一个常见的请求,但不是由CouchDB的视图直接支持 – 要做到这一点,你需要将group-reduce查询复制到另一个数据库,并构build一个视图按值sorting。
这是一个折衷,我们赞成dynamic范围查询和增量索引。
我最近也需要这样做,最后我在我的应用程序层做了这个。 这在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!
我不确定你有什么作为你的回报结果,但我肯定这应该做的伎俩:
emit([doc.hits, split[i]], 1);
sorting规则在文档中定义。
根据Avi的回答,我想出了这个Couchdb列表函数,它可以满足我的需求,这个函数只是最stream行的事件报告(key = event name,value = attendees)。
ddoc.lists.eventPopularity = function(req,res){ start({headers:{“Content-type”:“text / plain”}}); var data = [] while(row = getRow()){ data.push(行); } data.sort(function(a,b){ 返回a.value - b.value; })。相反(); for(i in data){ 发送(data [i] .value +':'+ data [i] .key +“\ n”); } }
作为参考,这里是相应的视图function:
ddoc.views.eventPopularity = { map:function(doc){ if(doc.type =='user'){ 为(我在doc.events){ emit(doc.events [i] .event_name,1); } } }, 减less:'_count' }
和列表函数的输出(剪切):
165:devise驱动的创新:devise师如何促进对话 165:你的客户是人群还是社区? 164:社交媒体stream言 163:不要害怕创造力! 任何事情都可能发生 159:机构需要像软件公司一样思考吗? 158:客户体验:未来趋势和见解 156:意外作家:每个人的伟大的Web复制 155:为什么一切都是惊人的,但没有人是快乐的
这是一个古老的问题,但我觉得它仍然值得一个体面的答案(我花了至less20分钟寻找正确的答案…)
我不赞成在这里的答案中的其他build议,并认为他们不满意。 特别是我不喜欢对应用层中的行进行sorting的build议,因为它不能很好地扩展,并且不处理需要限制数据库中的结果集的情况。
我在这个线程中提出了更好的方法,它假定如果你需要对查询中的值进行sorting,你应该把它们添加到密钥集中,然后使用范围来查询密钥 – 指定所需的密钥并松开价值范围。 例如,如果您的密钥由国家,州和城市组成:
emit([doc.address.country,doc.address.state, doc.address.city], doc);
然后你只需要查询国家,就可以对其他关键组件进行自由sorting:
startkey=["US"]&endkey=["US",{}]
如果你还需要颠倒顺序 – 请注意,简单的定义descending: true
不够的。 您实际上需要反转开始和结束键顺序,即:
startkey=["US",{}]&endkey=["US"]
在这个伟大的来源看到更多的参考。
上面的每个解决scheme都会打破我认为的couchdb性能。 我对这个数据库很新。 据我所知,couchdb查看准备结果之前被查询。 看来我们需要手动准备结果。 例如,每个search项将驻留在数据库中,命中数。 当有人search时,search条件将被查找并增加命中次数。 当我们想看到search词的stream行,它会发出(hitcount,searchterm)对。
链接Retrieve_the_top_N_tags似乎被打破,但我在这里find了另一个解决scheme。
引用写这个解决scheme的开发者:
而不是返回地图步骤中的标记所键入的结果,而是发出每个标记的每一个出现。 然后在reduce步骤中,我将使用散列来计算按标签分组的聚合值,将其转换为数组,然后对其sorting,然后select前3个。
正如评论所述,唯一的问题是长尾巴的情况:
问题是你必须小心你获得的标签数量; 如果结果大于500字节,那么couchdb会抱怨,因为“reduce必须有效减less”。 3或6甚至20个标签不应该是一个问题,但。
它完美的工作,检查链接,看看代码!