Сортировка просмотров CouchDB по значению - PullRequest
37 голосов
/ 12 мая 2010

Я тестирую 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 ]

24 голосов
/ 12 мая 2010

Это правда, что нет простого ответа. Однако есть несколько моделей.

  1. http://wiki.apache.org/couchdb/View_Snippets#Retrieve_the_top_N_tags. Мне лично это не нравится, потому что они признают, что это хрупкое решение, а код не выглядит расслабляющим.

  2. Ответ Ави, который заключается в сортировке памяти в вашем приложении.

  3. couchdb-lucene , который, кажется, каждый в конечном итоге находит нужным!

  4. Что мне нравится, так это то, что Крис сказал в цитате Ави. Расслабьтесь. В CouchDB базы данных легки и превосходны, предоставляя вам уникальную перспективу ваших данных. В наши дни все дело в фильтрованной репликации, которая состоит в том, чтобы вырезать подмножества ваших данных для помещения в отдельную БД.

    Во всяком случае, основы просты. Вы берете свой .rows из выходных данных представления и вставляете его в отдельную БД, которая просто выдает ключ на счетчике. Дополнительный трюк - написать очень простую _list функцию. Списки «рендерит» необработанный вывод дивана в разные форматы. Ваша _list функция должна выводить

    { "docs":
        [ {..view row1...},
          {..view row2...},
          {..etc...}
        ]
    }
    

    То, что нужно сделать, это отформатировать выводное представление в точности так, как этого требует API _bulk_docs. Теперь вы можете свернуть трубку прямо в другой локон:

    curl host:5984/db/_design/myapp/_list/bulkdocs_formatter/query_popularity \
     | curl -X POST host:5984/popularity_sorter/_design/myapp/_view/by_count
    
  5. На самом деле, если ваша функция списка может обрабатывать все документы, вы можете просто отсортировать их и вернуть отсортированному клиенту.

13 голосов
/ 12 мая 2010

Это появилось в списке рассылки пользователей CouchDB, и Крис Андерсон, один из основных разработчиков, написал:

Это общий запрос, но не поддерживаетсянепосредственно представлениями CouchDB - для этого вам нужно скопировать запрос на уменьшение группы в другую базу данных и создать представление для сортировки по значению.

Это компромисс, который мы делаем в пользу динамического диапазоназапросы и инкрементные индексы.

Мне нужно было сделать это также недавно, и я закончил делать это на своем уровне приложений.Это легко сделать в 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!

3 голосов
/ 31 января 2017

Это старый вопрос, но я чувствую, что он все еще заслуживает достойного ответа (я потратил не менее 20 минут на поиск правильного ответа ...)

Я не одобряю другие предложения в ответах здесь и чувствую, что они неудовлетворительны. Особенно мне не нравится предложение сортировать строки в аппликативном слое, так как оно плохо масштабируется и не имеет отношения к случаю, когда вам нужно ограничить набор результатов в БД.

Лучший подход, с которым я столкнулся, предлагается в этой теме , и он предполагает, что если вам нужно отсортировать значения в запросе, вы должны добавить их в набор ключей и затем запросить ключ, используя диапазон - указание нужного ключа и ослабление диапазона значений. Например, если ваш ключ состоит из страны, штата и города:

emit([doc.address.country,doc.address.state, doc.address.city], doc);

Затем вы запрашиваете только страну и получаете бесплатную сортировку по остальным ключевым компонентам:

startkey=["US"]&endkey=["US",{}] 

В случае, если вам также необходимо изменить порядок - обратите внимание, что простого определения descending: true будет недостаточно. Вам на самом деле нужно поменять местами начальный и конечный порядок ключей, т.е.:1014*

startkey=["US",{}]&endkey=["US"]

См. Больше ссылок на этот великий источник .

2 голосов
/ 02 февраля 2011

Основываясь на ответе Avi, я придумал функцию списка Couchdb, которая работала для моих нужд и представляла собой просто отчет о наиболее популярных событиях (ключ = имя события, значение = участники).

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
2 голосов
/ 12 мая 2010

Я не уверен насчет 1, который у вас есть в качестве возвращенного результата, но я уверен, что это должно сработать:

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

Правила сортировки определены в документации.

0 голосов
/ 06 августа 2013

Ссылка Retrieve_the_top_N_tags, кажется, не работает, но я нашел другое решение здесь .

Цитирую разработчика, который написал это решение:

вместо того, чтобы возвращать результаты, введенные тегом на шаге карты, я бы вместо этого генерировал каждое вхождение каждого тега. Затем на шаге сокращения я вычислю значения агрегации, сгруппированные по тегу, используя хеш, преобразую его в массив, отсортирую его и выберу верхний 3.

Как указано в комментариях, единственная проблема будет в случае длинного хвоста:

Проблема в том, что вы должны быть осторожны с количеством получаемых вами тегов; если результат больше 500 байт, вы получите жалобу на couchdb, так как «уменьшение должно эффективно уменьшать». 3, 6 или даже 20 тегов не должны быть проблемой.

У меня сработало отлично, проверьте ссылку, чтобы увидеть код!

0 голосов
/ 14 мая 2013

Я думаю, что каждое приведенное выше решение нарушит производительность couchdb. Я очень новичок в этой базе данных. Как я знаю, представления couchdb готовят результаты до того, как их опрашивают. Кажется, нам нужно подготовить результаты вручную. Например, каждый поисковый термин будет находиться в базе данных с количеством посещений. И когда кто-то ищет, его поисковые термины будут найдены и увеличит количество посещений. Когда мы хотим увидеть популярность поискового термина, он выдаст пару (hitcount, searchterm).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...