2

我正在寻找一个 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密钥,而是根据 url 的状态计算它。我当前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;
}

替代文字 http://img.skitch.com/20100316-qeawxgd5pru8d5i6bprygcsmhf.jpg

我究竟做错了什么?(我知道我想让你为我写代码,我很内疚,但现在我在从数据库中获取数据后用 ruby​​ 计算状态。如果已经从数据库中获取了正确的数据,那就太好了数据库)

4

3 回答 3

3

reduce 函数的变量value是 map 函数发出的值数组。在您的情况下,value是一个由“url”数组组成的数组。在蒲团中运行 map-reduce 时,它​​设置group=true为对 map 函数发出的每个键单独运行 map-reduce。在您的情况下,这些键是 document _ids。也就是说,reduce 函数value是一个数组,其元素都是属于某个 doc _id 的 url 数组。由于 doc _ids 是唯一的,因此 reduce 函数最终value是一个包含一个元素的数组,该元素是相应 doc 的 url-array。这就是为什么value.length你的 reduce 函数总是 1 的原因。

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

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

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

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

于 2010-03-16T14:45:42.967 回答
1

doc.urls似乎是一个Object包含一个status属性和一个url属性的 s 数组。所以你的 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".

于 2010-03-16T12:39:55.383 回答
0

感谢 Alsciende 将我推向正确的解决方案,结果我真的不了解 reduce 功能。我根本不需要reduce函数。

这是我的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);
  }
}
于 2010-03-16T13:53:04.503 回答