Перейти к основному содержимому
Версия: 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 индекса.