
说真的,我干这行快八年了,前前后后换过四家公司,有互联网大厂也有传统企业,但凡是要做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向量检索
results = milvus_client.search(
collection_name="doc_vectors",
data=[query_vector],
limit=20,
output_fields=["doc_id", "chunk_id"]
)
doc_ids = [r["entity"]["doc_id"] for r in results[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"]: row for row in cursor.fetchall()}
# 第三步:MongoDB拿文档内容
contents = mongo_client.docs.find(
{"_id": {"$in": list(allowed_docs.keys())}},
{"content": 1, "title": 1}
)
看着不多对吧?但实际项目中,这三步之间的错误处理、重试逻辑、数据不一致处理,能写出几百行代码。而且这三步是串行的,每一步的延迟都会叠加。
换成KingbaseES一体化架构之后,一条SQL就搞定了:
-- 融合架构:一条SQL搞定向量检索+权限过滤+文档内容
SELECT
d.id,
d.title,
d.department,
d.content,
v.chunk_text,
1 - (v.embedding <=> :query_vector) AS similarity
FROM doc_vectors v
JOIN documents d ON v.doc_id = d.id
WHERE d.department = ANY(:user_depts)
AND d.security_level <= :user_clearance
AND v.embedding <=> :query_vector < 0.3
ORDER BY v.embedding <=> :query_vector
LIMIT 10;
索引:IVFFLAT和HNSW怎么选
IVFFLAT的原理是先把向量空间分成若干个聚类簇(用k-means),检索的时候只查离查询向量最近的几个簇。它的特点是索引构建快,内存占用小,但查询速度和准确率取决于你检查多少个簇——查得多准确率高但慢,查得少快但可能漏。
HNSW则是基于图的方法,构建一个多层的近邻图,检索时从顶层开始贪心搜索,逐层向下找到最相近的节点。它在高维空间里通常比IVFFLAT更快、准确率更高,代价是内存占用更大、索引构建更慢。
创建索引的语法:
-- IVFFLAT索引,lists是聚类数量
CREATE INDEX ON document_chunks
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
-- HNSW索引,m是每层连接数,ef_construction是构建时搜索宽度
CREATE INDEX ON document_chunks
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
实际选择的时候,我一般这么判断:如果数据量在百万级以下,内存也够,直接上HNSW,体验最好。如果数据量特别大或者内存紧张,IVFFLAT更稳妥。不过有个坑要注意:IVFFLAT索引需要先有数据才能建——因为它需要数据来训练聚类中心。空表建IVFFLAT索引会报错或者效果很差。HNSW则没有这个问题。
查询的时候,你可以通过参数控制召回率和速度的平衡:
-- HNSW查询:ef_search越大召回越高但越慢
SET hnsw.ef_search = 100;
SELECT id, chunk_text, embedding <=> '[0.1,0.2,...]' AS distance
FROM document_chunks
ORDER BY embedding <=> '[0.1,0.2,...]'
LIMIT 10;
-- IVFFLAT查询:probes是检查的簇数
SET ivfflat.probes = 10;
SELECT id, chunk_text, embedding <=> '[0.1,0.2,...]' AS distance
FROM document_chunks
ORDER BY embedding <=> '[0.1,0.2,...]'
LIMIT 10;
我做过一些对比测试,在百万级1024维向量、top10查询的场景下,HNSW的P99延迟大概在5毫秒左右,IVFFLAT在probes设为10的时候大概15毫秒。如果把probes降到1,IVFFLAT也能跑到3毫秒,但召回率直接掉到60%以下。所以大部分情况下我更推荐HNSW。
还有一个功能我觉得特别实用:表达式索引(也就是函数索引)。你可以只对向量的某一部分建索引:
-- 对向量的前256维建索引
CREATE INDEX ON document_chunks
USING hnsw ((embedding[1:256]) vector_cosine_ops);
这在什么场景下有用呢?比如你的embedding前半段是文本语义向量,后半段是元数据编码,你想只按语义部分做检索,这时候子向量索引就派上用场了。
为什么说一体化不只是"省一个组件"
聊到这儿你可能觉得,一体化的好处不就是少维护一套数据库嘛。我一开始也是这么想的,但用深了之后发现,好处远不止于此。
首先是事务。因为向量数据存在KES里面,它天然继承了KES的ACID事务能力。你可以在一个事务里同时写入业务数据和向量数据,要么一起成功要么一起回滚:
BEGIN;
-- 写入文档元数据
INSERT INTO documents (title, department, security_level, content)
VALUES ('Q3财务报告', '财务部', 3, '...')
RETURNING id INTO doc_id;
-- 写入文档切片和向量
INSERT INTO document_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范围查询、时间范围过滤:
-- 多模融合查询:找最近的、语义相似的、特定时间段的事故报告
SELECT
a.id,
a.location,
a.accident_time,
a.description,
a.geo_point <-> ST_MakePoint(116.4, 39.9) AS geo_distance,
a.feature_vector <=> :query_vec AS semantic_distance
FROM accident_reports a
WHERE a.accident_time >= NOW() - INTERVAL '30 days'
AND ST_DWithin(a.geo_point, ST_MakePoint(116.4, 39.9), 5000)
AND a.feature_vector <=> :query_vec < 0.25
ORDER BY semantic_distance
LIMIT 20;
这些在专用向量数据库里你得自己在应用层实现,不仅开发量大,而且很容易出安全漏洞。
还有是高可用。KES从实例级、集群级到中心级都有完整的高可用方案。实例级有备份恢复、闪回;集群级有物理日志全同步复制、故障秒级切换、脑裂防护;中心级有同城双中心全同步、异地灾备。你的向量数据跟着KES一起享受这些能力,不用单独给向量数据库搭一套HA方案。
我之前用Milvus的时候,HA方案依赖K8s和etcd,运维复杂度很高。有一次etcd出了问题导致Milvus集群脑裂,两个节点都认为自己是leader,数据写了两份,排查了很久。KES用增强型一致性协议选主,从机制上避免脑裂,省心多了。
最后是兼容性。KES支持多种异构数据库的原生协议兼容——你可以用MySQL的客户端驱动直接连KES,也可以用Oracle的API。这意味着如果你的应用之前是跑在MySQL上的,要加上向量能力,基本不用改连接方式和数据访问层代码。
有问题或者不同意见的,欢迎在评论区聊聊。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/qq_32682301/article/details/164006653




