Как создать "понравившийся" вид фильтра в couchdb

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

SELECT name FROM use WHERE name LIKE % bro%

Как создать такой вид в couchdb?

Ответы

Ответ 1

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

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

1. Путь SQL

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

Вы также можете сделать это в CouchDB, с временным представлением :

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, ElasticSearch, SQLite FTS) для создания вспомогательного текстового индекса в ваших документах.

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

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

Ответ 2

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

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

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

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

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

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

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

Ответ 3

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

{
"getavailableproduct":       {         "map": "function (doc) {                var prefix = doc ['productid']. match (/[A-Za-z0-9] +/g);                           <                      >            }"    
       }
}

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

? Ключ = "[SEARCH_KEYWORD]"

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

но если я хочу набрать не полное слово (например: ea из еды, или foo из пищи), этот код не работает.

Ответ 4

Я знаю, что это старый вопрос, но: Как насчет использования функции "списка"? У вас могут быть все ваши обычные представления, и затем добавьте функцию "списка" в проектный документ для обработки результатов просмотра:

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

Ответ 5

Вы можете опубликовать свои документы, как обычно. 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 } )

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

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

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

  • Пока он не идеален, он все еще довольно быстрый, так как поиск в B-деревьях Couch выполняется быстро.

Ответ 6

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