#couchdb #mapreduce
#couchdb #mapreduce
Вопрос:
Допустим, у меня есть записи в блоге, подобные этим, в моей базе данных CouchDB:
{"имя": "Мэри", "дата публикации": "20110412", "тема": "это", "сообщение": "бла"} {"имя": "Джо", "дата публикации": "20110411", "тема": "это", "сообщение": "блядь"} {"имя": "Мэри", "дата публикации": "20110411", "тема": "и это", "сообщение": "бла-бла"} {"имя": "Джо", "дата публикации": "20110410", "тема": "И другое", "сообщение": "бла-бла-бла"} {"имя": "Джейн", "дата публикации": "20110409", "тема": "Серьезный материал", "сообщение": "Не совсем"}
Получить список всех записей довольно просто. Но как мне получить список последних сообщений от всех пользователей?
Вот так:
{"имя": "Мэри", "дата публикации": "20110412", "тема": "это", "сообщение": "бла"} {"имя": "Джо", "дата публикации": "20110411", "тема": "это", "сообщение": "блядь"} {"имя": "Джейн", "дата публикации": "20110409", "тема": "Серьезный материал", "сообщение": "Не совсем"}
Ответ №1:
Попробуйте использовать эту функцию map:
function(doc) {
if (doc.postdate amp;amp; doc.name) {
emit([doc.name, doc.postdate], 1);
}
}
и следующая функция уменьшения:
function(keys, values, rereduce) {
var max = 0,
ks = rereduce ? values : keys;
for (var i = 1, l = ks.length; i < l; i) {
if (ks[max][0][1] < ks[i][0][1]) max = i;
}
return ks[max];
}
и запрашиваем его с помощью group_level=1
. Он выдает вам _id
количество записей, затем вы можете получить их все с помощью одного запроса с keys
параметром или с помощью POST.
Я не уверен, что это лучший подход, но, похоже, он работает.
ОБНОВЛЕНИЕ: исправлено, что карта неправильно обрабатывала повторное получение.
Комментарии:
1. Я пробовал что-то подобное. Это то, что я получаю взамен при доступе к представлению: «ошибка»:»reduce_overflow_error»,»причина»: «Уменьшенный вывод должен сокращаться быстрее: текущий вывод:… Может быть, потому, что мои документы на самом деле довольно большие, около 7-10 тыс.
2. Я только что попробовал загрузить 30000 документов, и у меня это работает. Но я использовал только четыре разных
doc.name
файла. Может быть, у вас много пользователей с несколькими публикациями на пользователя? Вы пробовали обновленную версию?3. Пожалуйста, обратите внимание, что я также обновил функцию map до
emit([doc.name, doc.postdate], 1)
, а неemit([doc.name, doc.postdate], doc)
.
Ответ №2:
Вы собираетесь использовать postdate в качестве ключа, потому что ключи отсортированы. Например, вот как будет выглядеть ваша функция map…
function(doc) {
if(doc.postdate) {
emit(doc.postdate, doc);
}
}
Это даст вам все документы, отсортированные по возрастанию по дате публикации. Если вы хотите по убыванию, то выполните запрос с ?descending=true
Приветствия.
Комментарии:
1. К сожалению, это включало бы все сообщения, скажем, от Мэри, в то время как я ищу только последнее. Не требует ли он слишком многого от CouchDB?
2. Вы можете сделать это без проблем! Просто убедитесь, что вы переходите по убыванию, и вызовите URL-адрес, используя параметр limit, следующим образом:
?descending=trueamp;limit=1
. Приветствия.3. А, я понимаю: вам нужны последние данные для каждого пользователя, а не последние в целом. Это возможно только при выполнении нескольких вызовов и использовании сложных ключей. Например, ваша ключевая структура была бы такой,
[doc.name, doc.postdate]
и затем вы могли бы запросить?startkey=["Mary"]amp;endkey=["Mary",{}]amp;descending=trueamp;limit=1
, чтобы получить последнюю запись Мэри.4. Спасибо, Сэм. Я думаю, это отвечает на мой вопрос. К сожалению, мне приходится использовать несколько вызовов. Это невозможно, когда база данных насчитывает около миллиона пользователей.
5. Если это так, то вы могли бы самостоятельно поддерживать список в дополнительном документе. Дайте ему _id «latestPosts» или что-то в этом роде. Также взгляните на couchdb-lucene для получения дополнительной, более традиционной функциональности запросов. Приветствия.