2. 向量数据采集与预处理:数据源接入、清洗、标准化与分片

数据采集和预处理,说白了就是给向量数据库「喂饭」的过程。饭喂得好不好,直接决定了后面检索和分析的效率。我见过太多团队在模型和算法上花了大把精力,结果数据源接入那一步就埋了雷——格式不统一、脏数据满天飞、向量维度对不上……最后全白干。

这一章,咱们就把这些坑一个个填上。

2.1 数据源接入:文本、图像、多模态

向量数据库不像传统数据库只收结构化数据。它什么都能吃——文本、图片、音频、视频,甚至混合数据。但不同的数据源,接入方式和预处理逻辑完全不同。

2.1.1 文本数据接入

文本是最常见的向量数据源。我习惯把文本接入分成三个步骤:

  1. 原始文本提取:从 PDF、Word、HTML、数据库等来源抽取纯文本内容。
  2. 段落/句子切分:按长度或语义边界切分,避免单条数据过长或过短。
  3. 元数据绑定:保留来源、时间戳、作者等上下文信息。

关键点:文本切分的粒度直接影响向量检索效果。切太粗,语义模糊;切太细,上下文断裂。我个人习惯用 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 本章知识体系总览

下面这张图把本章的核心逻辑串起来了。你可以把它当作数据预处理的标准流程参考。

向量数据采集与预处理流程 向量数据采集与预处理流程 文本数据 图像数据 多模态数据 其他数据源 数据清洗 空值处理 | 去重 | 异常检测 | 噪声过滤 标准化与归一化 L2归一化 | 零均值标准化 | 维度对齐 数据分片 哈希分片 | 范围分片 | 聚类分片 向量数据库入库 每步都需做质量校验 避免脏数据向下游扩散 分片策略影响检索效率 建议根据数据量动态调整

从数据源接入到最终入库,每一步都有坑。但只要你把清洗、归一化、分片这三个环节做扎实了,向量数据库的质量就有了基本保障。剩下的,就是根据业务场景不断调优了。