在CouchDB中对一组哈希进行Map / Reduce

时间:2010-03-16 12:29:37

标签: javascript couchdb mapreduce

我正在寻找map / reduce函数来计算设计文档中的状态。 您可以在下面看到我当前数据库中的示例文档。

{
   "_id": "0238f1414f2f95a47266ca43709a6591",
   "_rev": "22-24a741981b4de71f33cc70c7e5744442",
   "status": "retrieved image urls",
   "term": "Lucas Winter",
   "urls": [
       {
           "status": "retrieved",
            "url": "http://...."
       },
       {
           "status": "retrieved",
            "url": "http://..."
       }
   ],
   "search_depth": 1,
   "possible_labels": {
       "gender": "male"
    },
    "couchrest-type": "SearchTerm"
}

我想摆脱status密钥,而是根据网址的状态来计算它。 我当前的by_status视图如下所示:

function(doc) {
    if (doc['status']) {
       emit(doc['status'], null);
    }
}

我尝试了一些东西,但实际上没有任何效果。现在我的Map Function看起来像这样:

function(doc) {
    if(doc.urls){
        emit(doc._id, doc.urls)
    }
}

我的Reduce Function

function(key, value, rereduce){ 
    var reduced_status = "retrieved"
    for(var url in value){
        if(url.status=="new"){
            reduced_status = "new";
        }
    }
    return reduced_status;
}

结果是我到处找到了绝对不正确的东西。

我试图缩小问题的范围,似乎value不是数组,当我使用以下Reduce Function我到处都得到长度1,这是不可能的因为我有12个文件我的数据库,每个包含20到200个URL

function(key, value, rereduce){ 
   return value.length;
}

alt text http://img.skitch.com/20100316-qeawxgd5pru8d5i6bprygcsmhf.jpg

我做错了什么? (我知道我希望你为我编写代码并且我感到内疚,但是现在我从数据库中获取数据后我会计算ruby中的状态。很高兴已经从中获取了正确的数据。数据库)

3 个答案:

答案 0 :(得分:3)

reduce函数的变量value是map函数发出的值数组。在您的情况下,value是一个由“url” - 数组组成的数组。在蒲团中运行map-reduce时,它会设置group=true,以便map-reduce分别针对map函数发出的每个键运行。在您的情况下,这些键是文档_ids。也就是说,reduce函数value是一个数组,其元素都是属于某个doc _id的url-arrays。由于doc _ids是唯一的,因此最终使用reduce函数value是一个包含一个元素的数组,此元素是相应doc的url-array。这就是为什么value.length与reduce函数一直为1的原因。

但它可能会变得更糟:如果你最终进入rereduce循环,reduce函数的value是一个值数组,由之前调用reduce函数返回。在您的情况下,您可以使用value调用reduce函数,使其看起来像["retrieved","new","retrieved"],这不会产生正确的结果。

通常,reduce函数用于聚合map-function发出的数据,例如计算行数或总结值 - 这在您的情况下是不必要的。您可以在这里阅读有关couchdb中map-reduce的更多信息:

http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views

http://books.couchdb.org/relax/design-documents/views

答案 1 :(得分:1)

doc.urls似乎是包含Object属性和status属性的url数组。所以你的Reduce功能应该是

function(key, value, rereduce){ 
    var reduced_status = "retrieved";
    for(var i=0; i<value.length; i++) {
        if(value[i].status=="new"){
            reduced_status = "new";
        }
    }
    return reduced_status;
}

编辑:实际上该函数应在找到status == "new"后立即返回。

答案 2 :(得分:0)

感谢Alsciende推动我走向正确的解决方案,事实证明我真的不明白还原功能。我根本不需要减少功能。

这是我Map Function为我解决的问题。

function(doc) {
if(doc.urls){
  var reduced_status = "retrieved";
  for(var i=0; i<doc.urls.length; i++) {
    if(doc.urls[i].status=="new"){
        reduced_status = "new";
        break;
    }
  }
  emit(reduced_status, null);
  }
}