向量数据库落地实践

admin 2025-01-31 208人围观 ,发现204个评论
一、前言

本文基于京东内部向量数据库vearch进行实践。Vearch是对大规模深度学习向量进行高性能相似搜索的弹性分布式系统。详见:

二、探索

初次认识向量数据库,一脸懵逼?


向量是什么?如何将文本转换为向量?如何确定维度?如何定义表结构?如何选择索引方式,建表参数如何配置?检索参数如何配置?分片数副本数如何选择等等

随着对文档的逐渐熟悉以及和vearch相关同事的沟通,以上问题迎刃而解,具体的不再赘述。主要记住以下几点:

1、文本转向量:采用大模型网关接口domain/embeddings传入对应的模型如:text-embedding-ada-002-2和待转换的文本即可;

3、建表参数的选择以及表结构:主要在于retrieval_type检索模型的选择,具体的可以参考文档。经过综合考虑,决定采用HNSW:

字段标识

字段含义

类型

是否必填

备注

metric_type

计算方式

string

L2或者InnerProduct

nlinks

节点邻居数量

int

默认32

efConstruction

构图时寻找节点邻居过程中在图中遍历的深度

int

默认40

"retrieval_type":"HNSW","retrieval_param":{"metric_type":"InnerProduct","nlinks":32,"efConstruction":40}注意:1、向量存储只支持MemoryOnly2、创建索引不需要训练,index_size值大于0均可

具体的建表示例见后文。

4、分片数和副本数结合实际数据量评估,如果无法评估,按照最少资源申请即可,后续可扩展。

三、实践1、建表(space)

为了简化操作,实行db(库)-space(表)一对一的方案,弱化库的概念。经过一系列探索之后定义出了通用的space结构:

{"name":"demphah","partition_num":3,"replica_num":3,"engine":{"name":"gamma","index_size":1,"id_type":"String","retrieval_type":"HNSW","retrieval_param":{"metric_type":"InnerProduct","nlinks":32,"efConstruction":100,"efSearch":64}},"properties":{"vectorVal":{"type":"vector","dimension":1536},"contentVal":{"type":"string"},"chunkFlagId":{"type":"string","index":true},"chunkIndexId":{"type":"integer","index":true}}}

字段说明:

engine、partition_num等都是固定的参数,properties中所列字段皆为通用字段,如果有扩展字段如:skuId,storeId追加即可

字段名

含义

类型

说明

vectorVal

文本向量

vector

维度与选用模型有关

contentVal

源文本

string

chunkFlagId

文件唯一id

string

文件的标识id,用于串联分块后的片段

chunkIndexId

文件分段位置

integer

从0开始,递增

skuId

扩展字段见上

这里file的概念可以理解为一个单元,可能是一个文件,也可能是一个url,总之就是一个数据整体。

2、分段写入

这里针对通用文件描述,比如提供一个pdf文件如何导入向量库:

a.首先上传文件到oss,然后根据对应的fileKey获取到文件数据流

b.再根据各种拆分场景(按行、字节数、正则拆分等)分成片段

c.分段写入向量库:

/***将字符串转换为向量并插入数据库*p*目前所有的知识库管理端写入全走这个方法**@paramdbName数据库名称*@paramspaceName空间名称*@paramstr字符串*@paramflagId标志ID*@paramchunkIndexId块索引ID*@paramproperties属性*/privatevoidembeddingsAndInsert(StringdbName,StringspaceName,Stringstr,StringflagId,IntegerchunkIndexId,MapString,Objectproperties){//先向数据库写入一条记录,记录当前文档的写入操作intsuccess=(spaceName,flagId,(),0,str);if(success=0){("writeDocRecord失败{},{},{}",spaceName,flagId,chunkIndexId);}//分块转向量并写入ListFloatembeddings=(str);if((embeddings)){return;}KnBaseVecDtoknBaseVecDto=buildKnBaseVecDto(newFeaVector(embeddings),flagId,chunkIndexId,str);MapString,ObjectnewPros=(knBaseVecDto);if((properties)){(properties);}//{"_index":"kn_base_file_db","_type":"kn_base_file_space","_id":"-81244911","status":200}Stringinsert=(dbName,spaceName,null,newPros);if((insert)||!("_index")){("写入失败的块:{},{}",chunkIndexId,insert);}}
3、数据记录

上文写知识库的过程有个的逻辑,用于记录写入的片段。下文详细介绍其中用到的mysql表:

1、表1space记录表

注:主要用于记录创建的space,以及查询管控,如禁用某个space等

CREATETABLE`xxx_vearch_spaces`(`id`bigint(20)unsignedNOTNULLAUTO_INCREMENTCOMMENT'自增主键',`type`tinyint(3)NOTNULLCOMMENT'类型',`status`tinyint(3)NOTNULLCOMMENT'状态',`space`varchar(127)NOTNULLCOMMENT'空间标识',`db`varchar(127)NOTNULLCOMMENT'库标识',`desc`varchar(127)NOTNULLCOMMENT'空间描述',`ext`varchar(4095)NOTNULLDEFAULT''COMMENT'扩展字段',`creator`varchar(127)NOTNULLDEFAULT''COMMENT'创建人',`created`timestampNOTNULLCOMMENT'创建时间',`modifier`varchar(127)NOTNULLDEFAULT''COMMENT'修改人',`modified`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'修改时间',`deleted`tinyint(3)NOTNULLDEFAULT'0'COMMENT'已删除(0:否;1:是)',PRIMARYKEY(`id`)USINGBTREE,UNIQUEKEY`uniq_space_db`(`space`,`db`)USINGBTREE)ENGINE=InnoDBAUTO_INCREMENT=0DEFAULTCHARSET=utf8mb4COMMENT='xxx向量空间'

2、表2file记录表

注:主要用于记录space下的file,以及查询管控,如禁用某个file,以及关联查询对应的全部片段。

CREATETABLE`xxx_spaces_knbase`(`id`bigint(20)unsignedNOTNULLAUTO_INCREMENTCOMMENT'自增主键',`status`tinyint(3)NOTNULLCOMMENT'状态',`space`varchar(127)NOTNULLCOMMENT'空间标识',`file_name`varchar(255)NOTNULLCOMMENT'文件名',`file_desc`varchar(511)NOTNULLCOMMENT'文件描述',`byte_num`bigint(20)unsignedNOTNULLCOMMENT'字符数',`hit_count`int(10)unsignedNOTNULLCOMMENT'命中次数',`ext`varchar(4095)NOTNULLDEFAULT''COMMENT'扩展字段',`creator`varchar(127)NOTNULLDEFAULT''COMMENT'创建人',`created`timestampNOTNULLCOMMENT'创建时间',`modifier`varchar(127)NOTNULLDEFAULT''COMMENT'修改人',`modified`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'修改时间',`deleted`tinyint(3)NOTNULLDEFAULT'0'COMMENT'已删除(0:否;1:是)',`file_flag_id`varchar(255)DEFAULTNULLCOMMENT'文件唯一标识',PRIMARYKEY(`id`)USINGBTREE,KEY`idx_space`(`space`)USINGBTREE)ENGINE=InnoDBAUTO_INCREMENT=0DEFAULTCHARSET=utf8mb4COMMENT='xxx空间知识库'

3、表3paragraph记录表

注:主要用于记录file拆分的片段,包括当前位置,查询命中数等。

CREATETABLE`xxx_knbase_doc_record`(`id`bigint(20)unsignedNOTNULLAUTO_INCREMENTCOMMENT'自增主键',`space`varchar(127)NOTNULLCOMMENT'空间标识',`file_flag_id`varchar(255)NOTNULLCOMMENT'文件标识',`d_index`bigint(20)unsignedNOTNULLCOMMENT'文档位置',`hit_count`int(10)unsignedNOTNULLCOMMENT'命中次数',`ext`varchar(4095)NOTNULLDEFAULT''COMMENT'扩展字段',`creator`varchar(127)NOTNULLDEFAULT''COMMENT'创建人',`created`timestampNOTNULLCOMMENT'创建时间',`modifier`varchar(127)NOTNULLDEFAULT''COMMENT'修改人',`modified`timestampNOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'修改时间',`deleted`tinyint(3)NOTNULLDEFAULT'0'COMMENT'已删除(0:否;1:是)',PRIMARYKEY(`id`)USINGBTREE,UNIQUEKEY`uniq_space_file_idx`(`space`,`file_flag_id`,`d_index`)USINGBTREE)ENGINE=InnoDBAUTO_INCREMENT=0DEFAULTCHARSET=utf8mb4COMMENT='xxx知识文档记录'
四、总结

向量数据库对于大模型应用落地来说至关重要,有些不可外露的内部数据可以存储在向量库中,用于内部检索。随着向量库中数据的丰富,大模型推理回答的能力也将更加精准。

上文的设计比如space中的chunkFlagId可以关联出原始的整个文件;chunkIndexId可以控制数据的查询范围,另一方面可以通过此字段实现分页(vearch目前不支持分页查询)以及全文导出。xxx_knbase_doc_record表中记录了片段的记录,可用于计算片段的chunkIndexId,一方面避免重复,另一方面保证属性的递增,可用于扩展很多能力。

目前向量数据库的检索只支持基本的向量检索和关键字检索,后续会逐步优化混合检索等方案以提高检索准确率等。

猜你喜欢
    不容错过