2. 向量数据采集与预处理:数据源接入、清洗、标准化与分片
数据采集和预处理,说白了就是给向量数据库「喂饭」的过程。饭喂得好不好,直接决定了后面检索和分析的效率。我见过太多团队在模型和算法上花了大把精力,结果数据源接入那一步就埋了雷——格式不统一、脏数据满天飞、向量维度对不上……最后全白干。
这一章,咱们就把这些坑一个个填上。
2.1 数据源接入:文本、图像、多模态
向量数据库不像传统数据库只收结构化数据。它什么都能吃——文本、图片、音频、视频,甚至混合数据。但不同的数据源,接入方式和预处理逻辑完全不同。
2.1.1 文本数据接入
文本是最常见的向量数据源。我习惯把文本接入分成三个步骤:
- 原始文本提取:从 PDF、Word、HTML、数据库等来源抽取纯文本内容。
- 段落/句子切分:按长度或语义边界切分,避免单条数据过长或过短。
- 元数据绑定:保留来源、时间戳、作者等上下文信息。
关键点:文本切分的粒度直接影响向量检索效果。切太粗,语义模糊;切太细,上下文断裂。我个人习惯用 256-512 tokens 作为默认窗口,再根据业务场景微调。
2.1.2 图像数据接入
图像接入的核心是特征提取。你不能直接把像素矩阵扔进向量数据库——维度太高,语义太浅。
我常用的做法是:
- 用预训练 CNN(如 ResNet、EfficientNet)提取图像特征向量。
- 向量维度通常压缩到 512-2048 维。
- 同时保留图像路径、标签、拍摄时间等元数据。
小技巧:图像向量化时,记得做数据增强(旋转、裁剪、色彩抖动)。我在一个电商项目中试过,加了增强后,相似图片检索的准确率提升了 12%。
2.1.3 多模态数据接入
多模态数据,说白了就是文本+图像+音频的混合体。比如一个商品页面,既有标题描述,又有主图详情图,还有用户评论。
接入策略有两种:
| 策略 | 做法 | 适用场景 |
|---|---|---|
| 独立向量化 | 各模态分别提取向量,分别存储 | 检索时按模态加权 |
| 融合向量化 | 用多模态模型(如 CLIP)生成统一向量 | 跨模态检索(文本搜图、图搜文本) |
嗯,这里要注意:融合向量化虽然方便,但模型选型很关键。我曾经踩过一个坑——用了一个没对齐好的多模态模型,结果文本和图像的向量空间根本不在一个语义尺度上,检索结果一塌糊涂。
2.2 清洗规则设计
数据清洗,是向量数据预处理里最脏最累的活。但你不做,后面所有环节都会受影响。
2.2.1 常见脏数据类型
- 空值/缺失值:文本为空、图像损坏、向量全零。
- 重复数据:完全重复或近似重复(如相似度 > 0.99)。
- 异常值:向量范数过大或过小、维度不匹配。
- 噪声数据:文本中的乱码、HTML 标签残留、图像中的水印。
避坑指南:我曾经在一个日志分析项目中,发现 30% 的文本向量都是全零向量。查了半天,原来是 embedding 模型在遇到空字符串时直接返回了零向量。从那以后,我每条数据入库前都会加一道「向量非零校验」。
2.2.2 清洗规则配置
我建议把清洗规则做成可配置的 pipeline,而不是硬编码在代码里。这样不同业务线可以灵活调整。
# 清洗规则配置示例(YAML 格式)
cleaning_rules:
text:
- type: remove_html_tags
- type: normalize_whitespace
- type: filter_min_length
params: { min_chars: 10 }
image:
- type: check_dimensions
params: { min_width: 100, min_height: 100 }
- type: detect_corrupted
vector:
- type: check_norm
params: { min_norm: 0.01, max_norm: 100.0 }
- type: deduplicate
params: { similarity_threshold: 0.99 }
2.3 标准化与归一化
标准化和归一化,这两个概念经常被混用。我简单区分一下:
- 标准化(Standardization):让数据符合标准正态分布,均值为 0,标准差为 1。
- 归一化(Normalization):把数据缩放到 [0, 1] 或 [-1, 1] 区间。
在向量数据库里,归一化比标准化更常用。为什么?因为大多数向量检索算法(如余弦相似度、内积)都假设向量是单位长度。如果向量没归一化,检索结果会被向量长度主导,而不是语义相似度。
核心原则:使用余弦相似度或内积作为距离度量时,务必对向量做 L2 归一化。否则,长向量会「压倒」短向量,检索结果严重偏斜。
归一化的代码很简单:
import numpy as np
def l2_normalize(vector):
norm = np.linalg.norm(vector)
if norm == 0:
return vector # 零向量不做归一化
return vector / norm
嗯,这里有个细节:零向量不能归一化,否则会除零。我一般会在归一化前先做一次零向量过滤。
2.4 数据分片策略
数据分片,说白了就是把大向量集合拆成多个小片段。分片做得好,检索效率翻倍;做不好,集群负载不均,查询延迟飙升。
2.4.1 分片维度
分片可以从两个维度考虑:
| 分片维度 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 水平分片 | 按数据行拆分,每片包含完整向量 | 扩展性好,适合海量数据 | 跨片查询需要聚合 |
| 垂直分片 | 按向量维度拆分,每片包含部分维度 | 适合高维向量,减少单节点压力 | 实现复杂,查询需合并 |
实际项目中,水平分片是主流。垂直分片只在向量维度极高(比如 10000+ 维)时才会考虑。
2.4.2 分片策略对比
水平分片又有几种常见策略:
- 哈希分片:对向量 ID 做哈希,均匀分布到各片。简单但无法感知数据分布。
- 范围分片:按向量 ID 或时间范围划分。适合有明确分区键的场景。
- 聚类分片:用 K-Means 等算法把相似向量分到同一片。检索时只需搜索少数片,效率高。
我的经验:聚类分片在亿级向量场景下效果拔群。我在一个推荐系统项目中用了聚类分片,检索延迟从 50ms 降到了 8ms。但代价是建索引时间变长了——聚类本身需要计算量。
2.4.3 分片数量规划
分片数量不是越多越好。我一般按这个公式估算:
分片数 = 总向量数 / 每片目标向量数
每片目标向量数建议范围:100万 - 1000万
举个例子:如果有 1 亿条向量,每片放 500 万条,分片数就是 20。这个规模下,单次检索只需要扫描 1-3 个分片,延迟可控。
注意:分片太多会导致元数据膨胀,分片太少则单节点压力过大。我曾经见过一个团队把 1000 万条数据分了 100 个片,结果每个片只有 10 万条,查询时广播到所有片,反而比不分片还慢。
2.5 本章知识体系总览
下面这张图把本章的核心逻辑串起来了。你可以把它当作数据预处理的标准流程参考。
从数据源接入到最终入库,每一步都有坑。但只要你把清洗、归一化、分片这三个环节做扎实了,向量数据库的质量就有了基本保障。剩下的,就是根据业务场景不断调优了。