按值排序CouchDB视图

时间:2010-05-12 10:00:53

标签: sorting couchdb

我正在测试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很新,我想不出我是如何编写所需的函数的。

7 个答案:

答案 0 :(得分:24)

确实没有简单的答案。但是有几种模式。

  1. http://wiki.apache.org/couchdb/View_Snippets#Retrieve_the_top_N_tags。我个人并不喜欢这样,因为他们承认这是一个脆弱的解决方案,代码并不是放松的。

  2. Avi的答案,就是在您的应用程序中对内存进行排序。

  3. couchdb-lucene似乎每个人最终都会发现自己需要的东西!

  4. 我喜欢的是克里斯在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
    
  5. 事实上,如果您的列表函数可以处理所有文档,您可以让它自己对它们进行排序并将它们返回到已排序的客户端。

答案 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)

我不确定你的返回结果是1,但我很肯定这应该可以解决问题:

emit([doc.hits, split[i]], 1);

rules of sorting在文档中定义。

答案 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个标签应该不是问题。

它非常适合我,请查看链接以查看代码!