Перейти к основному содержимому
Версия: 2.0.x

Полнотекстовый inverted индекс

Начиная с версии 3.3.0, Selena поддерживает полнотекстовые inverted индексы, которые могут разбивать текст на более мелкие слова и создавать индексную запись для каждого слова, показывающую отношение отображения между словом и соответствующим номером строки в файле данных. Для полнотекстового поиска Selena запрашивает inverted индекс на основе ключевых слов поиска, быстро определяя строки данных, соответствующие ключевым словам.

Primary Key таблицы поддерживают полнотекстовые inverted индексы начиная с v2.0.0.

Полнотекстовый inverted индекс пока не поддерживается в shared-data кластерах.

Обзор​

Selena хранит свои базовые данные в файлах данных, организованных по столбцам. Каждый файл данных содержит полнотекстовый inverted индекс на основе индексированных столбцов. Значения в индексированных столбцах токенизируются на отдельные слова. Каждое слово после токенизации обрабатывается как индексная запись, отображаемая на номер строки, в которой появляется слово. В настоящее время поддерживаются методы токенизации для английской токенизации, китайской токенизации, многоязычной токенизации и без токенизации.

Например, если строка данных содержит "hello world" и её номер строки 123, полнотекстовый inverted индекс строит индексные записи на основе этого результата токенизации и номера строки: hello->123, world->123.

Во время полнотекстового поиска Selena может находить индексные записи, содержащие ключевые слова поиска, используя полнотекстовые inverted индексы, а затем быстро находить номера строк, в которых появляются ключевые слова, значительно уменьшая количество строк данных, которые необходимо сканировать.

Базовые операции​

Создание полнотекстового inverted индекса​

Перед созданием полнотекстового inverted индекса необходимо включить параметр конфигурации FE enable_experimental_gin.

ADMIN SET FRONTEND CONFIG ("enable_experimental_gin" = "true");
примечание

При создании полнотекстового inverted индекса для таблицы необходимо отключить функцию replicated_storage для таблицы.

  • Для v2.0.0 и более поздних версий эта функция автоматически отключается при создании индекса.
  • Для версий ранее v2.0.0 необходимо вручную установить свойство таблицы replicated_storage в false.

Создание полнотекстового Inverted индекса при создании таблицы​

Создание полнотекстового inverted индекса на столбце v с английской токенизацией.

CREATE TABLE `t` (
`k` BIGINT NOT NULL COMMENT "",
`v` STRING COMMENT "",
INDEX idx (v) USING GIN("parser" = "english")
) ENGINE=OLAP
DUPLICATE KEY(`k`)
DISTRIBUTED BY HASH(`k`) BUCKETS 1
PROPERTIES (
"replicated_storage" = "false"
);
  • Параметр parser указывает метод токенизации. Поддерживаемые значения и описания следующие:
    • none (по умолчанию): без токенизации. Вся строка данных в индексированном столбце обрабатывается как один индексный элемент при построении полнотекстового inverted индекса.
    • english: английская токенизация. Этот метод токенизации обычно разбивает на любом не-алфавитном символе. Также заглавные английские буквы преобразуются в строчные. Следовательно, ключевые слова в условиях запроса должны быть строчными английскими буквами, а не заглавными, чтобы использовать полнотекстовый inverted индекс для поиска строк данных.
    • chinese: китайская токенизация. Этот метод токенизации использует CJK Analyzer в CLucene для токенизации.
    • standard: многоязычная токенизация. Этот метод токенизации обеспечивает токенизацию на основе грамматики (основанную на алгоритме сегментации текста Unicode) и хорошо работает для большинства языков и случаев смешанных языков, таких как китайский и английский. Например, этот метод токенизации может различать китайский и английский, когда эти два языка сосуществуют. После токенизации английского он преобразует заглавные английские буквы в строчные. Следовательно, ключевые слова в условиях запроса должны быть строчными английскими буквами, а не заглавными, чтобы использовать полнотекстовый inverted индекс для поиска строк данных.
  • Тип данных индексированного столбца должен быть CHAR, VARCHAR или STRING.

Добавление полнотекстового inverted индекса после создания таблицы​

После создания таблицы вы можете добавить полнотекстовый inverted индекс, используя ALTER TABLE ADD INDEX или CREATE INDEX.

ALTER TABLE t ADD INDEX idx (v) USING GIN('parser' = 'english');
CREATE INDEX idx ON t (v) USING GIN('parser' = 'english');

Управление полнотекстовым inverted индексом​

Просмотр полнотекстового inverted индекса​

Выполните SHOW CREATE TABLE для просмотра полнотекстовых inverted индексов.

MySQL [example_db]> SHOW CREATE TABLE t\G

Удаление полнотекстового inverted индекса​

Выполните ALTER TABLE ADD INDEX или DROP INDEX для удаления полнотекстовых inverted индексов.

DROP INDEX idx on t;
ALTER TABLE t DROP index idx;

Ускорение запросов с помощью полнотекстового inverted индекса​

После создания полнотекстового inverted индекса необходимо убедиться, что системная переменная enable_gin_filter включена, чтобы inverted индекс мог ускорять запросы. Также необходимо учитывать, токенизированы ли значения столбцов индекса, чтобы определить, какие запросы могут быть ускорены.

Поддерживаемые запросы при токенизированном индексированном столбце​

Если полнотекстовый inverted индекс токенизирует индексированные столбцы, то есть 'parser' = 'standard|english|chinese', для фильтрации данных с использованием полнотекстовых inverted индексов поддерживается только предикат MATCH или MATCH_ANY, и формат должен быть <col_name> (NOT) MATCH '%keyword%' или <col_name> (NOT) MATCH_ANY 'keyword1, keyword2'. keyword должно быть строковым литералом и не поддерживает выражения.

  1. Создайте таблицу и вставьте несколько строк тестовых данных.

    CREATE TABLE `t` (
    `id1` bigint(20) NOT NULL COMMENT "",
    `value` varchar(255) NOT NULL COMMENT "",
    INDEX gin_english (`value`) USING GIN ("parser" = "english") COMMENT 'english index'
    )
    DUPLICATE KEY(`id1`)
    DISTRIBUTED BY HASH(`id1`)
    PROPERTIES (
    "replicated_storage" = "false"
    );


    INSERT INTO t VALUES
    (1, "selena is a database

    1"),
    (2, "selena is a data warehouse");
  2. Используйте предикат MATCH для запросов.

  • Запрос строк данных, столбец value которых содержит ключевое слово selena.

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH "selena";
  • Получите строки данных, столбец value которых содержит ключевое слово, начинающееся с data.

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH "data%";
  1. Используйте предикат MATCH_ANY для запросов.
  • Запрос строк данных, столбец value которых содержит ключевое слово database или data.

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH_ANY "database data";

Примечания:

  • Во время запросов ключевые слова могут быть сопоставлены нечётко с использованием %, в формате %keyword%. Однако ключевое слово должно содержать часть слова. Например, если ключевое слово selena , оно не может соответствовать слову selena, потому что содержит пробелы.

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH "star%";
    +------+-------------------------------+
    | id1 | value |
    +------+-------------------------------+
    | 1 | selena is a database1 |
    | 2 | selena is a data warehouse |
    +------+-------------------------------+
    2 rows in set (0.02 sec)

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH "selena ";
    Empty set (0.02 sec)
  • Если английская или многоязычная токенизация используется для построения полнотекстового inverted индекса, заглавные английские слова преобразуются в строчные при фактическом хранении полнотекстового inverted индекса. Следовательно, во время запросов ключевые слова должны быть строчными, а не заглавными, чтобы использовать полнотекстовый inverted индекс для поиска строк данных.

    MySQL [example_db]> INSERT INTO t VALUES (3, "Selena is the BEST");

    MySQL [example_db]> SELECT * FROM t;
    +------+-------------------------------+
    | id1 | value |
    +------+-------------------------------+
    | 1 | selena is a database |
    | 2 | selena is a data warehouse |
    | 3 | Selena is the BEST |
    +------+-------------------------------+
    3 rows in set (0.02 sec)

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH "BEST"; -- Ключевое слово в верхнем регистре
    Empty set (0.02 sec) -- Возвращает пустой набор результатов

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH "best"; -- Ключевое слово в нижнем регистре
    +------+-----------------------+
    | id1 | value |
    +------+-----------------------+
    | 3 | Selena is the BEST | -- Может найти строки данных, соответствующие условию
    +------+-----------------------+
    1 row in set (0.01 sec)
  • Предикат MATCH или MATCH_ANY в условиях запроса должен использоваться как pushdown предикат, поэтому он должен быть в предложении WHERE и выполняться для индексированного столбца.

    Возьмём следующую таблицу и тестовые данные в качестве примера:

    CREATE TABLE `t_match` (
    `id1` bigint(20) NOT NULL COMMENT "",
    `value` varchar(255) NOT NULL COMMENT "",
    `value_test` varchar(255) NOT NULL COMMENT "",
    INDEX gin_english (`value`) USING GIN("parser" = "english") COMMENT 'english index'
    )
    ENGINE=OLAP
    DUPLICATE KEY(`id1`)
    DISTRIBUTED BY HASH (`id1`) BUCKETS 1
    PROPERTIES (
    "replicated_storage" = "false"
    );

    INSERT INTO t_match VALUES (1, "test", "test");

    Следующие операторы запроса не соответствуют требованиям:

    • Поскольку предикат MATCH в операторе запроса не находится в предложении WHERE, он не может быть отправлен вниз, что приводит к ошибке запроса.

      MySQL [test]> SELECT value MATCH "test" FROM t_match;
      ERROR 1064 (HY000): Match can only be used as a pushdown predicate on a column with GIN in a single query.
    • Поскольку столбец value_test, для которого выполняется предикат MATCH в операторе запроса, не является индексированным столбцом, запрос не выполняется.

      MySQL [test]> SELECT * FROM t_match WHERE value_test match "test";
      ERROR 1064 (HY000): Match can only be used as a pushdown predicate on a column with GIN in a single query.

Поддерживаемые запросы при нетокенизированном индексированном столбце​

Если полнотекстовый inverted индекс не токенизирует индексированный столбец, то есть 'parser' = 'none', все pushdown предикаты в условиях запроса, перечисленные ниже, могут использоваться для фильтрации данных с использованием полнотекстового inverted индекса:

  • Предикаты выражений: (NOT) LIKE, (NOT) MATCH, (NOT) MATCH_ANY

    примечание
    • В этом случае MATCH семантически эквивалентен LIKE.
    • MATCH и LIKE поддерживают только формат (NOT) <col_name> MATCH|LIKE '%keyword%'. keyword должно быть строковым литералом и не поддерживает выражения. Обратите внимание, что если LIKE не соответствует этому формату, даже если запрос может выполняться нормально, он деградирует до запроса, который не использует полнотекстовый inverted индекс для фильтрации данных.
  • Регулярные предикаты: ==, !=, <=, >=, NOT IN, IN, IS NOT NULL, NOT NULL

Проверка, ускоряется ли запрос полнотекстовым inverted индексом​

После выполнения запроса вы можете просмотреть детальные метрики GinFilterRows и GinFilter в узле сканирования Query Profile, чтобы увидеть количество отфильтрованных строк и время фильтрации с использованием полнотекстового inverted индекса.