• 用户指南

# 稀疏向量

• 准备稀疏向量嵌入；
• 创建具有稀疏向量列的集合；
• 插入具有稀疏向量嵌入的实体；
• 索引集合并对稀疏向量执行 ANN 搜索。

## 准备稀疏向量嵌入

• 稀疏矩阵利用scipy.sparse类族表示稀疏嵌入。这种方法对于处理大规模、高维数据非常有效。

• 字典列表：将每个稀疏嵌入表示为字典，结构为`{dimension_index: value, ...}` ，其中每个键值对表示维度索引及其对应的值。

例如

``````{2: 0.33, 98: 0.72, ...}
``````
• 元组迭代列表：与字典列表类似，但使用元组可迭代器`[(dimension_index, value)]` ，仅指定非零维及其值。

示例

``````[(2, 0.33), (98, 0.72), ...]
``````

``````# Prepare entities with sparse vector representation
import numpy as np
import random

rng = np.random.default_rng()

num_entities, dim = 10000, 10000

# Generate random sparse rows with an average of 25 non-zero elements per row
entities = [
{
"scalar_field": rng.random(),
# To represent a single sparse vector row, you can use:
# - Any of the scipy.sparse sparse matrices class family with shape[0] == 1
# - Dict[int, float]
# - Iterable[Tuple[int, float]]
"sparse_vector": {
d: rng.random() for d in random.sample(range(dim), random.randint(20, 30))
},
}
for _ in range(num_entities)
]

# print the first entity to check the representation
print(entities[0])

# Output:
# {
#     'scalar_field': 0.520821523849214,
#     'sparse_vector': {
#         5263: 0.2639375518635271,
#         3573: 0.34701499565746674,
#         9637: 0.30856525997853057,
#         4399: 0.19771651149001523,
#         6959: 0.31025067641541815,
#         1729: 0.8265339135915016,
#         1220: 0.15303302147479103,
#         7335: 0.9436728846033107,
#         6167: 0.19929870545596562,
#         5891: 0.8214617920371853,
#         2245: 0.7852255053773395,
#         2886: 0.8787982039149889,
#         8966: 0.9000606703940665,
#         4910: 0.3001170013981104,
#         17: 0.00875671667413136,
#         3279: 0.7003425473001098,
#         2622: 0.7571360018373428,
#         4962: 0.3901879090102064,
#         4698: 0.22589525720196246,
#         3290: 0.5510228492587324,
#         6185: 0.4508413201390492
#     }
# }
``````

## 用稀疏向量场创建集合

``````from pymilvus import MilvusClient, DataType

# Create a MilvusClient instance
client = MilvusClient(uri="http://localhost:19530")

# Create a collection with a sparse vector field
schema = client.create_schema(
auto_id=True,
enable_dynamic_fields=True,
)

# For sparse vector, no need to specify dimension
schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR) # set `datatype` to `SPARSE_FLOAT_VECTOR`

client.create_collection(collection_name="test_sparse_vector", schema=schema)
``````

## 插入具有稀疏向量嵌入的实体

``````# Insert entities
client.insert(collection_name="test_sparse_vector", data=entities)
``````

## 为集合建立索引

``````# Index the collection

# Prepare index params
index_params = client.prepare_index_params()

field_name="sparse_vector",
index_name="sparse_inverted_index",
index_type="SPARSE_INVERTED_INDEX", # the type of index to be created. set to `SPARSE_INVERTED_INDEX` or `SPARSE_WAND`.
metric_type="IP", # the metric type to be used for the index. Currently, only `IP` (Inner Product) is supported.
params={"drop_ratio_build": 0.2}, # the ratio of small vector values to be dropped during indexing.
)

# Create index
client.create_index(collection_name="test_sparse_vector", index_params=index_params)
``````

• `index_type`:要建立的索引类型。稀疏向量的可能选项：

• `SPARSE_INVERTED_INDEX`:反转索引，将每个维度映射到其非零向量上，便于在搜索过程中直接访问相关数据。适用于数据稀疏但维度较高的数据集。

• `SPARSE_WAND`:利用弱-和（WAND）算法，快速绕过不可能的候选项，将评估重点放在排名潜力较高的候选项上。将维度视为术语，将向量视为文档，从而加快大型稀疏数据集的搜索速度。

• `metric_type`:稀疏向量仅支持`IP` （Inner Product）距离度量。

• `params.drop_ratio_build`:专门用于稀疏向量的索引参数。它控制在索引过程中排除的小向量值的比例。通过该参数，可以在构建索引时忽略小值，从而对效率和准确性之间的权衡进行微调。例如，如果`drop_ratio_build = 0.3` ，在索引构建过程中，所有稀疏向量的所有值都会被收集并排序。这些值中最小的 30% 不会包含在索引中，从而减少了搜索过程中的计算工作量。

``````# Load the collection into memory

# Perform ANN search on sparse vectors

# for demo purpose we search for the last inserted vector
query_vector = entities[-1]["sparse_vector"]

search_params = {
"metric_type": "IP",
"params": {"drop_ratio_search": 0.2}, # the ratio of small vector values to be dropped during search.
}

search_res = client.search(
collection_name="test_sparse_vector",
data=[query_vector],
limit=3,
output_fields=["pk", "scalar_field"],
search_params=search_params,
)

for hits in search_res:
for hit in hits:
print(f"hit: {hit}")

# Output:
# hit: {'id': '448458373272710786', 'distance': 7.220192909240723, 'entity': {'pk': '448458373272710786', 'scalar_field': 0.46767865218233806}}
# hit: {'id': '448458373272708317', 'distance': 1.2287548780441284, 'entity': {'pk': '448458373272708317', 'scalar_field': 0.7315987515699472}}
# hit: {'id': '448458373272702005', 'distance': 0.9848432540893555, 'entity': {'pk': '448458373272702005', 'scalar_field': 0.9871869181562156}}
``````

• `params.drop_ratio_search`:专门用于稀疏向量的搜索参数。该选项可通过指定查询向量中最小值的忽略比例，对搜索过程进行微调。它有助于平衡搜索精度和性能。`drop_ratio_search` 的值越小，这些小值对最终得分的贡献就越小。通过忽略一些小值，可以在对精确度影响最小的情况下提高搜索性能。

## 执行标量查询

``````# Perform a query by specifying filter expr
filter_query_res = client.query(
collection_name="test_sparse_vector",
filter="scalar_field > 0.999",
)

print(filter_query_res[:2])

# Output:
# [{'pk': '448458373272701862', 'scalar_field': 0.9994093623822689, 'sparse_vector': {173: 0.35266244411468506, 400: 0.49995484948158264, 480: 0.8757831454277039, 661: 0.9931875467300415, 1040: 0.0965644046664238, 1728: 0.7478245496749878, 2365: 0.4351981580257416, 2923: 0.5505295395851135, 3181: 0.7396837472915649, 3848: 0.4428485333919525, 4701: 0.39119353890419006, 5199: 0.790219783782959, 5798: 0.9623121619224548, 6213: 0.453134149312973, 6341: 0.745091438293457, 6775: 0.27766478061676025, 6875: 0.017947908490896225, 8093: 0.11834774166345596, 8617: 0.2289179265499115, 8991: 0.36600416898727417, 9346: 0.5502803921699524}}, {'pk': '448458373272702421', 'scalar_field': 0.9990218525410719, 'sparse_vector': {448: 0.587817907333374, 1866: 0.0994109958410263, 2438: 0.8672442436218262, 2533: 0.8063794374465942, 2595: 0.02122959867119789, 2828: 0.33827054500579834, 2871: 0.1984412521123886, 2938: 0.09674275666475296, 3154: 0.21552987396717072, 3662: 0.5236313343048096, 3711: 0.6463911533355713, 4029: 0.4041993021965027, 7143: 0.7370485663414001, 7589: 0.37588241696357727, 7776: 0.436136394739151, 7962: 0.06377989053726196, 8385: 0.5808192491531372, 8592: 0.8865005970001221, 8648: 0.05727503448724747, 9071: 0.9450633525848389, 9161: 0.146037295460701, 9358: 0.1903032660484314, 9679: 0.3146636486053467, 9974: 0.8561339378356934, 9991: 0.15841573476791382}}]
``````

``````# primary keys of entities that satisfy the filter
pks = [ret["pk"] for ret in filter_query_res]

# Perform a query by primary key
pk_query_res = client.query(
collection_name="test_sparse_vector", filter=f"pk == '{pks[0]}'"
)

print(pk_query_res)

# Output:
# [{'scalar_field': 0.9994093623822689, 'sparse_vector': {173: 0.35266244411468506, 400: 0.49995484948158264, 480: 0.8757831454277039, 661: 0.9931875467300415, 1040: 0.0965644046664238, 1728: 0.7478245496749878, 2365: 0.4351981580257416, 2923: 0.5505295395851135, 3181: 0.7396837472915649, 3848: 0.4428485333919525, 4701: 0.39119353890419006, 5199: 0.790219783782959, 5798: 0.9623121619224548, 6213: 0.453134149312973, 6341: 0.745091438293457, 6775: 0.27766478061676025, 6875: 0.017947908490896225, 8093: 0.11834774166345596, 8617: 0.2289179265499115, 8991: 0.36600416898727417, 9346: 0.5502803921699524}, 'pk': '448458373272701862'}]
``````

## 限制

• 目前，稀疏向量只支持IP距离度量。

• 对于稀疏向量字段，只支持SPARSE_INVERTED_INDEXSPARSE_WAND索引类型。

• 目前，稀疏向量不支持范围搜索分组搜索搜索迭代器

## 常见问题

• 稀疏向量支持什么距离度量？

稀疏向量只支持内积（IP）距离度量，这是因为稀疏向量的维度较高，L2 距离和余弦距离不切实际。

• 能否解释一下 SPARSE_INVERTED_INDEX 和 SPARSE_WAND 之间的区别，以及如何在它们之间做出选择？

SPARSE_INVERTED_INDEX是一种传统的倒排索引，而SPARSE_WAND使用弱-AND算法来减少搜索过程中全 IP 距离评估的次数。SPARSE_WAND通常速度更快，但其性能会随着向量密度的增加而下降。要在它们之间做出选择，请根据您的特定数据集和使用案例进行实验和基准测试。

• 如何选择 drop_ratio_build 和 drop_ratio_search 参数？

drop_ratio_builddrop_ratio_search的选择取决于数据的特性以及对搜索延迟/吞吐量和准确性的要求。

• 稀疏嵌入支持哪些数据类型？

维度部分必须是无符号 32 位整数，值部分可以是非负 32 位浮点数。

• 稀疏嵌入的维度可以是 uint32 空间内的任何离散值吗？

可以，但有一个例外。稀疏嵌入的维数可以是`[0, maximum of uint32)` 范围内的任意值。这意味着不能使用 uint32 的最大值。

• 是通过索引还是蛮力对增长的线段进行搜索？

对增长的数据段的搜索是通过与密封数据段索引相同类型的索引进行的。对于索引建立前的新增长区段，则使用蛮力搜索。

• 是否可以在一个集合中同时包含稀疏向量和密集向量？

可以，通过多向量类型支持，您可以创建同时包含稀疏和密集向量列的集合，并对其执行混合搜索。

• 插入或搜索稀疏嵌入式有哪些要求？

稀疏嵌入必须至少有一个非零值，向量索引必须是非负的。