ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

踩了三年烟囱式架构的坑,我终于理解了向量数据库和融合存储到底香在哪

踩了三年烟囱式架构的坑,我终于理解了向量数据库和融合存储到底香在哪 文章目录先说个事儿我们到底为什么需要向量数据库烟囱式架构那些年我踩过的坑索引IVFFLAT和HNSW怎么选为什么说一体化不只是省一个组件兼容是对前人努力的尊重是确保业务平稳过渡的基石然而这仅仅是故事的起点说真的我干这行快八年了前前后后换过四家公司有互联网大厂也有传统企业但凡是要做AI相关的项目架构图画出来几乎一个模子刻出来的——关系型数据库存业务数据旁边竖一个专用向量数据库存embedding再搞个文档数据库塞非结构化内容有时候还得加个时序数据库处理监控指标。DBA运维着四五套不同的数据库开发在代码里写着五六个不同的driver数据在各个库之间搬来搬去ETL任务跑了一轮又一轮。每次出了问题排查链路能绕地球半圈。我之前一直觉得这就是AI时代该有的样子直到去年有个项目让我接触到了KingbaseES的向量能力才发现原来还能这么玩——一套数据库把关系、向量、文档、GIS、时序全给你装进去了。说实话刚听说的时候我是不信的觉得不就是在关系库里面加了个vector类型嘛能有多大花头结果越用越觉得之前三年的架构简直是在给自己挖坑。这篇文章我想跟你聊聊我这几年在烟囱式架构上踩的坑以及后来用KingbaseES一体化融合架构做项目的真实体验。先说个事儿我们到底为什么需要向量数据库我查过一些资料向量数据库这个领域的发展其实经历了好几个阶段。最早大概是1989年到2000年前后那时候的系统像Rasdaman主要是给地球科学、天文航天、石油勘探这些领域用的处理的是有序、密集的多维数据查询的时候还伴随各种科学计算算子。这一阶段的系统跟现在我们说的AI向量数据库基本不是一回事数据模型和查询模式差得很远。然后到了2000年到2017年左右出现了一批面向高维数据管理的系统比如SciDB——这可是Micheal Stonebraker老爷子搞的还有Samuel Madden牵头的Tile项目。这一阶段的研究重点转向了图像、视频、点云这类高维数据的存储和索引Tile还专门做了面向稀疏向量优化的存储和索引结构。但老实说这些系统在学术圈挺有名在工业界真正大规模用起来的并不多。原因嘛我觉得一方面是当时的应用场景确实有限另一方面这些系统的产品化程度普遍不高你让企业拿来跑核心业务心里没底。真正的转折点是2017年前后。那一年Milvus开源了紧接着Pinecone在2019年推出了云服务。从那以后向量数据库这个赛道突然就热了起来。为什么因为大模型和embedding技术起来了。以前向量主要是学术界在玩现在任何一个做AI应用的团队都需要把文本、图片、音频转成向量存起来做相似度检索需求一下子就爆发了。不过这里我想插一句自己的看法。现在市面上很多讨论把向量数据库和专用向量数据库画等号好像你要存向量就必须用Milvus、Pinecone、Weaviate这些。这个假设其实是有问题的。向量检索本质上是一个数据类型加一个索引方法的问题关系型数据库完全可以通过扩展来支持不一定非得另起炉灶搞一套独立系统。KingbaseES走的就是这条路子——在KES之上做向量功能增强以插件形式提供能力。这个选择到底好不好我后面会结合实际体验详细说。还有一个概念上的复杂性我觉得值得提一下。什么叫向量数据库业界其实有好几种界定方式。最窄的定义是专门用于存储和检索高维向量数据的数据库系统Milvus、Pinecone属于这一类。稍微宽一点的定义是支持向量数据类型和向量相似度检索的数据库按照这个定义KingbaseES加了向量组件之后也算。最宽泛的定义则把任何能存向量的系统都算进去包括Elasticsearch带个dense_vector字段这种。我个人倾向于第二种界定因为第一种把那些在关系库基础上做向量扩展的路线排除在外了而这条路线恰恰可能是企业落地AI时最务实的选择。烟囱式架构那些年我踩过的坑第一个坑是ETL。业务方有个需求要在问答结果里展示文档的创建部门、文档密级这些信息。这些信息在MySQL里但相似度检索是在Milvus里做的。流程变成了先去Milvus检索出最相似的top10向量拿到对应的chunk_id和doc_id然后拿着doc_id去MySQL查部门和密级信息再根据当前用户的权限过滤掉无权查看的文档。这就导致一个很尴尬的问题Milvus返回的top10里可能有5条用户是没权限看的你过滤掉之后只剩5条上下文不够回答质量就下降。你说可以在Milvus里存权限信息做预过滤行啊但权限是会变的今天用户能看的文档明天可能就被收回权限了。你怎么同步又回到数据一致性的问题了。更麻烦的是权限过滤条件可能很复杂——部门、角色、密级、文档归属人这些条件组合起来你很难在向量检索阶段高效处理。专用向量数据库虽然也支持标量过滤但能力跟关系型数据库的WHERE子句比起来差了不是一点半点。第二个坑是运维。四套数据库四套监控四套备份策略四个升级版本节奏。Milvus那套东西依赖etcd、MinIO、Pulsar光本地开发环境搭起来就要半天。有一次测试环境的etcd挂了Milvus整个不可用我折腾了一下午才恢复。DBA同事本来只管MySQL现在还得学Milvus的运维苦不堪言。第三个坑是事务。这个其实最致命但也最容易被忽视。在专用向量数据库里向量的写入和查询是没有ACID事务保证的。我给你看个最直观的例子。假设你有一个企业文档检索系统在烟囱式架构下你要先在Milvus里做向量相似度检索拿到doc_id列表然后去MySQL里查这些文档的元数据和权限再去MongoDB里拿文档内容。三步三个数据库三次网络往返。代码大概长这样# 烟囱式架构三步查询三个数据库# 第一步Milvus向量检索resultsmilvus_client.search(collection_namedoc_vectors,data[query_vector],limit20,output_fields[doc_id,chunk_id])doc_ids[r[entity][doc_id]forrinresults[0]]# 第二步MySQL查元数据和权限placeholders,.join([%s]*len(doc_ids))cursor.execute(f SELECT d.id, d.title, d.department, d.security_level FROM documents d WHERE d.id IN ({placeholders}) AND d.department IN ({user_dept_list}) AND d.security_level %s ,doc_ids[user_clearance])allowed_docs{row[id]:rowforrowincursor.fetchall()}# 第三步MongoDB拿文档内容contentsmongo_client.docs.find({_id:{$in:list(allowed_docs.keys())}},{content:1,title:1})看着不多对吧但实际项目中这三步之间的错误处理、重试逻辑、数据不一致处理能写出几百行代码。而且这三步是串行的每一步的延迟都会叠加。换成KingbaseES一体化架构之后一条SQL就搞定了-- 融合架构一条SQL搞定向量检索权限过滤文档内容SELECTd.id,d.title,d.department,d.content,v.chunk_text,1-(v.embedding:query_vector)ASsimilarityFROMdoc_vectors vJOINdocuments dONv.doc_idd.idWHEREd.departmentANY(:user_depts)ANDd.security_level:user_clearanceANDv.embedding:query_vector0.3ORDERBYv.embedding:query_vectorLIMIT10;索引IVFFLAT和HNSW怎么选IVFFLAT的原理是先把向量空间分成若干个聚类簇用k-means检索的时候只查离查询向量最近的几个簇。它的特点是索引构建快内存占用小但查询速度和准确率取决于你检查多少个簇——查得多准确率高但慢查得少快但可能漏。HNSW则是基于图的方法构建一个多层的近邻图检索时从顶层开始贪心搜索逐层向下找到最相近的节点。它在高维空间里通常比IVFFLAT更快、准确率更高代价是内存占用更大、索引构建更慢。创建索引的语法-- IVFFLAT索引lists是聚类数量CREATEINDEXONdocument_chunksUSINGivfflat(embedding vector_cosine_ops)WITH(lists100);-- HNSW索引m是每层连接数ef_construction是构建时搜索宽度CREATEINDEXONdocument_chunksUSINGhnsw(embedding vector_cosine_ops)WITH(m16,ef_construction64);实际选择的时候我一般这么判断如果数据量在百万级以下内存也够直接上HNSW体验最好。如果数据量特别大或者内存紧张IVFFLAT更稳妥。不过有个坑要注意IVFFLAT索引需要先有数据才能建——因为它需要数据来训练聚类中心。空表建IVFFLAT索引会报错或者效果很差。HNSW则没有这个问题。查询的时候你可以通过参数控制召回率和速度的平衡-- HNSW查询ef_search越大召回越高但越慢SEThnsw.ef_search100;SELECTid,chunk_text,embedding[0.1,0.2,...]ASdistanceFROMdocument_chunksORDERBYembedding[0.1,0.2,...]LIMIT10;-- IVFFLAT查询probes是检查的簇数SETivfflat.probes10;SELECTid,chunk_text,embedding[0.1,0.2,...]ASdistanceFROMdocument_chunksORDERBYembedding[0.1,0.2,...]LIMIT10;我做过一些对比测试在百万级1024维向量、top10查询的场景下HNSW的P99延迟大概在5毫秒左右IVFFLAT在probes设为10的时候大概15毫秒。如果把probes降到1IVFFLAT也能跑到3毫秒但召回率直接掉到60%以下。所以大部分情况下我更推荐HNSW。还有一个功能我觉得特别实用表达式索引也就是函数索引。你可以只对向量的某一部分建索引-- 对向量的前256维建索引CREATEINDEXONdocument_chunksUSINGhnsw((embedding[1:256])vector_cosine_ops);这在什么场景下有用呢比如你的embedding前半段是文本语义向量后半段是元数据编码你想只按语义部分做检索这时候子向量索引就派上用场了。为什么说一体化不只是省一个组件聊到这儿你可能觉得一体化的好处不就是少维护一套数据库嘛。我一开始也是这么想的但用深了之后发现好处远不止于此。首先是事务。因为向量数据存在KES里面它天然继承了KES的ACID事务能力。你可以在一个事务里同时写入业务数据和向量数据要么一起成功要么一起回滚BEGIN;-- 写入文档元数据INSERTINTOdocuments(title,department,security_level,content)VALUES(Q3财务报告,财务部,3,...)RETURNINGidINTOdoc_id;-- 写入文档切片和向量INSERTINTOdocument_chunks(doc_id,chunk_index,chunk_text,embedding)VALUES(doc_id,0,第一部分...,[0.1,0.2,...]),(doc_id,1,第二部分...,[0.3,0.4,...]),(doc_id,2,第三部分...,[0.5,0.6,...]);COMMIT;这在专用向量数据库里是做不到的。你的向量写入和关系数据写入之间没有事务保证一旦中间出了问题就得靠补偿逻辑来修。在金融、医疗这些对数据一致性敏感的场景ACID事务不是锦上添花是硬性要求。其次是混合查询能力。我前面给的那个例子已经展示了向量和关系数据的JOIN但这还不是全部。KES支持向量与关系数据、文档数据、GIS数据、时序数据的混合检索。比如你可以在一条SQL里同时做向量相似度检索、GIS范围查询、时间范围过滤-- 多模融合查询找最近的、语义相似的、特定时间段的事故报告SELECTa.id,a.location,a.accident_time,a.description,a.geo_point-ST_MakePoint(116.4,39.9)ASgeo_distance,a.feature_vector:query_vecASsemantic_distanceFROMaccident_reports aWHEREa.accident_timeNOW()-INTERVAL30 daysANDST_DWithin(a.geo_point,ST_MakePoint(116.4,39.9),5000)ANDa.feature_vector:query_vec0.25ORDERBYsemantic_distanceLIMIT20;这些在专用向量数据库里你得自己在应用层实现不仅开发量大而且很容易出安全漏洞。还有是高可用。KES从实例级、集群级到中心级都有完整的高可用方案。实例级有备份恢复、闪回集群级有物理日志全同步复制、故障秒级切换、脑裂防护中心级有同城双中心全同步、异地灾备。你的向量数据跟着KES一起享受这些能力不用单独给向量数据库搭一套HA方案。我之前用Milvus的时候HA方案依赖K8s和etcd运维复杂度很高。有一次etcd出了问题导致Milvus集群脑裂两个节点都认为自己是leader数据写了两份排查了很久。KES用增强型一致性协议选主从机制上避免脑裂省心多了。最后是兼容性。KES支持多种异构数据库的原生协议兼容——你可以用MySQL的客户端驱动直接连KES也可以用Oracle的API。这意味着如果你的应用之前是跑在MySQL上的要加上向量能力基本不用改连接方式和数据访问层代码。有问题或者不同意见的欢迎在评论区聊聊。
返回列表