最近更新时间:2024-11-26 19:57:04
在 RAG 中,数据集(Collection)是用户管理和组织信息的基本单元,每个数据集可以包含多种类型的数据,如论文、Excel、PPT 等。这种灵活性使得用户能够根据自己的需求对数据进行归类和整理。每次用户的一次chat,都会关联一个或多个数据集进行 RAG 查询。这种查询方式能够根据用户的问题,从相关的数据集中检索出答案,提高了查询的准确性和效率。
Chunk是指从源文件中提取出的较小的数据片段或文本块。这些块通常是经过特定处理后得到,旨在提高信息检索和处理的效率。一个源文件(例如 PDF 论文)可以被划分为多个 Chunk,每个 Chunk 包含一定数量的文本或信息。
对于数据集内的每个源文件(以 PDF 论文为例),其每个源文件被输入到处理系统中时,会经过多个处理管道(Pipeline),负责对源文件进行不同的处理步骤,包括:
文本提取:从 PDF 中提取文本内容,去除格式和冗余信息。
分块处理:将提取的文本划分为多个 Chunk,通常基于段落、句子或固定字数等标准。
语义嵌入生成:为每个 Chunk 生成相应的语义 Embedding。这些 Embedding 是通过深度学习模型(如 BERT 或其他自然语言处理模型)计算得出,能够捕捉 Chunk的语义信息。
当用户对某个 Collection 发起 Chat 时,作为一个 RAG 召回系统,目标是从当前 Collection 对应的所有 Chunk中召回相关信息。这个过程通常包括如下步骤:
Query embedding:调用模型,对用户 Query 文本进行 Embedding,产出 Query 向量。
向量召回:Query 向量与 Chunk Embedding 向量进行近似计算,从数据库中检索出多个相关 Chunk。这些 Chunk 是与用户查询最相关的文本片段,可能来自于多个源文件,但都属于同一个数据集。
重排序:系统对召回的 Chunk 进行重排序,以确定哪些 Chunk 最能满足用户的查询需求。重排序通常基于 Chunk 的相关性、质量和其它因素进行评估。
作为问题上下文:经过重排序后,选定的 Chunk 将作为问题上下文(Question Context)返回给用户。这些上下文信息将帮助用户更好地理解查询结果,并提供更准确的答案。
字段名 | 含义 | 字段类型 |
| 唯一表示一个数据集的 ID。可以是用户数据集,也可能是公开数据集。 |
|
| 唯一表示数据集内的一条记录。 |
|
| 每个源文件(例如 PDF 文件)对应的 ID。 |
|
| 原始文本,用于作为 Context 返回给 LLM。 |
|
| 文本的 Dense Embedding 向量,与 Text 一一对应,包含了文本经过模型 Embed 后生成的语义信息,用于语义匹配。 |
|
| 文本的 Sparse Embedding 向量,与 Text 一一对应,包含了文本的关键词信息和权重,用于关键词匹配。 |
|
| 该 Chunk 的 Metadata 信息,包含作者、来源、引用等。 |
|
| 该条记录对应的原文类型,可能是 Chunk、Summary 等,从 |
|
| 该条记录对应的索引类型,从 |
|
在设计表 Schema 时,如何有效地管理和查询不同数量的数据集是一个重要的考虑因素。为了在表的数量和查询性能之间取得平衡,选择以用户的数据集 ID (collection_id
) 作为分区键(partition by range(collection_id)
)。其中,collection_id
以日期为前缀,保证按时间有序。这种设计策略能够有效地应对用户私有数据集和平台公开数据集的数量差异,同时保证高效的查询性能。
以带时间前缀的 collection_id
作为分区键具有以下几个优点:
自然的时间序列性:由于collection_id
按时间有序,使用它作为分区键可以确保数据按照访问的冷热特性存放 layout,实现冷热数据分离的效果。
避免元数据膨胀:相比最朴素的做法——为每个用户私有数据创建一个独立的表,随着用户数量和数据集数量的增加,系统元数据将迅速膨胀,导致管理和维护的复杂性增加,影响整体系统性能表现。因此使用单一大表并通过 collection_id
进行分区,可以有效减少表的数量,简化数据库结构。
便于针对特殊数据集做定制:当有特殊的数据集需要定制时,比如希望与其它数据集隔离,或者单独定制索引策略时,仅需要增加一个子分区表达式即可,不需要业务重新建表做路由。
以日期为前缀的 collection_id
示例:
"20240803-clzqw6zd70iv501l1k9cmhb5p"
"20240804-clzqw6zd70iv501l1k9cmsfhw"
"20240805-clzqw6zd70iv501l1k9cmvert"
按月创建分区表的示例:
CREATE TABLE llama_index_vectors_1024_part_202407 partition of llama_index_vectors_1024 FOR VALUES FROM ('20240701') TO ('20240801');
CREATE TABLE llama_index_vectors_1024_part_202408 partition of llama_index_vectors_1024 FOR VALUES FROM ('20240801') TO ('20240901');
按日创建分区表的示例:
CREATE TABLE llama_index_vectors_1024_part_20240701 partition of llama_index_vectors_1024 FOR VALUES FROM ('20240701') TO ('20240702');
CREATE TABLE llama_index_vectors_1024_part_2024702 partition of llama_index_vectors_1024 FOR VALUES FROM ('20240702') TO ('20240703');
根据数据增量大小和访问 Pattern不同,建议采用按月或按日的分区策略,保证分区表数量与查询性能之间的平衡。
在实际使用中,大多数查询都会带上类似 collection_id = '20240803-xxx'
的等值条件,且每个为保证更好的 QPS(每个查询最会使用一个计算节点),我们选择使用 collection_id
作为分布列。这种设计的缺点是 RT 会受一些影响。
4.1 向量索引
对于 Embedding 向量字段 ,使⽤ HNSW 索引 ,在保证⾼召回率前提下实现毫秒级的查询延迟。
4.2 点查索引
对于 index_name
、text_type
等常⽤于 filter 的字段 ,构建 B-Tree ⼆级索引(collection_id
, index_name
),对于⾼筛选率的查询有⾮常好的加速效果。
5.1 创建主表
CREATE TABLE llama_index_vectors_1024
(
id text not null,
collection_id text not null, --以日期字符串为前缀,例: "20240803-clzqw6zd70iv501l1k9cmhb5p"
datasource_id text,
index_name text,
text_type text
text text,
embedding vecf16(1024),
sparse_embedding svector(30052),
meta jsonb,
primary key (collection_id, id)
)
DISTRIBUTED BY (collection_id)
PARTITION BY range(collection_id);
-- 设置为plain存储
ALTER TABLE llama_index_vectors_1024
ALTER COLUMN id set storage plain,
ALTER COLUMN collection_id set storage plain,
ALTER COLUMN index_name set storage plain,
ALTER COLUMN text_type set storage plain,
ALTER COLUMN embedding set storage plain,
ALTER COLUMN datasource_id set storage plain;
5.2 按月创建分区表
-- 按月建分区
CREATE TABLE llama_index_vectors_1024_part_202407 partition of llama_index_vectors_1024 FOR VALUES FROM ('20240701') TO ('20240801');
CREATE TABLE llama_index_vectors_1024_part_202408 partition of llama_index_vectors_1024 FOR VALUES FROM ('20240801') TO ('20240901');
-- 默认分区,当collection_id没有命中时间前缀的分区表,会路由到默认分区表
CREATE TABLE llama_index_vectors_1024_part_default partition of llama_index_vectors_1024 default;
5.3 向量索引
CREATE INDEX llama_index_vectors_1024_embedding on
llama_index_vectors_1024
USING vectors(embedding vecf16_cos_ops
WITH (options = $$
optimizing.optimizing_threads = 10
segment.max_growing_segment_size = 2000
segment.max_sealed_segment_size = 30000000
[indexing.hnsw]
m=30
ef_construction=500
$$);
5.4 点查索引
CREATE INDEX llama_index_vectors_1024_index_name on
llama_index_vectors_1024 using btree(collection_id, index_name);
CREATE INDEX llama_index_vectors_1024_text_type on
llama_index_vectors_1024 using btree(collection_id, text_type);
CREATE INDEX llama_index_vectors_1024_datasource_id on
llama_index_vectors_1024 using btree(collection_id, datasource_id);
CREATE INDEX llama_index_vectors_1024_meta on llama_index_vectors_1024
USING gin((collection_id::tsvector), meta);
SELECT id, text, meta,
embedding <-> '[0.1,0.3, ...., 0.6]' -- 1024维query向量数组
as distance
FROM llama_index_vectors_1024
WHERE collection_id = '20240803-clzqw6zd70iv501l1k9cmhb5p'
AND index_name = 'EMBEDDING'
ORDER BY distance --按点积距离排序 LIMIT 16
纯净模式
鼠标选中内容,快速反馈问题