You need to enable JavaScript to run this app.
导航
通过 SQL 使用向量检索
最近更新时间:2025.05.27 10:59:26首次发布时间:2025.05.22 14:33:42
我的收藏
有用
有用
无用
无用

ByteHouse 提供向量数据的管理与近似度查询功能,通过支持多种常见近似向量查询(Approximate Nearest Neighbor,ANN)算法来提升检索性能,提供对非结构化数据的处理能力。本文介绍了如何使用 SQL 语句在 ByteHouse 中使用 HNSW 或 Faiss Indices 算法库进行向量检索。

背景信息

ByteHouse 当前支持 HNSW(hnswlib)Faiss 两个比较流行的检索算法库,支持 HNSW、FLAT、IVF_FLAT、IVF_PQ、IVF_PQ_FS 等多种常用索引。
HNSW 算法库为图类型索引,通过一种最小世界建立图的思路,为每个节点维护 M 个最近邻节点。同时,维护一个分层图结构,越向上越稀疏,查询时从最上层开始,找到最近点以后继续向下一层计算,直到最底层,得到查询向量的 k 个最近邻。
Faiss 是 Facebook 开源的 ANN 算法库,包含了倒排(Inverted File,IVF)、乘积量化(Product Quantization,PQ)、标量量化(Scalar Quantization,SQ)等多种类型的索引,同时多种索引还可以组合使用。ByteHouse 主要使用 Faiss 的 IVF 类索引,同时支持 PQ、PQ_FS(Fsat Scan,快速搜索)等向量压缩方法,以减少索引的内存使用。

前提条件
  • 请确保您使用的 ByteHouse 满足为 v2.2 及以上版本。您可登录 ByteHouse 控制台,单击顶部租户管理,在基础信息页面中查看您使用的引擎版本。
    Image
  • 请确保您已开启向量检索服务。

快速开始

ANN 算法库以索引(index)的方式接入,支持通过创建表(create table)或修改表(alter table)添加定义。定义索引后,支持插入数据和使用索引查询。本章节以 HNSW 索引类型为例,帮助您快速上手使用向量检索功能。对于不同索引的详细说明,请参见使用 HNSW 索引使用 Faiss Indices 索引章节。

定义索引

方式 1:新建表时定义

CREATE TABLE test_ann
(
    `id` UInt64,
    `label` String,
    `vector` Array(Float32),
    INDEX v1 vector TYPE HNSW('DIM=960, METRIC=COSINE')
)
ENGINE = CnchMergeTree
ORDER BY id
SETTINGS 
index_granularity = 1024, -- 缓解读放大问题
index_granularity_bytes = 0 -- 避免生成 adaptive mark

方式 2:修改已有表定义

ALTER TABLE test_ann ADD INDEX v1 vector TYPE HNSW('DIM=960, METRIC=COSINE')

参数说明

参数项

是否必填

配置说明

test_ann

自定义表名称。

``vector Array(Float32)

vector 列数据类型定义为 Array(Float32),通常用于存储向量数据。

INDEX v1 vector

定义索引。本文中基于 vector 字段定义了一个名为 v1 的索引,用于加速对 vector 字段的查询。

TYPE HNSW('DIM=960, METRIC=COSINE')

定义使用的索引类型,并配置对应索引类型相关的内部参数。

  • 索引类型:当前支持 HNSW、FLAT、IVF_FLAT、IVF_PQ、IVF_PD_FS。
  • 内部参数:内部参数按 key-value 格式进行配置,多个参数使用逗号分隔,例如:DIM=960, METRIC=COSINE。其中:
    • DIM:定义索引对应向量的维度信息,必须与向量实际的维度一致。
    • METRIC:定义建立索引时的度量方式。METRIC 参数可以不指定,默认值为 L2,您也可手动配置为 L2 或 COSINE。需要说明的是,后续只有使用对应 metric 的 distance 函数,才能执行基于索引的查询链路。例如,如果索引中 metric 为 L2,后续查询需使用 L2Distance 函数进行查询才能使用对应索引,同理,metric 为 COSINE 时,需要使用 cosineDistance 函数进行查询。

索引类型的详细使用指导请参见使用 HNSW 索引使用 Faiss Indices 索引章节。

ENGINE

指定表的存储引擎。配置为 CnchMergeTree。

ORDER BY

指定表中的数据的排序。

SETTINGS

  • index_granularity:表示索引粒度,即索引中每个标记(mark)对应的行数。设置该参数可以缓解读放大问题,提高查询性能。
  • index_granularity_bytes:表示索引粒度的字节数,当设置为 0 时,会避免生成 adaptive mark,使得索引标记的生成仅基于行数,而不是基于数据的字节数。

ByteHouse 支持配置的全量 settings 参数列表请参见Settings 参数

插入数据

支持 ByteHouse 自身的插入(insert)语句,以及 Kafka 等流式导入方式,详情请参见数据导入文档。示例如下:

  • 通过 VALUES 字段导入数据

    INSERT INTO test_ann (id, vector) VALUES (1, [1.0, 1.0, 1.0]),(2, [2.0, 2.0, 2.0])
    
  • 通过 CSV 文件导入数据

    INSERT INTO test_ann FORMAT CSV infile '/filename.csv'
    

使用索引查询

本节介绍了如何使用索引查询数据,包含了常规查询和添加 prewhere 条件的混合查询。此外,ByteHouse 也支持添加 where 条件过滤搜索结果,通过相似度阈值筛选符合条件的记录,详情请参见Distance 过滤

常规查询

select 
    id, 
    label,
    dist 
from test_ann 
order by cosineDistance(vector, [query_vector]) as dist 
limit 100 
settings enable_new_ann=1

参数项

是否必填

配置说明

cosineDistance(vector, [query_vector])

定义向量相似度计算公式。

  • Distance 函数必须与 index 定义的 metric 对应上才能正确使用索引,例如建表语法示例中 metric 定义为 cosine,则查询语法中也应使用 cosine。
  • vector 为定义的向量字段。
  • [query_vector] 为您需要输入的查询向量。

order by ... as dist

将计算结果重命名为 dist 并按升序排序。
目前只有带有 order by {metric}Distance limit k 模式的查询才会使用向量索引计算。

limit

设置返回的记录数。

settings

enable_new_ann:需设置为 1 ,表示启用新实现的 ANN 查询路径。
ByteHouse 支持配置的全量 settings 参数列表请参见Settings 参数

混合查询

ByteHouse 当前也支持带有 prewhere 的混合查询使用方式,例如以下示例使用 prewhere id > 1000 添加预过滤条件,仅处理 id > 1000 的记录。

select 
    id,
    label,
    dist 
from test_ann 
prewhere id > 1000
order by cosineDistance(vector, [query_vector]) as dist 
limit 100 
settings enable_new_ann=1

使用 HNSW 索引

索引构建语法

使用 HNSW 索引时,可以定义参数 MEF_CONSTRUCTION,借助这两个参数权衡性能和准确度表现。一般来说 M 的值越大,EF_CONSTRUCTION 的值越大,索引构建时间越长,准确度越高,搜索延迟越高。示例如下:

CREATE TABLE test_ann
(
    `id` UInt64,
    `vector` Array(Float32),
    INDEX v1 vector TYPE HNSW('DIM=960, METRIC=COSINE, M=32, EF_CONSTRUCTION=512')
)
ENGINE = MergeTree
ORDER BY id
SETTINGS index_granularity = 1024

HNSW 索引支持配置的索引参数说明如下。全量索引参数表及使用建议请参见索引参数

参数项

是否必填

配置说明

M

定义了 HNSW 图中每个节点的最大连接数(Max Connections),默认值为 16。M 值较大时(如设置为 32),可以提高搜索速度,但会增加内存占用。M 值较小时(如设置为 4-16),可以降低内存占用,但会降低召回率。

EF_CONSTRUCTION

定义了索引构建时的探索因子(Exploration Factor),默认值为 200。该值较大(如 512)时,搜索精度更好,但构建时间越长。该值较小(如 100)时,构建速度更快,但索引质量可能会降低。

查询语法

您可使用查询语句检索数据。
此外,ByteHouse 还支持支持添加 prewhere 语句添加预过滤条件,详情请参见混合查询;也支持添加 where 语句用于过滤搜索结果,通过相似度阈值筛选符合条件的记录,详情请参见Distance 过滤

select 
    id, 
    dist 
from test_ann 
order by cosineDistance(vector, [query_vector]) as dist 
limit 100 
settings enable_new_ann=1, hnsw_ef_s=200

参数说明

参数项

是否必填

配置说明

settings

hnsw_ef_s:通过设置该值用于控制准确度和延迟。该参数值越大,准确度越高,延迟越长,大于 EF_CONSTRUCTION 参数后,理论上准确度不会有更大提升。
ByteHouse 支持配置的全量 settings 参数列表请参见Settings 参数

使用 Faiss Indices 索引

注意事项

Faiss 不同于 HNSW,构建索引时会进行训练,对 CPU 消耗比较大。使用时,请注意设置以下参数:

  • 根据内存大小设置索引缓存(cache)大小,可使用 vector_index_cache_size 参数配置,默认 200GB。该参数基于最近最少使用策略(Least Recently Used,LRU)实现。
  • 测试时,可以关注 CPU 的使用率,如果 CPU 使用过高,可以设置 vector_index_build_threads 的参数值,默认值为 8,以限制 train index 的并发。

索引构建语法

Faiss 提供了四种常用的索引类型,并提供了对应的微调参数,用于微调准确度。

FLAT 索引

FLAT 是 Faiss 中最简单的索引类型,基于暴力搜索实现。它将所有向量存储在内存中,查询时计算查询向量与所有向量的距离,返回最近邻。FLAT 实现简单,无需训练,精确性高,但时间复杂度为 O(n),不适合超大规模数据库。建议在数据量较小、向量维度低、对查询速度要求不高但需要精确结果的情况下使用。

CREATE TABLE tab_flat
(
    id Int32, 
    vector Array(Float32), 
    INDEX faiss_index vector TYPE FLAT('dim=4') GRANULARITY 1
) 
ENGINE = MergeTree 
ORDER BY id 
SETTINGS index_granularity = 128

FLAT 索引支持设置的索引参数如下。全量索引参数表及使用建议请参见索引参数

参数项

是否必填

配置说明

dim

定义对应向量的维度。

metric

定义建立索引时的度量方式。METRIC 参数可以不指定,默认值为 L2,您也可手动配置为 L2 或 COSINE。

GRANULARITY

定义索引粒度,表示每 1 个数据块(mark)构建一次索引。

IVF_FLAT 索引

IVF_FLAT 索引结合了倒排文件(IVF)和 FLAT 索引的优点,能够在保持较高检索精度的同时显著提升查询效率,适合中等规模到大规模的低维度向量检索任务(如 4-128 维)。

CREATE TABLE tab_ivf_flat
(
    id Int32, 
    vector Array(Float32), 
    INDEX faiss_index vector TYPE IVF_FLAT('dim=4') GRANULARITY 1
) 
ENGINE = MergeTree 
ORDER BY id 
SETTINGS index_granularity = 128

IVF_FLAT 索引支持配置的索引参数说明如下。全量索引参数表及使用建议请参见索引参数

参数项

是否必填

配置说明

dim

定义对应向量的维度。

metric

定义建立索引时的度量方式。METRIC 参数可以不指定,默认值为 L2,您也可手动配置为 L2 或 COSINE。

nlist

定义 IVF 类型索引需要的聚类中心数量,数量越多,构建越慢。如果不设置引擎会自动推算,逻辑如下,您可在建表时使用 nlist 参数指定每个 part 构建索引时 nlist 的上限。

static size_t decideIndexNlist(size_t n)
{
    if (n < ONE_MILLION)
        return std::min(int(n), int(4 * std::floor(std::sqrt(n))));
    else if (n >= ONE_MILLION && n < ONE_MILLION * 2)
        return 1024;
    else if (n >= ONE_MILLION * 2 && n < TEN_MILLION)
        return 4096;
    else if (n > TEN_MILLION)
        return 65536;
}

GRANULARITY

定义索引粒度,表示每 1 个数据块(mark)构建一次索引。

IVF_PQ 索引

IVF_PQ 索引是一种高效的向量压缩和索引方法,结合了倒排文件(IVF)和乘积量化(PQ)的技术,能够在大幅降低内存占用的同时保持较高的检索精度,适用于超大规模数据集(亿级以上向量)。

CREATE TABLE tab_ivf_pq
(
    id Int32, 
    vector Array(Float32), 
    INDEX faiss_index vector TYPE IVF_PQ('dim=4','m=4','nbit=4') GRANULARITY 1
) 
ENGINE = MergeTree 
ORDER BY id 
SETTINGS index_granularity = 128

IVF_PQ 索引支持配置的索引参数说明如下。全量索引参数表及使用建议请参见索引参数

参数项

是否必填

配置说明

dim

定义对应向量的维度。

metric

定义建立索引时的度量方式。METRIC 参数可以不指定,默认值为 L2,您也可手动配置为 L2 或 COSINE。

m

定义乘积量化的子向量数量。常用取值为 64 或者 32,取值范围为 2 的 n 次方,范围介于 [1, std::min(dim, 64)]。

nbit

定义每个子向量的量化位数。默认值 8,通常无需修改,取值为偶数,通常范围为 [1, 16]。

nlist

定义 IVF 类型索引需要的聚类中心数量,数量越多,构建越慢, 如果不设置引擎会自动推算。

GRANULARITY

定义索引粒度,表示每 1 个数据块(mark)构建一次索引。

IVF_PQ_FS 索引

IVF_PQ_FS 索引是 IVF_PQ 的增强版,增加了快速搜索(Fast Scan)和 Refine 功能,能够在保持压缩优势的同时提升检索精度,适合需要高精度检索的大规模向量数据。

CREATE TABLE tab_ivf_pq_fs
(
    id Int32, 
    vector Array(Float32), 
    INDEX faiss_index vector TYPE IVF_PQ_FS('dim=4','m=4') GRANULARITY 1
) 
ENGINE = MergeTree 
ORDER BY id 
SETTINGS index_granularity = 128

IVF_PQ_FS 索引支持配置的索引参数说明如下。全量索引参数表及使用建议请参见索引参数

参数项

是否必填

配置说明

dim

定义对应向量的维度。

metric

定义建立索引时的度量方式。METRIC 参数可以不指定,默认值为 L2,您也可手动配置为 L2 或 COSINE。

m

定义乘积量化的子向量数量。常用取值为 64 或者 32,取值范围为 2 的 n 次方,范围介于 [1, std::min(dim, 64)]。

refine

定义精排阶段所采用的量化方法,默认使用 RFlat,准确度最高,还可以使用 SQ4、SQ6、SQ8、SQfp16 等标量量化方法。准确度排序为 RFlat>SQfp16>SQ8>SQ6>SQ4,内存资源使用也从多到少。以下为使用 SQ8 的示例:

CREATE TABLE tab_ivf_pq_fs_sq8
(
    id Int32,
    vector Array(Float32),
    INDEX faiss_index vector TYPE IVF_PQ_FS('dim=4','m=2', 'refine=SQ8') GRANULARITY 1
)
ENGINE = MergeTree
ORDER BY id
SETTINGS index_granularity = 128

nlist

定义 IVF 类型索引需要的聚类中心数量,数量越多,构建越慢, 如果不设置引擎会自动推算。

GRANULARITY

定义索引粒度,表示每 1 个数据块(mark)构建一次索引。

查询语法

您可使用基础查询语句检索数据,也可通过设置 settings 参数,提升准确率。
此外,ByteHouse 还支持支持添加 prewhere 语句添加预过滤条件,详情请参见混合查询;也支持添加 where 语句用于过滤搜索结果,通过相似度阈值筛选符合条件的记录,详情请参见Distance 过滤

基本查询

SELECT *, d
FROM xxx.yyy
ORDER BY L2Distance(vector, [...]) as d limit 3 
settings 
enable_new_ann=1;

参数项

是否必填

配置说明

SELECT *, d

定义查询的范围。该示例表示返回表中的所有原始字段,以及向量间距离计算结果 d

  • d:该值来自 ORDER BYL2Distance(vector, [...]) as d 的计算结果,表示 vector 字段和查询向量([...])间的欧氏距离**,**用于排序和结果展示。

FROM xxx.yyy

定义需要查询的数据库名和表名。

ORDER BY L2Distance(vector, [...]) as d limit 3

定义查询结果的排序方式。
该示例表示按照向量距离计算结果 d 升序排列,并取前 3 条记录,即距离最近的 3 个向量。

  • L2Distance(vector, [...]):定义需要查询的两个向量,计算 vector 字段和查询向量([...]) 间的欧氏距离(L2 范数)。
  • as d:将向量距离结果重命名为 d,方便查看结果。
  • limit:定义限制返回的记录数。该示例表示返回距离最小的前 3 条记录,即最相似的 3 个向量。

settings

设置 settings 参数。

  • enable_new_ann:需设置为 1 ,表示启用新实现的 ANN 查询路径。

ByteHouse 支持配置的全量 settings 参数列表请参见Settings 参数

使用 settings 参数调优查询

您可以使用 nprobek_factor_rf 参数为 IVF_FLAT、IVF_PQ 和 IVF_PQ_FS 索引调优查询,以提升查询准确率。ByteHouse 支持配置的全量 settings 参数列表请参见Settings 参数

IVF_FLAT 和 IVF_PQ 索引调优

IVF_FLAT 和 IVF_PQ 索引支持设置 nprobe 参数。nprobe 参数指定检索时要访问的 IVF 聚类中心数量。默认是 1,值越大,准确率越好,但性能越差,查询速度越低。取值为 2 的 n 次方,例如 32、64,范围介于 [1, std::min(nlist/2, 查询里的 top n)]。

SELECT *, d
FROM xxx.yyy
ORDER BY L2Distance(vector, [...]) as d limit 3 
settings 
enable_new_ann=1, nprobe=256;

IVF_PQ_FS 索引调优

IVF_PQ_FS 索引支持设置 nprobek_factor_rf 参数。k_factor_rf 参数可用于控制精排时的候选集扩展倍数,初步检索返回 k 个结果后,将候选集扩大 k_factor_rf 倍(即 k×32),对扩展后的候选集重新计算精确距离,选出最终的 k 个结果。

SELECT *, d
FROM xxx.yyy
ORDER BY L2Distance(vector, [...]) as d limit 3 
settings 
enable_new_ann=1, nprobe=256, k_factor_rf=32;

相关参考:调优参数配置

Distance 过滤

ByteHouse 优化了 where dist < max_score 以及 where dist > min_score 这类单一过滤条件查询,用于过滤搜索结果,通过相似度阈值筛选符合条件的记录。语法示例如下:

select id, dist 
from test_ann 
where dist < 0.9 
order by cosineDistance(embedding_column, [query_vector]) as dist
limit 100

Settings 参数

您可以使用以下 settings 参数优化向量检索查询语句。如果您通过 user.xml 文件中配置,则该参数将在全局生效;如果您通过 SQL 语句中配置,则该参数仅对当前语句生效。

参数

说明

配置方式

默认值

使用建议

index_granularity

表示索引粒度,即索引中每个标记(mark)对应的行数。设置该参数可以缓解读放大问题,提高查询性能。

在建表语句中设置。

8192

控制每个 Mark 包含的行数,调小可降低读放大,提升向量过滤精度。建议设置为 128。

index_granularity_bytes

表示索引粒度的字节数,当设置为 0 时,会避免生成 adaptive mark,使得索引标记的生成仅基于行数,而不是基于数据的字节数。

在建表语句中设置。

10485760(约10 MiB)

禁用 Adaptive Mark,固定 Mark 大小,减少 Mark 定位计算开销。建议设置为 0。

enable_vector_index_preload

Table level preload 开关。

在建表语句中设置。

0

写入加速。写入后的 part 的向量索引直接进入缓存,消除缓存加载时间。

enable_new_ann

是否使用新的 ANN 执行路径。

在查询语句中设置。

0

设置为 1 开启。

hnsw_ef_s

基于 HNSW index 进行 search 时,使用的搜索参数,值越大,准确度越高。

在查询语句中设置。

10

Recall 90 以上场景,一般需要设置到 128 以上。

nprobe

使用 Faiss IVF 索引(IVF_FLAT、IVF_PQ、IVF_PQ_FS 索引)的搜索参数,表示搜索使用的聚类中心数量。理论上,nprobe 越大,准确度越大,延迟越高。

在查询语句中设置。

0 (默认为 0 表示未进行设置,index 中默认使用参数为 1)

Recall 90 以上场景,考虑设置到 nlist 的 1/4 以上。

k_factor_rf

使用 Faiss 包含 refine 的索引(IVF_PQ_FS 索引)时的搜索参数,k_factor_rf 越大,用于排序的结果越多,准确度越高,延迟越高。

在查询语句中设置。

0 (同上)

使用了 refine 的索引,在 recall 较低情况,可以尝试调大,可以先尝试设置为 100,视情况进行微调。

vector_index_build_threads

每个 part build threads 数量。

在插入(insert)语句中设置。

8

单个 part 的 build threads 控制,如果并发导入或者合并并发度较高,建议调小。

索引参数

参数

说明

适用索引

是否必填

默认值

DIM

定义索引对应向量的维度信息,必须与向量实际的维度一致。

HNSW、FLAT、IVF_FLAT、IVF_PQ、IVF_PQ_FS

960

METRIC

定义了建立索引时的度量方式。支持设置为 L2 或 COSINE。
需要说明的是,只有使用对应 metric 的 distance 函数,才能执行基于索引的查询链路。例如,如果索引中 metric 为 L2,后续查询需使用 L2Distance 函数进行查询才能使用对应索引,同理,metric 为 COSINE 时,需要使用 cosineDistance 函数进行查询。

HNSW、FLAT、IVF_FLAT、IVF_PQ、IVF_PQ_FS

L2

M

定义了 HNSW 图中每个节点的最大连接数(Max Connections)。M 值较大时(如设置为 32),可以提高搜索速度,但会增加内存占用。M 值较小时(如设置为 4-16),可以降低内存占用,但会降低召回率。

HNSW、IVF_PQ、IVF_PQ_FS

16

EF_CONSTRUCTION

定义了索引构建时的探索因子(Exploration Factor)。该值较大(如 512)时,搜索精度更好,但构建时间越长。该值较小(如 100)时,构建速度更快,但索引质量可能会降低。

HNSW

200

GRANULARITY

定义索引粒度,表示每 1 个数据块(mark)构建一次索引。

FLAT、IVF_FLAT、IVF_PQ、IVF_PQ_FS

nbit

定义每个子向量的量化位数。默认值 8,通常无需修改,取值为偶数,通常范围为 [1, 16]。

IVF_PQ

8

nlist

定义 IVF 类型索引需要的聚类中心数量,数量越多,构建越慢。如果不设置值,引擎会自动推算,逻辑如下,您可在建表时使用 nlist 参数指定每个 part 构建索引时 nlist 的上限。

static size_t decideIndexNlist(size_t n)
{
    if (n < ONE_MILLION)
        return std::min(int(n), int(4 * std::floor(std::sqrt(n))));
    else if (n >= ONE_MILLION && n < ONE_MILLION * 2)
        return 1024;
    else if (n >= ONE_MILLION * 2 && n < TEN_MILLION)
        return 4096;
    else if (n > TEN_MILLION)
        return 65536;
}

IVF_FLAT、IVF_PQ、IVF_PQ_FS

refine

定义精排阶段所采用的量化方法,可配置为 RFlat、SQ4、SQ6、SQ8、SQfp16 等标量量化方法。准确度排序为 RFlat>SQfp16>SQ8>SQ6>SQ4,内存资源使用也从多到少。

IVF_PQ_FS

RFlat