Map / Reduce для массива хэшей в CouchDB - PullRequest
2 голосов
/ 16 марта 2010

Я ищу функцию карты / уменьшения для расчета статуса в проектной документации. Ниже вы можете увидеть пример документа из моей текущей базы данных.

{
   "_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 вид выглядит следующим образом:

* +1007 *

Я пробовал кое-что, но на самом деле ничего не работает. Прямо сейчас мой 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 ​​после получения данных из базы данных. Было бы неплохо уже получить нужные данные из базы данных)

Ответы [ 3 ]

3 голосов
/ 16 марта 2010

Переменная value функции Reduce представляет собой массив значений, излучаемых функцией map. В вашем случае value - это массив, состоящий из массивов "url". При запуске map-Reduce в футоне он устанавливает group=true, так что Map-Reduction запускается отдельно для каждого ключа, испускаемого функцией карты. В вашем случае эти ключи являются документом _ids. То есть, функция Reduce value - это массив, все элементы которого являются url-массивами, принадлежащими определенному документу _id. Так как _id _id уникальны, в результате получается, что функция Reduce value является массивом с одним элементом, этот элемент является массивом url соответствующего документа. Вот почему value.length всегда равен 1 с вашей функцией уменьшения.

Но это может ухудшиться: если вы окажетесь в цикле восстановления, value функции Reduce - это массив значений, возвращаемых предыдущим вызовом функции Reduce. В вашем случае вы бы вызвали функцию приведения к value, похожую на ["retrieved","new","retrieved"], что не приводит к правильным результатам.

Обычно функция сокращения используется для агрегирования данных, выдаваемых функцией map, например, для подсчета строк или суммирования значений, что не является необходимым в вашем случае. Вы можете прочитать больше о map-lower в couchdb здесь:

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

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

1 голос
/ 16 марта 2010

doc.urls представляется массивом Object s, содержащим свойство 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;
}

edit: фактически функция должна вернуться, как только найдет status == "new".

0 голосов
/ 16 марта 2010

Спасибо Альсиенде за то, что подтолкнул меня к правильному решению, оказалось, что я действительно не понял функцию уменьшения. Мне не нужна была функция уменьшения вообще.

Вот мой 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);
  }
}
...