You need to enable JavaScript to run this app.
导航
使用说明
最近更新时间:2025.07.02 17:37:25首次发布时间:2024.03.14 11:22:40
我的收藏
有用
有用
无用
无用

全文检索(或文本搜索)用于识别符合查询条件的自然语言文档。最常见的应用是查找包含指定查询词的所有文档。通过构建全文索引对文档进行预处理,可以实现高效的后续搜索。ByteHouse 企业版通过增强文本倒排索引能力,支持更快速的文本检索与过滤,并允许使用 SQL 语法执行全文检索。本文将介绍如何使用 SQL 命令创建全文索引并进行查询。

前提条件

在倒排索引使用之前需要确保所选集群开启了全文检索高级特性。开启方式请参见开启服务

功能概述

倒排索引可以为 String、Array(String)、JSON 中 String 类型构建倒排索引,提供快速的文本检索和过滤的方式。后续将支持 Nullable 类型倒排,敬请期待。
Image

索引定义

倒排索引使用 ClickHouse 二级索引 API 进行管理,二级索引常用命令均适用于倒排索引,如:ADD INDEX / DROP INDEX / MATERIALIZE INDEX / CLEAR INDEX,操作详情请参见ALTER INDEX 更改索引常用命令。以下展示了创建倒排索引的基本语法。

  • 创建表时定义索引。

    CREATE TABLE test_inverted_with_token
    (
        `key` UInt64,
        `doc` String,
        INDEX doc_idx doc TYPE inverted('standard', '{"version":"v3"}') GRANULARITY 8192
    )
    ENGINE = MergeTree()
    ORDER BY key;
    
  • 对于已有表,可使用 ALTER ADD INDEX 添加索引。

    ALTER TABLE test_inverted_with_token ADD INDEX doc_idx doc TYPE inverted('standard', '{"version":"v3"}') GRANULARITY 8192;
    
  • 为存量数据构建索引。

    ALTER TABLE test_inverted_with_token MATERIALIZE INDEX doc_idx;
    

常用 settings 参数说明如下:

  • GRANULARITY:二级索引通常将其设置为 1 , 倒排索引则支持将 GRANULARITY 设置为 8192 或更大。
  • 查询时添加 settings 参数 filter_with_inverted_index_segment = 1,可启用性能更好的过滤方式。

SQL 参考

ALTER INDEX 更改索引常用命令

倒排索引使用二级索引 API 进行管理,二级索引常用命令均适用于倒排索引。

ADD INDEX

添加索引,但不会为历史数据构建索引。

ALTER TABLE test_inverted_with_token ON CLUSTER {cluster} ADD INDEX doc_idx doc TYPE inverted('standard', '{"version":"v3"}') GRANULARITY 8192;

如需为存量数据构建索引,可执行以下命令:

ALTER TABLE test_inverted_with_token MATERIALIZE INDEX doc_idx;

DROP INDEX

删除索引,并清空索引文件。

ALTER TABLE test_inverted_with_token ON CLUSTER {cluster} DROP INDEX doc_idx;

MATERIALIZE INDEX

为存量数据构建索引。

ALTER TABLE test_inverted_with_token ON CLUSTER {cluster} MATERIALIZE INDEX doc_idx;

CLEAR INDEX

清空存量数据索引文件,但保留索引。

ALTER TABLE test_inverted_with_token ON CLUSTER {cluster} CLEAR INDEX doc_idx;

切换倒排索引版本

ByteHouse 倒排索引支持 3 个版本,您可通过指定 "version" 参数使用对应的版本,不同版本差异说明如下:

版本

功能说明

Version 3

支持分词查找,模糊匹配,高基数点查。
在 Version 1 基础上,ByteHouse 对字典进行了优化,避免了 Version 1 需将字典完全载入内存方可查询的技术瓶颈,降低 IO 与内存资源消耗压力。

Version 2

支持文本相似度查找,BM25 算法,与向量结合进行混合检索。
在 Version 1 行信息倒排列表基础上,ByteHouse 添加了频率信息/位置信息倒排列表,来用做文本相似度计算。

Version 1

继承自 ClickHouse 社区版本,建议使用 V3 版本。

使用 Version 3

INDEX doc_idx doc TYPE inverted('standard', '{"version":"v3"}') GRANULARITY 8192

使用 Version 2

INDEX doc_idx doc TYPE inverted('standard', '{"version":"v2"}') GRANULARITY 8192

使用 Version 1

INDEX doc_idx doc TYPE inverted('standard', '{"version":"v1"}') GRANULARITY 8192

为 Array/JSON/MAP 列文本内容构建倒排

ByteHouse 支持通过配置 sub_column_filters.value 指定 Array/JSON/MAP 子列,并为其构建倒排索引。

Array 列

CREATE TABLE test_inverted_with_arry_str
(
    `id` UInt64,
    `doc` Array(String),
    INDEX doc_idx doc TYPE inverted('token', '{"sub_column_filters": {"doc": ["*"]}}') GRANULARITY 8192
)
ENGINE = MergeTree()
ORDER BY id

JSON 列

  • 为指定 JSON 子列文本内容构建倒排。

    CREATE TABLE index_partial_subcols
    (
        `key` Int,
        `value` JSON,
        INDEX val_ivt value TYPE inverted('token', '{"sub_column_filters": {"value": ["k0", "k1"]}}') GRANULARITY 8192
    )
    ENGINE = MergeTree
    ORDER BY key
    
  • 为 JSON 全子列文本内容构建倒排。

    CREATE TABLE index_partial_subcols
    (
        `key` Int,
        `value` JSON,
        INDEX val_ivt value TYPE inverted('token', '{"sub_column_filters": {"value": ["*"]}}') GRANULARITY 8192
    )
    ENGINE = MergeTree
    ORDER BY key
    

MAP(String,String) 列

CREATE TABLE map_test.test_map
(
    `id` UInt32,
    `m` Map(String, String) KV,
    -- 为指定对 key1,key2 构建倒排索引 
    INDEX m_inv m TYPE inverted('token', '{"version":"v3", "sub_column_filters": { "m" : ["key1","key2"] } }') GRNULARITY 8192
)
ENGINE = MergeTree
ORDER BY id
SETTINGS index_granularity = 8192

分词算法

不同的分词算法在特定查询情况下过滤效率不同,同时也影响召回率。基于规则分词的分词算法(standard/token/ngram/char_sep分词)在绝大多数情况下,写入速度大幅优于基于语义的分词算法(ICU/中文分词)。通常情况下,关键词检索和模糊匹配场景建议使用基于规则的分词算法,相似度检索场景建议按需使用语义分词算法。

分词算法

算法类型

选取建议

standard 分词

规则分词

基于 ASCII 码中非字母字符部分进行分词,对于 UTF8 编码的词语,standard 文词将词语独立切分。
对于中英文混合文本场景,英文按词切分,中文按字切分。推荐在绝大多数搜索场景中使用该分词器(其行为等同于 Elasticsearch 的默认分词器)。

token 分词

规则分词

基于空格和标点符号进行分词。此方法主要适用于英语等以空格分隔单词的语言,也适用于无标点空格的 string id 字段。

ngram 分词

规则分词

将文本按指定长度(n)连续切分。此方法尤其适合处理无空格分隔的语言(如中文),或包含长复合词的文本。它常用于支持模糊匹配查询的场景,例如对长且无分隔符的中文文本进行搜索。

自定义分隔符

自定义分隔符,目前仅支持指定 ASCII 符号。指定该自定义分隔符后,系统将按照 seperators 中定义的所有字符进行分割。

ICU 分词

语义分词

ICU 分词( International Components for Unicode) 为通用语义分词器,支持多语言语义分词,无需配置词典,可覆盖主流国际化(i18n)语言。但该分词效率低于规则分词,建议仅在相似度检索场景下使用该分词。

中文分词

语义分词

更好地支持中文分词,且支持自定义分词表。但该分词效率低于规则分词,建议仅在相似度检索场景下使用该分词。

Standard 分词

INDEX doc_idx doc TYPE inverted('standard', '{"version":"v3"}') GRANULARITY 8192

Token 分词

INDEX doc_idx doc TYPE inverted('token', '{"version":"v3"}') GRANULARITY 8192

ngram分词

"ngrams": 3是以三元组的方式切分文本。

INDEX doc_idx doc TYPE inverted('ngram','{"version":"v3", "ngrams": 3 }') GRANULARITY 8192

自定义分割符

示例中,系统将按照 ,; 分割。

INDEX doc_idx doc TYPE inverted('char_sep','{"version":"v3","seperators": ",;"}') GRANULARITY 1

ICU 分词

使用 language 指定分词文本语种。如下示例中,"language":"zh" 为中文。

inverted('icu', '{"version": "v2", "language":"zh"}')

中文分词

绝大多数中文场景下推荐使用 JIEBA,使用时需要额外在服务器上传词典。

inverted('chinese', '{"version": "v2", "config":"default"}')
<chinese_tokenizer>
    <default>
        <dict_path>/home/cppjieba/dict/jieba.dict.utf8</dict_path>
        <hmm_model_path>/home/dict/hmm_model.utf8</hmm_model_path>
        <user_dict_path>/home/cppjieba/dict/user.dict.utf8</user_dict_path>
        <idf_path>/home/cppjieba/dict/idf.utf8</idf_path>
        <stop_words_path>/homecppjieba/dict/stop_words.utf8</stop_words_path>
    </default>
</chinese_tokenizer>

常用查询函数

String 类型

函数名

描述

hasTokens({column_name},'{value}')

在存在倒排索引(inverted index)的情况下,系统会根据分词器来将查询词完全分词并执行索引过滤。在索引过滤后读取实际数据,上传给上层函数再次进行精准字符匹配过滤。过滤效率通常优于 like '%xxx%' 模糊匹配。索引层面等价于 Elasticseatch match_phrase 语义。

{colum_name} = '{value}'

检查字段值是否等于指定值。

{colum_name} != '{value}'

检查字段值是否不等于指定值。

{colum_name} like '{value}'

检查字段值是否匹配指定模式。

{colum_name} notlike '{value}'

检查字段值是否不匹配指定模式。

hasToken({column_name},'{value}')

检查字段值是否包含指定令牌。

startsWith({column_name},'{value}')

检查字段值是否以指定前缀开头。

endsWith({column_name},'{value}')

检查字段值是否以指定后缀结尾。

multiSearchAny(column_name, [value1, ..., valueN])

对字段的任意值使用指定的搜索词进行多搜索。

{column_name} notIn [value1, ..., valueN]

检查字段值是否不在指定值列表中。

{column_name} In [value1, ..., valueN]

检查字段值是否在指定值列表中。

hasTokenBySeperator(column_name, value_literal, seperator)

检查 column_name 列在按照 seperator 分隔后是否有有某个值 value_literal 的存在。

Array(String) 类型

函数名

功能描述

has({column_name}, '{value}')

判断一个元素是否在给定的数组或集合中。

hasAny({column_name}, [value1, ..., valueN])

判断给定的数组或集合中是否至少有一个元素满足指定的条件。

arraySetCheck({column_name}, [value1, ..., valueN])

检查一个数组或集合是否满足指定的条件。

相似度检索

如下示例使用 version 2 索引, 基于 BM25 算法,通过 textSearch 函数召回与搜索文本相似的文本内容。

select * from table where textSearch(doc, 'text for sim') order by _text_search_score desc limit n;

相关 SETTINGS 参数

查询相关

参数

描述

默认值

enable_inverted_index

启用倒排索引。

1

filter_with_inverted_index_segment

使用索引分块粒度快速过滤 Mark。

0

filtered_ratio_to_use_skip_read

设置行过滤启用的过滤比例,0 代表关闭,1 代表始终启用。

0

skip_inverted_index_term_size

当分词器切分出的词语大于该值,则不会启用索引过滤该词。

512

建表相关

参数

描述

默认值

max_digestion_size_per_segment

构建索引时每处理指定量的文本信息形成一个索引块。
在内存充足时,建议将 max_digestion_size_per_segment 尽可能调大,当一个 part 中只存在 1 个 segment 时数据压缩和查询效率最好。

256 * 1024 * 1024 (256MB)

服务配置相关

参数

描述

默认值

ginindex_store_cache_size

倒排索引 LRU Cache 最大缓存量。

当前节点可用内存总量 1/8

ginindex_store_cache_sst_block_cache_size

倒排索引字典 LRU Cache 最大缓存量。

当前节点可用内存总量 1/16

常用系统表查询

倒排索引磁盘占用查询

SELECT
    name,
    formatReadableSize(sum(file_size)) as index_size
FROM system.checksums
WHERE (database = '{database}') AND (table = '{table}') AND active AND (file_name LIKE '%{index_name}%')
GROUP BY name

返回结果:
Image

倒排索引内存(LRU替换策略)占用查询

SELECT
    *,
    formatReadableSize(value)
FROM system.asynchronous_metrics
WHERE (metric LIKE '%Cache%') AND (metric LIKE '%Unified%')
ORDER BY metric ASC

返回结果:
Image

  • UnifiedGINCacheBytes:倒排索引缓存占用,最大缓存占用量支持通过设置 ginindex_store_cache_size 参数配置。
  • UnifiedSSTCacheBytes:字典缓存占用,该参数仅适用于 version 3 版本,最大字典缓存占用量支持通过 ginindex_store_cache_sst_block_cache_size参数配置。