Как создать представление фильтра «Мне нравится» в couchdb - PullRequest
14 голосов
/ 01 апреля 2011

Вот пример того, что мне нужно в SQL:

ВЫБЕРИТЕ имя ИЗ НАЗНАЧИТЕ, ГДЕ НРАВИТСЯ % bro%

Как мне создать подобный вид в couchdb?

Ответы [ 7 ]

14 голосов
/ 15 февраля 2012

Простой ответ заключается в том, что представления CouchDB не идеальны для этого.

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

1. Пути SQL

Когда вы делаете SELECT ... WHERE name LIKE %bro%, все знакомые мне движки SQL должны делать то, что называется "полным сканированием таблицы".Это означает, что сервер читает каждую строку в соответствующей таблице, и перебор сканирует поле, чтобы определить, совпадает ли он.

Вы можете сделать это в CouchDB 2.x с помощью запроса Mango, используя $regex * 1015оператор * * * 1016.Для базового случая запрос будет выглядеть примерно так:

{"selector":{
  "name": {
    "$regex": "bro"
  }
}}

Похоже, что для чувствительности к регистру не отображаются какие-либо параметры, и т. Д., Но вы можете расширить его, чтобы он соответствовал только в начале / концеили более сложные образцы.Если вы также можете ограничить свой запрос с помощью другого (индексируемого) оператора поля, это, вероятно, повысит производительность.Как следует из документации:

Регулярные выражения не работают с индексами, поэтому их не следует использовать для фильтрации больших наборов данных.[…]

Вы также можете выполнить полное сканирование в CouchDB 1.x, используя временное представление :

POST /some_database/_temp_view

{"map": "function (doc) { if (doc.name && doc.name.indexOf('bro') !== -1) emit(null); }"}

.один документ в базе данных и дать вам список соответствующих документов.Вы можете настроить функцию карты так, чтобы она также соответствовала типу документа, или использовать определенный ключ для заказа - emit(doc.timestamp) - или какое-либо значение данных, полезное для вашей цели - emit(null, doc.name).

2. Способ «тонны доступного дискового пространства»

В зависимости от размера исходных данных вы можете создать индекс, который выдает каждую возможную «внутреннюю строку» в качестве своего постоянного (на диске) ключа просмотра,То есть для такого имени, как «Доброс», вы бы emit("dobros"); emit("obros"); emit("bros"); emit("ros"); emit("os"); emit("s");.Затем для такого термина, как «% bro%», вы можете запросить свое представление с помощью startkey="bro"&endkey="bro\uFFFF", чтобы получить все вхождения термина поиска.Ваш индекс будет примерно равным размеру вашего текстового содержимого в квадрате , но если вам нужно выполнить произвольное «найти в строке» быстрее, чем полное сканирование базы данных, приведенное выше, и выделить место, это может сработать.Вы бы лучше обслуживали структуру данных, предназначенную для поиска по подстроке , хотя.

, что приводит нас тоже ...

3. Полнотекстовый поиск

Вы можете использовать плагин CouchDB ( couchdb-lucene теперь через Dreyfus / Clouseau для 2.x, ElasticSearch , FTS SQLite ) для создания вспомогательного тексто-ориентированного индекса в ваших документах.

Обратите внимание, что большинство индексов полнотекстового поиска естественно не поддерживают произвольных подстановочных префиксов либо, вероятно, по тем же причинам эффективности использования пространства, как мы видели выше.Обычно полнотекстовый поиск подразумевает не "бинарный поиск", а "поиск по слову".Тем не менее, YMMV, взгляните на опции, доступные в вашем полнотекстовом движке.

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

4 голосов
/ 01 апреля 2011

К сожалению, поиск с использованием LIKE %...% на самом деле не так, как работает CouchDB Views, но вы можете реализовать множество возможностей поиска, установив couchdb-lucene , это механизм полнотекстового поиска, который создает индексы в вашей базе данных, что вы можете делать более сложные поиски.

Типичный способ «поиска» в базе данных по заданному ключу без каких-либо сторонних инструментов - это создание представления, которое выдает значение, которое вы ищете в качестве ключа. В вашем примере:

function (doc) {
    emit(doc.name, doc);
}

Выводит список всех имен в вашей базе данных.

Теперь вы будете "искать" по первым буквам вашего ключа. Например, если вы ищете имена, начинающиеся с "bro".

/db/_design/test/_view/names?startkey="bro"&endkey="brp"

Обратите внимание, что я взял последнюю букву параметра поиска и "увеличил" последнюю букву в нем. Опять же, если вы хотите выполнять поиск, а не агрегировать статистику, вы должны использовать полнотекстовую поисковую систему, такую ​​как lucene. (см. выше)

1 голос
/ 12 июля 2016

Я знаю, что это старый вопрос, но: как насчет использования функции «список»? Вы можете иметь все свои обычные виды и затем добавить функцию «список» в проектный документ для обработки результатов вида:

{
  "_id": "_design/...",
  "views": {
    "employees": "..."
  },
  "lists": {
    "by_name": "..."
  }
}

И функция, присоединенная к функции "by_name", должна выглядеть примерно так:

function (head, req) {
  provides('json', function() {
    var filtered = [];

    while (row = getRow()) {
      // We can retrive all row information from the view
      var key = row.key;
      var value = row.value;
      var doc = req.query.include_docs ? row.doc : {};

      if (value.name.indexOf(req.query.name) == 0) {
        if (req.query.include_docs) {
          filtered.push({ key: key, value: value, doc: doc});
        } else {
          filtered.push({ key: key, value: value});
        }
      }
    }

    return toJSON({ total_rows: filtered.length, rows: filtered });
  });
}

Конечно, вы также можете использовать регулярные выражения. Это не идеальное решение, но оно работает для меня.

1 голос
/ 04 апреля 2011

я нашел простой код представления для моей проблемы ...

{
"getavailableproduct":
{ "map": "function (doc) {
префикс var = doc ['productid']. match (/ [A-Za-z0-9] + / g);
если (префикс)
for (var pre в префиксе) {emit (префикс [pre], null);}
} "
}
}

из этого кода представления, если я разделю ключевое предложение на ключевое слово ... и я могу позвонить

? Ключ = "[SEARCH_KEYWORD]"

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

но если я хочу ввести не полное слово (например, ea from eat или foo from food), этот код не работает ..

0 голосов
/ 03 апреля 2018

Вы можете использовать регулярные выражения. Согласно этой таблице вы можете написать что-то вроде этого, чтобы вернуть любой идентификатор, содержащий «SMS».

{
   "selector": {
      "_id": {
         "$regex": "sms"
      }
   }
}

Базовое регулярное выражение, которое вы можете использовать, включая

"^sms" roughly to LIKE "%sms"
"sms$" roughly to LIKE "sms%"

Вы можете узнать больше о регулярных выражениях здесь

0 голосов
/ 10 августа 2015

почему мы не можем просто использовать indexOf () в представлении?

0 голосов
/ 06 сентября 2013

Вы можете отправлять документы как обычно.emit(doc.name, null); Я бы добавил toLowerCase() для этого name, чтобы удалить чувствительность к регистру.

, а затем запросил бы представление с множеством клавиш, чтобы увидеть, появляется ли что-то "подобное" в запросе.

keys = differentVersions("bro"); // returns ["bro", "br", "bo", "ro", "cro", "dro", ..., "zro"]
$.couch("db").view("employeesByName", { keys: keys, success: dealWithIt } )

Некоторые соображения

  1. Очевидно, что массив может стать действительно очень большим очень быстро в зависимости от того, что возвращает differentVersions.В какой-то момент вы можете превысить лимит данных поста или предположительно получить медленный поиск.

  2. Результаты настолько же хороши, насколько differentVersions дает вам догадки о том, что этот человек хотел написать по буквам,Очевидно, что эта функция может быть простой или сложной, как вам нравится.В этом примере я попробовал две стратегии: а) удалил букву и нажал ее, и б) заменил букву в позиции n на все остальные буквы.Поэтому, если бы кто-то искал «bro», но набрал «gro», «bri» или даже «bgro», differentVersions переставил бы это в «bro» в какой-то момент.

  3. Хотя это и не идеально, но все же довольно быстро, поскольку быстрый взгляд на b-деревья Кауча быстр.

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