Pull to refresh

Интеграция алгоритма стемминга русских слов в fts3 SQLite

Website developmentSQLite
Sandbox
В данной статье я хочу поделиться опытом интеграции расширения для стемминга в код SQLite. Все действия выполнялись в ОС Ubuntu 11.10.

Проблема


В fts3 SQLite есть простой стеммер, реализующий алгоритм стемминга Портера, но для русских слов реализации нет. Т.е. MATCH по слову 'гостиницы' не найдёт записи, содержащие слово 'гостиница' и т.д.

Подготовка к компиляции


Что понадобится

  • исходники sqlite3 с репозитория;
  • наш стеммер на языке C (см. далее);
  • опционально библиотека readline (libreadline), если нужна история вводимых команд для консольного клиента.


Далее предполагается что исходники sqlite3 лежат в $HOME/SQLite.

Код стеммера

Кодировка русских символов UTF-8.
Стеммер использует для латинских слов встроенный стеммер Портера, а для русских слов реализует подобный алгоритм.
Изначально код был написан для C++ и подгружался как расширение для SQLite. Я его модифицировал, чтобы можно было скомпилировать на компиляторе языка C, поэтому до красивости и строгости тут очень далеко. Вот что у меня вышло:
fts3_porter_ext.c
Кладём наш стеммер в $HOME/SQLite/ext/fts3/fts3_porter_ext.c

Правка файлов

Makefile.in

Правим файл $HOME/SQLite/Makefile.in.
  • Добавляем к переменной LIBOBJS0 стеммер fts3_porter_ext.lo
  • К переменной SRC добавляем $(TOP)/ext/fts3/fts3_porter_ext.c
  • Пишем правило для сборки fts3_porter_ext.lo:
    fts3_porter_ext.lo: $(TOP)/ext/fts3/fts3_porter_ext.c $(HDR) $(EXTHDR)
    $(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3_porter_ext.c

fts3.c

Правим $HOME/SQLite/ext/fts3/fts3.c.
Добавляем после строки
void sqlite3Fts3PorterTokenizerModule(sqlite3_tokenizer_module const**ppModule);

строку
void sqlite3Fts3PorterTokenizerModule1(sqlite3_tokenizer_module const**ppModule);

После строки
sqlite3Fts3PorterTokenizerModule(&pPorter);

Добавляем инициализацию нашего модуля
const sqlite3_tokenizer_module *pPorter1 = 0;
sqlite3Fts3PorterTokenizerModule1(&pPorter1);

Наконец, после
|| sqlite3Fts3HashInsert(pHash, "porter", 7, (void *)pPorter)

добавляем наш модуль в хэш встроенных токенайзеров
|| sqlite3Fts3HashInsert(pHash, "russian", 8, (void *)pPorter1)

mkfts3amal.tcl

Правим $HOME/SQLite/ext/fts3/mkfts3amal.tcl
После строки
fts3_tokenizer1.c

Добавляем
fts3_porter_ext.c

mksqlite3c.tcl

Правим $HOME/SQLite/tool/mksqlite3c.tcl
После строки
fts3_tokenizer1.c

Добавляем
fts3_porter_ext.c


Компиляция


Выполним следующее (--prefix=$HOME лучше заменить на что-нибудь более вменяемое. Это будет путь установки)
cd $HOME/SQLite && mkdir build && cd build && ../configure --prefix=$HOME CFLAGS='-DSQLITE_SOUNDEX -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS' && make

Теперь проверим, что наш стеммер попал в sqlite3.c
grep fts3_porter_ext.c sqlite3.c

Должно получиться что-то вроде этого:
/************** Begin file fts3_porter_ext.c *********************************/
/************** End of fts3_porter_ext.c *************************************/

Теперь устанавливаем sqlite3 на компьютер:
sudo make install


Использование


При создании таблиц fts3 нужно указать наш стеммер, например так:
CREATE VIRTUAL TABLE tag_fti USING fts3(name, tokenize=russian);

Теперь, при MATCH запросах к таблице tag_fti будет использоваться наш стеммер.

Итог


Мы получили 2 файла sqlite3.c и sqlite3.h, которые можно подключать к нашим проектам.
Нет необходимости в загрузке модулей расширения.
Получили консольный клиент, который корректно обрабатывает запросы к fts3 таблицам, которые будут создавать наши приложения. Верно и обратное, что таблицы, созданные консольным клиентом, будут обработаны и нашими приложениями.
Буду рад, если статья для кого-нибудь станет полезной.

Upd: подправил ссылки
Tags:SQLiteрусский языкстеммингfts
Hubs: Website development SQLite
Total votes 23: ↑21 and ↓2 +19
Views4.8K
Редактор новостей на Хабре
from 30,000 to 70,000 ₽ХабрRemote job
Менеджер по работе с клиентами
from 40,000 to 80,000 ₽LikeVRRemote job
Tech Lead (Development)
from 180,000 ₽Game InsightRemote job
Sales Development Representative
from 70,000 ₽ЛАНИТМосква

Top of the last 24 hours