Простой ответ заключается в том, что представления 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, просто разделив различные разделители слов для конкретных локалей и пропустив эти "слова" в качестве ключей просмотра.Это будет более эффективно, чем указано выше, масштабирование будет пропорционально количеству проиндексированных данных.