Интернет, компьютеры, софт и прочий Hi-Tech

Подписаться через RSS2Email.ru

SQLite: расширения FTS3 и FTS4

SQLite

Содержание

  1. Введение в FTS3 и FTS4
    1. Различия между FTS3 и FTS4
    2. Создание и удаление таблиц FTS
    3. Заполнение таблиц FTS
    4. Простейшие FTS-запросы
    5. Резюме
  2. Компиляция и включение FTS3 и FTS4
  3. Запросы с использованием полнотекстового индекса
    1. Набор операций в расширенном языке запросов
    2. Набор операций в стандартном языке запросов
  4. Вспомогательные функции — Snippet, Offsets и Matchinfo
    1. Функция Offsets
    2. Функция Snippet
    3. Функция Matchinfo
  5. Токенайзеры
    1. Кастомные токенайзеры (реализуемые пользователями)
  6. Структуры данных
    1. Формат целых чисел переменного размера (varint)
    2. Формат сегмента B-дерева
      1. Листовые вершины сегмента B-дерева
      2. Внутренние узлы сегмента B-дерева
    3. Формат Doclist
  7. Приложение A: Советы по разработке приложений поиска

5. Токенайзеры

Токенайзер FTS — это набор правил для извлечения термов из документа или простого полнотекстового запроса FTS.

Если при создании таблицы FTS в запросе CREATE VIRTUAL TABLE не был указан какой-то специфический токенайзер, то будет использован умолчальный токенайзер, каковым является "simple". Этот простейший токенайзер выделяет токены из документа или простого полнотекстового запроса FTS по следующим правилам:

  • Терм — это непрерывная последовательность допустимых символов, где допустимыми являются все символы букв и цифр, символ "_", а также все символы кодировки UTF, код которых больше или равен 128. Все остальные символы отбрасываются при разбивке документа на термы. Они учитываются только как разделители рядом стоящих термов.

  • Во время процесса токенизации все символы в верхнем регистре из набора ASCII (с кодами UTF меньшими 128), преобразовываются в свои эквиваленты в нижнем регистре. В результате при использовании токенайзера simple полнотекстовые запросы становятся регистронезависимыми.

Пусть, например, документ содержит текст "Right now, they're very frustrated". Тогда из этого документа будут извлечены следующие термы для вставки в полнотекстовый индекс: "right now they re very frustrated". Когда для поиска документа будет введен такой запрос как "MATCH 'Frustrated'", токенайзер "simple" трансформирует терм запроса в нижний регистр перед поиском по полнотекстовому индексу.

Вместе с токенайзером "simple", исходный код FTS содержит также токенайзер на основе алгоритма стеминга Портера. Это токенайзер использует те же правила для разделения документа на термы и приводит их к нижнему регистру, но кроме этого он еще использует алгоритм стеминга Портера для приведения слов английского языка к основе. Например, обрабатывая тот же документ, что и в предыдущем абзаце, токенайзер Портера выделит в нем следующие токены: "right now thei veri frustrat". Хотя некоторые из этих термов не являются словами английского языка, в некоторых случаях их использование в полнотекстовом индексе делает поисковую выдачу более интеллектуальной, чем в случае токенайзера "simple". При использовании токенайзера "porter" наш примерный документ может быть найден не только запросом "MATCH 'Frustrated'", но и таким как "MATCH 'Frustration'", поскольку и терм "Frustration", и терм "Frustrated" приводятся алгоритмом стеминга Портера к одинаковой основе "frustrat". Таким образом, при использовании токенайзера "porter", FTS может находить не только точные совпадения запрашиваемых термов, но также и совпадения с другими похожими англоязычными термами. Более подробно с алгоритмом стеминга Портера можно ознакомиться по приведенной ссылке.

Пример, иллюстрирующий разницу между токенайзерами "simple" и "porter":

-- Создаем таблицу с использованием токенайзера "simple".
-- Вставляем в нее документ.
CREATE VIRTUAL TABLE simple USING fts3(tokenize=simple);
INSERT INTO simple VALUES('Right now they''re very frustrated');

-- Первый из следующих двух запросов найдет документ, сохранённый в таблице
-- "simple". Второй - не найдет.
SELECT * FROM simple WHERE simple MATCH 'Frustrated';
SELECT * FROM simple WHERE simple MATCH 'Frustration';

-- Создаем таблицу с использование токенайзера "porter". Вставляем в нее тот
-- же самый документ.
CREATE VIRTUAL TABLE porter USING fts3(tokenize=porter);
INSERT INTO porter VALUES('Right now they''re very frustrated');

-- Оба следующих запроса найдут документ, сохранённый в таблице
-- "porter".
SELECT * FROM porter WHERE porter MATCH 'Frustrated';
SELECT * FROM porter WHERE porter MATCH 'Frustration';

Если расширение скомпилировано с опцией препроцессора SQLITE_ENABLE_ICU, то существует встроенный токенайзер по имени "icu", реализованный с помощью библиотеки ICU. Первый аргумент метода xCreate() (смотрите fts3_tokenizer.h) этого токенайзера может быть идентификатором локали ICU. Например, "tr_TR" для турецкого языка, используемого в Турции, или "en_AU" для английского языка, используемого в Австралии. Пример:

CREATE VIRTUAL TABLE thai_text USING fts3(text, tokenize=icu th_TH)

Реализация токенайзера ICU очень проста. Он разбивает введённый текст согласно правилам ICU для нахождения границ слов и отбрасывает все токены, которые целиком состоят из пробелов. Он может оказаться полезным для некоторых приложений с некоторыми локализациями, но не для всех. Если требуется более сложная обработка, например для реализации стеминга или для отбрасывания пунктуации, может потребоваться создание токенайзера, который будет использовать токенайзер ICU как часть собственной реализации.

5.1. Кастомные токенайзеры (реализуемые пользователями)

Вместе со встроенными токенайзерами "simple", "porter" и (возможно) "icu" FTS предоставляет интерфейс, позволяющий самим пользователям создавать собственные токенайзеры на языке C. Этот интерфейс, используемый для создания новых токенайзеров, определяется и описывается в файле исходного кода fts3_tokenizer.h.

Регистрация нового токенайзера FTS похожа на регистрацию нового модуля виртуальных таблиц в SQLite. Пользователь передает указатели на структуру, содержащую указатели на различные функции обратного вызова, которые и составляют реализацию нового типа токенайзера. Для токенайзеров эта структура называется "sqlite3_tokenizer_module". Она определяется в файле fts3_tokenizer.h.

FTS не выставляет напоказ функции на C, которые пользователь вызывает для регистрации нового токенайзера. Вместо этого указатель на нее должен быть зашифрован как значение BLOB и посредством SQL передан FTS. Для этого предназначена специальная скалярная функция "fts3_tokenizer()". Эта функция должна быть вызвана с одним или двумя аргументами, как показано ниже:

SELECT fts3_tokenizer(<tokenizer-name>);
SELECT fts3_tokenizer(<tokenizer-name>, <sqlite3_tokenizer_module ptr>);

где <tokenizer-name> — это строка, идентифицирующая токенайзер, а <sqlite3_tokenizer_module ptr="1"> — указатель на структуру в sqlite3_tokenizer_module в SQL-формате BLOB. Если этот второй аргумент указан, он будет зарегистрирован как токенайзер <tokenizer-name> и будет возвращена его копия. Если же указан только один аргумент, то в качестве указателя на реализацию токенайзера <tokenizer-name> будет принят текущий, который и будет возвращён в виде, закодированном в BLOB. Либо, если такого токенайзера не существует, будет иметь место ошибка SQL (exception).

ПРЕДУПРЕЖДЕНИЕ БЕЗОПАСНОСТИ: Если расширение FTS3/4 используется в окружении, в котором потенциальные злоумышленники могут выполнять произвольные запросы SQL, то следует заранее предохраниться от вызовов функции fts3_tokenizer(), например с помощью обратных вызовов авторизации.

Следующий блок содержит пример вызова функции fts3_tokenizer() в коде на C:

/*
** Регистрирует реализацию токенайзера для FTS3 или FTS4.
*/
int registerTokenizer(
  sqlite3 *db,
  char *zName,
  const sqlite3_tokenizer_module *p
){
  int rc;
  sqlite3_stmt *pStmt;
  const char *zSql = "SELECT fts3_tokenizer(?, ?)";

  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
  if( rc!=SQLITE_OK ){
    return rc;
  }

  sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
  sqlite3_bind_blob(pStmt, 2, &p, sizeof(p), SQLITE_STATIC);
  sqlite3_step(pStmt);

  return sqlite3_finalize(pStmt);
}

/*
** Запрашивает у FTS реализацию токенайзера по имени zName.
*/
int queryTokenizer(
  sqlite3 *db,
  char *zName,
  const sqlite3_tokenizer_module **pp
){
  int rc;
  sqlite3_stmt *pStmt;
  const char *zSql = "SELECT fts3_tokenizer(?)";

  *pp = 0;
  rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
  if( rc!=SQLITE_OK ){
    return rc;
  }

  sqlite3_bind_text(pStmt, 1, zName, -1, SQLITE_STATIC);
  if( SQLITE_ROW==sqlite3_step(pStmt) ){
    if( sqlite3_column_type(pStmt, 0)==SQLITE_BLOB ){
      memcpy(pp, sqlite3_column_blob(pStmt, 0), sizeof(*pp));
    }
  }

  return sqlite3_finalize(pStmt);
}

Назад Вперед
4. Вспомогательные функции — Snippet, Offsets и Matchinfo 6. Структуры данных

Перевод Дмитрия Скоробогатова, 03.06.2011
Оригинальный текст может быть найден по адресу http://www.sqlite.org/fts3.html


Предыдущие публикации:

Биржа долевых инвестиций SIMEX.

Последнее редактирование: 2011-06-03 15:26:12

Метки материала: токенайзеры, sqlite, fts3, fts4, базы данных, программирование, db, sql, разработка по

Оставьте, пожалуйста, свой комментарий к публикации

Представиться как     Антибот:
   

Просьба не постить мусор. Если вы хотите потестить xBB, воспользуйтесь кнопкой предварительного просмотра на панели инструментов xBBEditor-а.


© 2007-2017, Дмитрий Скоробогатов.
Разрешается воспроизводить, распространять и/или изменять материалы сайта
в соответствии с условиями GNU Free Documentation License,
версии 1.2 или любой более поздней версии, опубликованной FSF,
если только иное не указано в самих материалах.