В данной статье я хочу поделиться опытом интеграции расширения для стемминга в код SQLite. Все действия выполнялись в ОС Ubuntu 11.10.
В fts3 SQLite есть простой стеммер, реализующий алгоритм стемминга Портера, но для русских слов реализации нет. Т.е. MATCH по слову 'гостиницы' не найдёт записи, содержащие слово 'гостиница' и т.д.
Далее предполагается что исходники sqlite3 лежат в $HOME/SQLite.
Кодировка русских символов UTF-8.
Стеммер использует для латинских слов встроенный стеммер Портера, а для русских слов реализует подобный алгоритм.
Изначально код был написан для C++ и подгружался как расширение для SQLite. Я его модифицировал, чтобы можно было скомпилировать на компиляторе языка C, поэтому до красивости и строгости тут очень далеко. Вот что у меня вышло:
fts3_porter_ext.c
Кладём наш стеммер в $HOME/SQLite/ext/fts3/fts3_porter_ext.c
Правим файл $HOME/SQLite/Makefile.in.
Правим $HOME/SQLite/ext/fts3/fts3.c.
Добавляем после строки
строку
После строки
Добавляем инициализацию нашего модуля
Наконец, после
добавляем наш модуль в хэш встроенных токенайзеров
Правим $HOME/SQLite/ext/fts3/mkfts3amal.tcl
После строки
Добавляем
Правим $HOME/SQLite/tool/mksqlite3c.tcl
После строки
Добавляем
Выполним следующее (--prefix=$HOME лучше заменить на что-нибудь более вменяемое. Это будет путь установки)
Теперь проверим, что наш стеммер попал в sqlite3.c
Должно получиться что-то вроде этого:
Теперь устанавливаем sqlite3 на компьютер:
При создании таблиц fts3 нужно указать наш стеммер, например так:
Теперь, при MATCH запросах к таблице tag_fti будет использоваться наш стеммер.
Мы получили 2 файла sqlite3.c и sqlite3.h, которые можно подключать к нашим проектам.
Нет необходимости в загрузке модулей расширения.
Получили консольный клиент, который корректно обрабатывает запросы к fts3 таблицам, которые будут создавать наши приложения. Верно и обратное, что таблицы, созданные консольным клиентом, будут обработаны и нашими приложениями.
Буду рад, если статья для кого-нибудь станет полезной.
Upd: подправил ссылки
Проблема
В 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: подправил ссылки