跳到主要内容
版本: 最新版本-3.5

全文倒排索引

自 3.3.0 版本起,StarRocks 支持全文倒排索引,该索引可以将文本分解为更小的词,并为每个词创建一个索引条目,该条目可以显示词与数据文件中相应行号之间的映射关系。对于全文搜索,StarRocks 会根据搜索关键字查询倒排索引,快速定位与关键字匹配的数据行。

Primary Key 表和 Shared-data 集群尚不支持全文倒排索引。

概述

StarRocks 将底层数据存储在按列组织的数据文件中。每个数据文件都包含基于索引列的全文倒排索引。索引列中的值被标记化为单个词。标记化后的每个词都被视为一个索引条目,映射到该词出现的行号。当前支持的标记化方法包括英语标记化、中文标记化、多语言标记化和无标记化。

例如,如果一个数据行包含 “hello world”,其行号为 123,则全文倒排索引会基于该标记化结果和行号构建索引条目:hello->123,world->123。

在全文搜索期间,StarRocks 可以使用全文倒排索引定位包含搜索关键字的索引条目,然后快速找到关键字出现的行号,从而显著减少需要扫描的数据行数。

基本操作

创建全文倒排索引

在创建全文倒排索引之前,您需要启用 FE 配置项 enable_experimental_gin

ADMIN SET FRONTEND CONFIG ("enable_experimental_gin" = "true");

此外,全文倒排索引只能在 Duplicate Key 表中创建,并且表属性 replicated_storage 需要为 false

在创建表时创建全文倒排索引

在列 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(默认):不进行标记化。在构造全文倒排索引时,索引列中的整行数据被视为单个索引项。
    • english:英语标记化。此标记化方法通常在任何非字母字符处进行标记化。此外,大写英文字母会转换为小写。因此,查询条件中的关键字需要是小写英文而不是大写英文,才能利用全文倒排索引来定位数据行。
    • chinese:中文标记化。此标记化方法使用 CLucene 中的 CJK Analyzer 进行标记化。
    • standard:多语言标记化。此标记化方法提供基于语法的标记化(基于 Unicode 文本分割算法),并且适用于大多数语言和混合语言的情况,例如中文和英文。例如,此标记化方法可以区分中文和英文在两种语言共存时。在标记化英文后,它会将大写英文字母转换为小写。因此,查询条件中的关键字需要是小写英文而不是大写英文,才能利用全文倒排索引来定位数据行。
  • 索引列的数据类型必须为 CHAR、VARCHAR 或 STRING。

在创建表后添加全文倒排索引

创建表后,您可以使用 ALTER TABLE ADD INDEXCREATE INDEX 添加全文倒排索引。

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

管理全文倒排索引

查看全文倒排索引

执行 SHOW CREATE TABLE 以查看全文倒排索引。

MySQL [example_db]> SHOW CREATE TABLE t\G

删除全文倒排索引

执行 ALTER TABLE ADD INDEXDROP INDEX 以删除全文倒排索引。

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

通过全文倒排索引加速查询

创建全文倒排索引后,您需要确保系统变量 enable_gin_filter 已启用,以便倒排索引可以加速查询。此外,您需要考虑是否对索引列值进行了标记化,以确定哪些查询可以被加速。

当索引列被标记化时支持的查询

如果全文倒排索引对索引列进行标记化,即 'parser' = 'standard|english|chinese',则只有 MATCH 谓词支持使用全文倒排索引进行数据过滤,格式需要为 <col_name> (NOT) MATCH '%keyword%'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, "starrocks is a database

    1"),
    (2, "starrocks is a data warehouse");
  2. 使用 MATCH 谓词进行查询。

  • 查询 value 列包含关键字 starrocks 的数据行。

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH "starrocks";
  • 检索 value 列包含以 data 开头的关键字的数据行。

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH "data%";

注意

  • 在查询期间,可以使用 % 模糊匹配关键字,格式为 %keyword%。但是,关键字必须包含单词的一部分。例如,如果关键字为 starrocks ,则它无法匹配单词 starrocks,因为它包含空格。

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

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH "starrocks ";
    Empty set (0.02 sec)
  • 如果使用英语或多语言标记化来构造全文倒排索引,则大写英文单词在实际存储全文倒排索引时会转换为小写。因此,在查询期间,关键字需要是小写而不是大写,才能利用全文倒排索引来定位数据行。

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

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

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH "BEST"; -- Keyword is uppercase English
    Empty set (0.02 sec) -- Returns an empty result set

    MySQL [example_db]> SELECT * FROM t WHERE t.value MATCH "best"; -- Keyword is lowercase English
    +------+-----------------------+
    | id1 | value |
    +------+-----------------------+
    | 3 | StarRocks is the BEST | -- Can locate data rows that meet the condition
    +------+-----------------------+
    1 row in set (0.01 sec)
  • 查询条件中的 MATCH 谓词必须用作下推谓词,因此它必须在 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.
    • 由于查询语句中执行 MATCH 谓词的列 value_test 不是索引列,因此查询失败。

      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.

当索引列未被标记化时支持的查询

如果全文倒排索引不对索引列进行标记化,即 'parser' = 'none',则可以使用以下查询条件中的所有下推谓词,通过全文倒排索引进行数据过滤

  • 表达式谓词:(NOT) LIKE, (NOT) MATCH

    注意
    • 在这种情况下,MATCH 在语义上等同于 LIKE
    • MATCHLIKE 仅支持格式 (NOT) <col_name> MATCH|LIKE '%keyword%'keyword 必须是字符串字面量,不支持表达式。请注意,如果 LIKE 不满足此格式,即使查询可以正常执行,它也会降级为不使用全文倒排索引来过滤数据的查询。
  • 常规谓词:==, !=, <=, >=, NOT IN, IN, IS NOT NULL, NOT NULL

如何验证全文倒排索引是否加速查询

执行查询后,您可以查看 Query Profile 的 scan 节点中的详细指标 GinFilterRowsGinFilter,以查看使用全文倒排索引过滤的行数和过滤时间。