Хабрахабр

Нечеткий поиск (fuzzy search) в реляционных базах данных

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

Но я не нашел пока реализации такого моста. Решения с использованием elasticsearch имеют один существенный недостаток — очень большая вероятность рассогласования основной базы данных, например PostgreSQL, MySQL, mongodb и elasticsearch, в которой хранятся индексы для поиска.
Идеальным вариантом было бы наличие «моста», который бы брал на себя функцию согласования данных, в том случае когда база для поискового движка окажется недоступной во время обновления основной базы данных. Например в одном из проектов связки mongodb и lucene говорится как раз об этой проблеме.

This allows for rolling shutdowns of the nodes to update them. On a normal shutdown of a LuMongo node, all segments committed and are distributed to existing nodes. These indexes could require rollback or repair. On unexpected shutdown the segments will fail to the existing nodes without committing. Since the documents are stored in MongoDB and not in the index, another possible solution could be fetching the documents for a corrupted segment and reindexing them. Currently this is not handled automatically but it will be in future releases using Lucene's built in index repair. MongoDB's replication is data center aware backups across datacenters are possible. MongoDB also provides seamless failover through replication.

Как же решается на практике эта проблема? Да никак. Если данные не очень большие то база просто переиндексируется по таймеру. Если база большая и часто переиндексировать ее невозможно — то все остается как есть, несогласованным, просто выявить это рассогласование немного сложнее.

Сейчас же есть необходимость найти рабочее решение. Надеюсь что устойчивые «мосты», которые будут устойчиво обновлять индексы в elasticsearch или lucene рано или поздно появятся.

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

Как оказалось, есть как минимум два решения, которые используют библиотеку lucene и находятся на уровне приложений poduction ready: это orientdb и h2.

В orientdb работать с нечетким полнотекстовым поиском очень просто:

create class russian
create property russian.message string
create index russian.message on russian(message) fulltext engine lucene metadata
select * from russian where message lucene 'Харбахрб~0.5' limit 2

В h2 немного сложнее т.к. индекс это отдельная таблица с которой нужно основную таблицу связать. Но немного сложнее это не означает сложно.

CREATE ALIAS IF NOT EXISTS FTL_INIT FOR "org.h2.fulltext.FullTextLucene.init";
CALL FTL_INIT();
DROP TABLE IF EXISTS TEST;
CREATE TABLE TEST(ID INT PRIMARY KEY, FIRST_NAME VARCHAR, LAST_NAME VARCHAR);
CALL FTL_CREATE_INDEX('PUBLIC', 'TEST', NULL);
INSERT INTO TEST VALUES(1, 'John', 'Wayne');
INSERT INTO TEST VALUES(2, 'Elton', 'John');
SELECT * FROM FTL_SEARCH_DATA('John', 0, 0);
SELECT * FROM FTL_SEARCH_DATA('LAST_NAME:John', 0, 0);

apapacy@gmail.com
22 апреля 2018 года

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть