在 Milvus 2.5.10(搭配 pymilvus 2.5.6)中,度量类型(Metric Types) 是用于衡量向量之间相似性或距离的核心参数,广泛应用于向量索引构建和相似性搜索(ANN,近似最近邻搜索)。度量类型决定了如何计算两个向量之间的距离或相似度,直接影响搜索结果的语义和性能。Milvus 支持多种度量类型,根据向量数据类型的不同(如浮点向量、二进制向量、稀疏向量),适用的度量类型也有所差异。
以下基于 Milvus 2.5.10 的官方文档(https://milvus.io/docs/zh/metric.md)和其他相关资源,详细介绍 Milvus 支持的度量类型,包括定义、适用场景、支持的向量类型、数学公式、代码示例以及选择建议。内容将涵盖所有度量类型,确保准确、全面,并基于最新版本。
1. 概述
度量类型(Metric Types)是 Milvus 中用于量化向量相似性的方法,常见于以下场景:
- 向量索引构建:在创建索引(如 HNSW、IVF_FLAT)时,指定度量类型以定义索引的距离计算方式。
- 向量搜索:在搜索时,指定度量类型以确定返回结果的排序依据(最近邻或最相似)。
- 混合查询:结合标量过滤和向量搜索时,度量类型影响向量部分的排序。
Milvus 支持的度量类型根据向量数据类型分为三类:
- 浮点向量(FLOAT_VECTOR, FLOAT16_VECTOR, BFLOAT16_VECTOR):支持多种距离和相似度度量。
- 二进制向量(BINARY_VECTOR):支持基于位运算的距离度量。
- 稀疏向量(SPARSE_FLOAT_VECTOR):仅支持内积度量。
度量类型分为两类:
- 距离度量:如欧几里得距离(L2),值越小表示向量越接近。
- 相似度度量:如余弦相似度(COSINE),值越大表示向量越相似。
2. 度量类型详解
以下按向量数据类型分类,介绍 Milvus 2.5.10 支持的所有度量类型,包括定义、公式、适用场景和代码示例。
2.1 浮点向量度量类型
浮点向量(FLOAT_VECTOR
、FLOAT16_VECTOR
、BFLOAT16_VECTOR
)是 Milvus 中最常用的向量类型,适用于机器学习模型(如 BERT、ResNet)生成的嵌入。支持的度量类型包括:
(1) L2(欧几里得距离)
- 定义:计算两个向量之间的欧几里得距离(平方和开根号),表示几何空间中的直线距离。
- 公式:
L 2 ( x , y ) = ∑ i = 1 n ( x i − y i ) 2 L2(x, y) = \sqrt{\sum_{i=1}^n (x_i - y_i)^2} L2(x,y)=i=1∑n(xi−yi)2
其中 x x x 和 y y y 是两个 n n n 维向量, x i x_i xi 和 y i y_i yi 是第 i i i 个维度。 - 适用场景:
- 向量未归一化,需直接比较绝对距离。
- 图像处理、推荐系统等需要精确几何距离的场景。
- 优点:
- 直观反映向量间的绝对差异。
- 计算简单,广泛支持。
- 缺点:
- 对向量幅值敏感,未归一化的向量可能导致偏差。
- 高维数据可能受维数灾难影响。
- 支持的索引:FLAT、IVF_FLAT、IVF_PQ、IVF_SQ8、HNSW、HNSW_SQ、HNSW_PQ、HNSW_PRQ、SCANN、DiskANN、GPU_CAGRA、GPU_IVF_FLAT、GPU_IVF_PQ、GPU_BRUTE_FORCE。
- 代码示例:
from pymilvus import MilvusClient, CollectionSchema, FieldSchema, DataType from pymilvus.milvus_client.index import IndexParams import random client = MilvusClient(uri="http://localhost:19530") fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True), FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=128) ] schema = CollectionSchema(fields=fields) client.create_collection(collection_name="l2_example", schema=schema) # 创建 HNSW 索引,指定 L2 index_params = IndexParams() index_params.add_index( field_name="vector", index_type="HNSW", metric_type="L2", params={"M": 16, "efConstruction": 200} ) client.create_index(collection_name="l2_example", index_params=index_params) client.load_collection(collection_name="l2_example") # 插入数据 data = [ {"id": i, "vector": [random.random() for _ in range(128)]} for i in range(1000) ] client.insert(collection_name="l2_example", data=data) # 搜索 query_vector = [random.random() for _ in range(128)] results = client.search( collection_name="l2_example", data=[query_vector], limit=5, search_params={"metric_type": "L2", "params": {"ef": 64}} ) print("L2 search results:", results)
(2) IP(内积)
- 定义:计算两个向量的内积,通常用于衡量方向相似性(需归一化向量以等价于余弦相似度)。
- 公式:
I P ( x , y ) = ∑ i = 1 n x i ⋅ y i IP(x, y) = \sum_{i=1}^n x_i \cdot y_i IP(x,y)=i=1∑nxi⋅yi- 对于归一化向量, I P ( x , y ) = cos ( θ ) IP(x, y) = \cos(\theta) IP(x,y)=cos(θ),值越大表示越相似。
- 适用场景:
- 归一化向量,衡量方向相似性。
- NLP(如词嵌入)、推荐系统(如用户-物品相似性)。
- 优点:
- 计算效率高,适合高维数据。
- 对于归一化向量,等价于余弦相似度。
- 缺点:
- 对未归一化向量敏感,需预处理。
- 不直接反映几何距离。
- 支持的索引:FLAT、IVF_FLAT、IVF_PQ、IVF_SQ8、HNSW、HNSW_SQ、HNSW_PQ、HNSW_PRQ、SCANN、DiskANN、GPU_CAGRA、GPU_IVF_FLAT、GPU_IVF_PQ、GPU_BRUTE_FORCE。
- 代码示例:
# 类似 L2 示例,仅修改 metric_type 为 IP index_params.add_index( field_name="vector", index_type="HNSW", metric_type="IP", params={"M": 16, "efConstruction": 200} ) client.create_index(collection_name="ip_example", index_params=index_params) results = client.search( collection_name="ip_example", data=[query_vector], limit=5, search_params={"metric_type": "IP", "params": {"ef": 64}} ) print("IP search results:", results)
(3) COSINE(余弦相似度)
- 定义:计算两个向量夹角的余弦值,衡量方向相似性,与向量幅值无关。
- 公式:
C O S I N E ( x , y ) = ∑ i = 1 n x i ⋅ y i ∑ i = 1 n x i 2 ⋅ ∑ i = 1 n y i 2 COSINE(x, y) = \frac{\sum_{i=1}^n x_i \cdot y_i}{\sqrt{\sum_{i=1}^n x_i^2} \cdot \sqrt{\sum_{i=1}^n y_i^2}} COSINE(x,y)=∑i=1nxi2⋅∑i=1nyi2∑i=1nxi⋅yi- 范围: [ − 1 , 1 ] [-1, 1] [−1,1],值越大表示越相似。
- 适用场景:
- 向量已归一化或需忽略幅值差异。
- 文本语义搜索、图像检索(如 CLIP 模型)。
- 优点:
- 忽略向量幅值,仅关注方向,适合语义相似性。
- 归一化后计算效率高。
- 缺点:
- 对未归一化向量需额外计算归一化。
- 不反映绝对距离。
- 支持的索引:FLAT、IVF_FLAT、IVF_PQ、IVF_SQ8、HNSW、HNSW_SQ、HNSW_PQ、HNSW_PRQ、SCANN、DiskANN、GPU_CAGRA、GPU_IVF_FLAT、GPU_IVF_PQ、GPU_BRUTE_FORCE。
- 代码示例:
# 类似 L2 示例,仅修改 metric_type 为 COSINE index_params.add_index( field_name="vector", index_type="HNSW", metric_type="COSINE", params={"M": 16, "efConstruction": 200} ) client.create_index(collection_name="cosine_example", index_params=index_params) results = client.search( collection_name="cosine_example", data=[query_vector], limit=5, search_params={"metric_type": "COSINE", "params": {"ef": 64}} ) print("COSINE search results:", results)
2.2 二进制向量度量类型
二进制向量(BINARY_VECTOR
)存储 1 位值(每 8 位占 1 字节),适用于高效的二值化特征。支持的度量类型基于位运算,计算两个向量之间的差异。
(1) HAMMING(汉明距离)
- 定义:计算两个二进制向量对应位不同的数量(异或运算后统计 1 的个数)。
- 公式:
H A M M I N G ( x , y ) = ∑ i = 1 n ( x i ⊕ y i ) HAMMING(x, y) = \sum_{i=1}^n (x_i \oplus y_i) HAMMING(x,y)=i=1∑n(xi⊕yi)
其中 ⊕ \oplus ⊕ 表示异或运算, n n n 是位数。 - 适用场景:
- 二值化特征(如图像哈希、签名)。
- 需要快速比较的场景。
- 优点:
- 计算效率极高(位运算)。
- 适合低存储成本的场景。
- 缺点:
- 仅反映位差异,语义表达有限。
- 精度较低。
- 支持的索引:BIN_FLAT、BIN_IVF_FLAT。
- 代码示例:
from pymilvus import MilvusClient, CollectionSchema, FieldSchema, DataType from pymilvus.milvus_client.index import IndexParams import random from bitarray import bitarray # pip install bitarray client = MilvusClient(uri="http://192.168.1.110:19530") fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True), FieldSchema(name="vector", dtype=DataType.BINARY_VECTOR, dim=128) ] schema = CollectionSchema(fields=fields) client.create_collection(collection_name="hamming_example", schema=schema) # 创建 BIN_FLAT 索引,指定 HAMMING index_params = IndexParams() index_params.add_index( field_name="vector", index_type="BIN_FLAT", metric_type="HAMMING" ) client.create_index(collection_name="hamming_example", index_params=index_params) def generate_binary_vector(dim=128): bits = bitarray() for _ in range(dim): bits.append(random.choice([True, False])) return bits.tobytes() # 插入数据 data = [ {"id": i, "vector": generate_binary_vector(128)} for i in range(1000) ] client.insert(collection_name="hamming_example", data=data) client.load_collection(collection_name="hamming_example") # 搜索 query_vector = generate_binary_vector(128) results = client.search( collection_name="hamming_example", data=[query_vector], limit=5, search_params={"metric_type": "HAMMING"} ) print("HAMMING search results:", results)
(2) JACCARD(杰卡德距离)
- 定义:计算两个二进制向量的杰卡德距离,表示交集与并集的比率。
- 公式:
J A C C A R D ( x , y ) = 1 − ∣ x ∩ y ∣ ∣ x ∪ y ∣ = ∣ x ⊕ y ∣ ∣ x ∪ y ∣ JACCARD(x, y) = 1 - \frac{|x \cap y|}{|x \cup y|} = \frac{|x \oplus y|}{|x \cup y|} JACCARD(x,y)=1−∣x∪y∣∣x∩y∣=∣x∪y∣∣x⊕y∣- ∣ x ∩ y ∣ |x \cap y| ∣x∩y∣:对应位均为 1 的数量。
- ∣ x ∪ y ∣ |x \cup y| ∣x∪y∣:至少一位为 1 的数量。
- 适用场景:
- 集合相似性比较(如标签集、特征集)。
- 需要归一化差异的场景。
- 优点:
- 归一化距离,适合比较集合相似性。
- 对向量长度不敏感。
- 缺点:
- 计算复杂度略高于 HAMMING。
- 语义表达有限。
- 支持的索引:BIN_FLAT、BIN_IVF_FLAT。
- 代码示例:
# 类似 HAMMING 示例,仅修改 metric_type 为 JACCARD index_params.add_index( field_name="vector", index_type="BIN_FLAT", metric_type="JACCARD" ) client.create_index(collection_name="jaccard_example", index_params=index_params) results = client.search( collection_name="jaccard_example", data=[query_vector], limit=5, search_params={"metric_type": "JACCARD"} ) print("JACCARD search results:", results)
(3) TANIMOTO(谷本距离)
- 定义:计算两个二进制向量的谷本距离,扩展了杰卡德距离,考虑位差异和共同位。
- 公式:
T A N I M O T O ( x , y ) = ∣ x ⊕ y ∣ ∣ x ∪ y ∣ + ∣ x ∩ y ∣ TANIMOTO(x, y) = \frac{|x \oplus y|}{|x \cup y| + |x \cap y|} TANIMOTO(x,y)=∣x∪y∣+∣x∩y∣∣x⊕y∣ - 适用场景:
- 集合相似性比较,强调共同特征。
- 化学信息学、指纹匹配。
- 优点:
- 比 JACCARD 更细致地考虑共同位。
- 适合特定领域(如化学相似性)。
- 缺点:
- 计算复杂度略高。
- 应用场景较窄。
- 支持的索引:BIN_FLAT、BIN_IVF_FLAT。
- 代码示例:
# 类似 HAMMING 示例,仅修改 metric_type 为 TANIMOTO index_params.add_index( field_name="vector", index_type="BIN_FLAT", metric_type="TANIMOTO" ) client.create_index(collection_name="tanimoto_example", index_params=index_params) results = client.search( collection_name="tanimoto_example", data=[query_vector], limit=5, search_params={"metric_type": "TANIMOTO"} ) print("TANIMOTO search results:", results)
2.3 稀疏向量度量类型
稀疏向量(SPARSE_FLOAT_VECTOR
)存储非零值及其索引,适用于稀疏数据(如 BM25 词频向量)。Milvus 2.5.10 仅支持一种度量类型:
(1) IP(内积)
- 定义:计算稀疏向量的内积,仅考虑非零值的乘积。
- 公式:
I P ( x , y ) = ∑ i ∈ I x ∩ I y x i ⋅ y i IP(x, y) = \sum_{i \in I_x \cap I_y} x_i \cdot y_i IP(x,y)=i∈Ix∩Iy∑xi⋅yi
其中 I x I_x Ix 和 I y I_y Iy 是向量 x x x 和 y y y 的非零索引集合。 - 适用场景:
- 关键词搜索(如 BM25)。
- 稀疏特征表示(如文档向量)。
- 优点:
- 计算效率高,仅处理非零值。
- 适合稀疏数据,存储成本低。
- 缺点:
- 仅支持内积,无法使用其他度量。
- 需确保数据稀疏性以获得最佳性能。
- 支持的索引:SPARSE_INVERTED_INDEX(支持
DAAT_WAND
算法)。 - 代码示例:
from pymilvus import MilvusClient, CollectionSchema, FieldSchema, DataType from pymilvus.milvus_client.index import IndexParams client = MilvusClient(uri="http://localhost:19530") fields = [ FieldSchema(name="id", dtype=DataType.INT64, is_primary=True), FieldSchema(name="vector", dtype=DataType.SPARSE_FLOAT_VECTOR) ] schema = CollectionSchema(fields=fields) client.create_collection(collection_name="sparse_ip_example", schema=schema) # 创建 SPARSE_INVERTED_INDEX 索引,指定 IP index_params = IndexParams() index_params.add_index( field_name="vector", index_type="SPARSE_INVERTED_INDEX", metric_type="IP", params={"inverted_index_algo": "DAAT_WAND"} ) client.create_index(collection_name="sparse_ip_example", index_params=index_params) # 插入数据 data = [ {"id": 0, "vector": {0: 0.1, 100: 0.5}}, {"id": 1, "vector": {1: 0.2, 200: 0.3}} ] client.insert(collection_name="sparse_ip_example", data=data) client.load_collection(collection_name="sparse_ip_example") # 搜索 query_vector = {0: 0.2, 100: 0.4} results = client.search( collection_name="sparse_ip_example", data=[query_vector], limit=5, search_params={"metric_type": "IP"} ) print("Sparse IP search results:", results)
3. 度量类型与向量类型的对应关系
以下是 Milvus 2.5.10 中度量类型与向量类型的支持矩阵:
度量类型 | FLOAT_VECTOR | BINARY_VECTOR | SPARSE_FLOAT_VECTOR |
---|---|---|---|
L2 | ✅ | ❌ | ❌ |
IP | ✅ | ❌ | ✅ |
COSINE | ✅ | ❌ | ❌ |
HAMMING | ❌ | ✅ | ❌ |
JACCARD | ❌ | ✅ | ❌ |
TANIMOTO | ❌ | ✅ | ❌ |
说明:
- 浮点向量支持最广泛的度量类型,适合通用场景。
- 二进制向量仅支持位运算相关的度量,适合高效存储和计算。
- 稀疏向量仅支持内积,专为稀疏数据优化。
4. 选择度量类型的建议
选择度量类型时,需考虑向量类型、数据特性、应用场景和预处理方式。以下是建议:
-
浮点向量:
- L2:适合未归一化的向量,或需精确几何距离的场景(如图像处理)。
- IP:适合归一化向量,强调方向相似性(如推荐系统)。
- COSINE:适合忽略幅值的语义搜索(如文本嵌入、CLIP 模型)。推荐对向量预归一化以提高效率。
- 选择依据:
- 如果向量已归一化,
IP
和COSINE
等价,选择COSINE
更直观。 - 如果向量未归一化且幅值重要,选择
L2
。 - 如果性能优先,
IP
计算最快。
- 如果向量已归一化,
-
二进制向量:
- HAMMING:默认选择,计算最快,适合快速比较(如图像哈希)。
- JACCARD:适合集合相似性,强调交集与并集的比例。
- TANIMOTO:适合特定领域(如化学相似性),对共同特征敏感。
- 选择依据:
- 优先选择
HAMMING
除非有特定需求(如集合归一化或化学应用)。
- 优先选择
-
稀疏向量:
- IP:唯一选项,适合关键词搜索或稀疏特征(如 BM25)。
- 注意:确保数据足够稀疏以最大化性能。
-
预处理建议:
- 对于
IP
和COSINE
,建议预归一化向量(L2 范数归一化)以提高搜索效率和一致性:import numpy as np def normalize_vector(v): norm = np.linalg.norm(v) return v / norm if norm > 0 else v
- 对于二进制向量,确保数据是二值化的(0 或 1)。
- 对于
5. 注意事项
- 版本兼容性:
- 确保使用 Milvus 2.5.10 和
pymilvus
2.5.6,所有度量类型均受支持。 - 稀疏向量的
IP
度量在 Milvus 2.5.x 中进一步优化,需验证版本。
- 确保使用 Milvus 2.5.10 和
- 索引与度量一致性:
- 索引构建时的
metric_type
必须与搜索时的metric_type
一致,否则会报错:try: client.search(..., search_params={"metric_type": "L2"}) except Exception as e: print(f"Error: {e}")
- 索引构建时的
- 性能优化:
IP
和COSINE
在归一化向量上计算效率高于L2
。- 二进制向量的位运算度量(
HAMMING
)速度极快,适合高吞吐量。
- 硬件支持:
- GPU 索引(如 GPU_CAGRA)支持浮点向量的所有度量类型,但需 NVIDIA GPU 和 CUDA。
- 稀疏向量索引(如 SPARSE_INVERTED_INDEX)仅支持 CPU。
- 数据预处理:
- 浮点向量需检查是否归一化,影响
IP
和COSINE
的结果。 - 二进制向量需确保维度是 8 的倍数(按字节存储)。
- 稀疏向量需确保非零值比例低以优化存储和计算。
- 浮点向量需检查是否归一化,影响
6. 混合查询示例
度量类型常与标量过滤结合使用,实现混合查询。以下是一个示例,展示浮点向量使用 COSINE
度量,结合 JSON 字段过滤:
from pymilvus import MilvusClient, CollectionSchema, FieldSchema, DataType
from pymilvus.milvus_client.index import IndexParams
import random
client = MilvusClient(uri="http://localhost:19530")
# 定义 schema
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
FieldSchema(name="metadata", dtype=DataType.JSON),
FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=128)
]
schema = CollectionSchema(fields=fields)
client.create_collection(collection_name="mixed_query_example", schema=schema)
# 创建索引
index_params = IndexParams()
# JSON 字段索引
index_params.add_index(
field_name="metadata",
index_type="INVERTED",
index_name="json_category",
params={"json_path": "metadata[\"category\"]", "json_cast_type": "varchar"}
)
# 向量索引
index_params.add_index(
field_name="vector",
index_type="HNSW",
metric_type="COSINE",
params={"M": 16, "efConstruction": 200}
)
client.create_index(collection_name="mixed_query_example", index_params=index_params)
# 插入数据
data = [
{
"id": i,
"metadata": {"category": "electronics" if i % 2 == 0 else "clothing"},
"vector": [random.random() for _ in range(128)]
}
for i in range(1000)
]
client.insert(collection_name="mixed_query_example", data=data)
client.load_collection(collection_name="mixed_query_example")
# 混合查询
query_vector = [random.random() for _ in range(128)]
results = client.search(
collection_name="mixed_query_example",
data=[query_vector],
limit=5,
filter='metadata["category"] == "electronics"',
output_fields=["id", "metadata"],
search_params={"metric_type": "COSINE", "params": {"ef": 64}}
)
print("Mixed query results:", results)
7. 总结
Milvus 2.5.10 支持的度量类型涵盖浮点向量(L2
、IP
、COSINE
)、二进制向量(HAMMING
、JACCARD
、TANIMOTO
)和稀疏向量(IP
),满足多样化的相似性计算需求。浮点向量度量适用于通用场景,二进制向量度量高效且节省存储,稀疏向量度量专为稀疏数据优化。选择度量类型时,需考虑向量类型、数据预处理(如归一化)和应用场景(如语义搜索或集合比较)。