milvus向量数据库参数说明

时间:2024-03-08 11:57:24
import random

from pymilvus import (
    connections,
    FieldSchema, CollectionSchema, DataType,
    Collection,
    utility
)

# This example shows how to:
#   1. connect to Milvus server
#   2. create a collection
#   3. insert entities
#   4. create index
#   5. search


_HOST = '192.168.166.130'
_PORT = '19530'

# Const names
_COLLECTION_NAME = 'demo'
_ID_FIELD_NAME = 'id_field'
_VECTOR_FIELD_NAME = 'float_vector_field'
_STR_FIELD_NAME = "str_field"
_MAX_LENGTH = 65535

# Vector parameters
_DIM = 8
_INDEX_FILE_SIZE = 32  # max file size of stored index

# Index parameters
_METRIC_TYPE = 'L2'
_INDEX_TYPE = 'IVF_FLAT'
_NLIST = 1024
_NPROBE = 16
_TOPK = 3


# Create a Milvus connection
def create_connection():
    print(f"\nCreate connection...")
    connections.connect(host=_HOST, port=_PORT)
    print(f"\nList connections:")
    print(connections.list_connections())


# Create a collection named 'demo'
def create_collection(name, id_field, vector_field, str_field):
    field1 = FieldSchema(name=id_field, dtype=DataType.INT64, description="int64", is_primary=True)
    field2 = FieldSchema(name=vector_field, dtype=DataType.FLOAT_VECTOR, description="float vector", dim=_DIM,
                         is_primary=False)
    field3 = FieldSchema(name=str_field, dtype=DataType.VARCHAR, description="string",
                         max_length=_MAX_LENGTH, is_primary=False)
    schema = CollectionSchema(fields=[field1, field2, field3], description="collection description")
    collection = Collection(name=name, data=None, schema=schema)
    print("\ncollection created:", name)
    return collection


def has_collection(name):
    return utility.has_collection(name)


# Drop a collection in Milvus
def drop_collection(name):
    collection = Collection(name)
    collection.drop()
    print("\nDrop collection: {}".format(name))


# List all collections in Milvus
def list_collections():
    print("\nlist collections:")
    print(utility.list_collections())


def insert(collection, num, dim):
    data = [
        [i for i in range(num)],                                        # id field
        [[random.random() for _ in range(dim)] for _ in range(num)],    # vector field
        [str(random.random()) for _ in range(num)],                     # string field
    ]
    collection.insert(data)
    return data[1]


def get_entity_num(collection):
    print("\nThe number of entity:")
    print(collection.num_entities)


def create_index(collection, filed_name):
    index_param = {
        "index_type": _INDEX_TYPE,
        "params": {"nlist": _NLIST},
        "metric_type": _METRIC_TYPE}
    collection.create_index(filed_name, index_param)
    print("\nCreated index:\n{}".format(collection.index().params))


def drop_index(collection):
    collection.drop_index()
    print("\nDrop index sucessfully")


def load_collection(collection):
    collection.load()


def release_collection(collection):
    collection.release()


def search(collection, vector_field, id_field, search_vectors):
    search_param = {
        "data": search_vectors,
        "anns_field": vector_field,
        "param": {"metric_type": _METRIC_TYPE, "params": {"nprobe": _NPROBE}},
        "limit": _TOPK,
        "expr": "id_field > 0"}
    results = collection.search(**search_param)
    for i, result in enumerate(results):
        print("\nSearch result for {}th vector: ".format(i))
        for j, res in enumerate(result):
            print("Top {}: {}".format(j, res))


def main():
    # create a connection
    create_connection()

    # drop collection if the collection exists
    if has_collection(_COLLECTION_NAME):
        drop_collection(_COLLECTION_NAME)

    # create collection
    collection = create_collection(_COLLECTION_NAME, _ID_FIELD_NAME, _VECTOR_FIELD_NAME, _STR_FIELD_NAME)

    # show collections
    list_collections()

    # insert 10000 vectors with 128 dimension
    vectors = insert(collection, 10, _DIM)

    # get the number of entities
    get_entity_num(collection)

    # create index
    create_index(collection, _VECTOR_FIELD_NAME)

    # load data to memory
    load_collection(collection)

    # search
    search(collection, _VECTOR_FIELD_NAME, _ID_FIELD_NAME, vectors[:3])

    # release memory
    release_collection(collection)

    # drop collection index
    drop_index(collection)

    # drop collection
    drop_collection(_COLLECTION_NAME)


if __name__ == '__main__':
    main()

对于milvus中的索引:

在 Milvus 中,索引(Index)是一种用于加速搜索操作的数据结构。当你在一个集合中插入向量数据后,Milvus 允许你为这些数据创建索引,以提高搜索效率和准确性。索引的作用主要体现在以下几个方面:

1、加速搜索
索引可以显著加快搜索速度。没有索引的情况下,搜索操作可能需要遍历集合中的所有向量,这在大数据集上是非常低效的。通过使用合适的索引,Milvus 可以快速缩小搜索范围并找到最相似的向量。

2、提高搜索准确性

某些索引类型支持参数调整,可以在搜索速度和准确性之间做出权衡。通过调整这些参数,用户可以根据自己的需求优化搜索结果的准确性。

3、支持不同的搜索算法
Milvus 支持多种索引类型,每种类型背后都对应不同的搜索算法或数据结构,如倒排索引(IVF),HNSW(Hierarchical Navigable Small World),FLAT(暴力搜索)等。不同的索引类型适用于不同的场景和需求。

4、索引类型和应用场景
- FLAT:不创建任何索引,直接在原始数据上进行暴力搜索。适用于小数据集或对搜索准确性要求极高的场景。
- IVF_FLAT、IVF_SQ8、IVF_PQ:这些都是基于量化的索引,适用于大规模数据集。它们在准确性和搜索速度之间提供了不同程度的权衡。
- HNSW、ANNOY:基于图的索引,提供较快的搜索速度和较高的准确性,适用于中等规模的数据集。

5、创建索引
在 Milvus 中创建索引是一个异步操作。你可以为一个集合指定索引类型和相关参数,Milvus 会在后台构建索引。一旦索引创建完成,所有后续的搜索操作都会利用这个索引。

示例
以下是一个在 Milvus 中为集合创建索引的示例:

from pymilvus import Collection

collection_name = "example_collection"

collection = Collection(name=collection_name)

# 定义索引参数

index_params = {

    "index_type": "IVF_FLAT",  # 索引类型

    "metric_type": "L2",       # 距离计算类型

    "params": {"nlist": 16384} # 索引构建参数

}

# 为集合创建索引

collection.create_index(field_name="vector", index_params=index_params)


通过创建索引,Milvus 能够在大规模向量数据集上提供快速且灵活的相似性搜索功能,满足不同场景下的需求。

6、params 参数的作用
- params 字段允许你为特定的索引类型定制化配置。这些配置影响索引的构建和搜索性能,以及搜索结果的准确性。不同的索引类型支持不同的配置参数。

7、nlist 参数的作用
- nlist 是 IVF_FLAT(以及其他 IVF 系列索引)特有的参数,它指定了倒排文件(Inverted File,IVF)的数量。在 IVF_FLAT 索引中,所有的向量被分配到这些倒排文件中的某一个,这个过程称为量化。nlist 的值决定了聚类的中心数量,也就是量化的粒度。

8、nlist 对搜索性能和准确性的影响
- 搜索性能:nlist 值较大时,向量空间被划分得更细,每个倒排文件包含的向量数量更少,这可以在搜索时减少不必要的距离计算,从而提高搜索速度。然而,索引构建时间和内存使用量会随之增加。
- 搜索准确性:较大的 nlist 值通常能提高搜索准确性,因为向量空间的划分更细致,相似的向量更有可能被分配到同一个或相近的倒排文件中。但是,这也意味着在搜索时需要检查更多的倒排文件,可能会增加搜索延迟。

示例


在定义 IVF_FLAT 索引时使用 nlist 参数:

index_params = {

    "index_type": "IVF_FLAT",

    "metric_type": "L2",

    "params": {"nlist": 16384}

}


这个示例中,nlist 被设置为 16384,意味着在索引构建过程中,向量空间将被划分为 16384 个区域,每个区域由一个倒排文件表示。

查询中的param参数的作用:

results = collection.search(

    data=query_vectors,  # 查询向量

    anns_field="vector_field",  # 集合中的向量字段

    param=search_params,

    limit=10  # 返回的相似向量数量

)

在 Milvus 中,collection.search 方法的 param 参数用于指定搜索操作的详细配置,这些配置直接影响搜索的行为、性能和结果的准确性。param 参数允许你根据使用的索引类型定制化搜索参数,从而在搜索速度、资源消耗和准确度之间做出权衡。

1、param 参数的作用
- 定义搜索算法的行为:不同的索引类型支持不同的搜索参数。通过 param 参数,你可以指定这些搜索算法特定的参数,如搜索半径、搜索的候选集大小等。
- 优化搜索性能:合理的 param 参数设置可以帮助 Milvus 更有效地利用索引,加快搜索速度,减少资源消耗。
- 调整搜索准确度:某些参数设置允许在搜索速度和准确度之间做出权衡。例如,增加搜索的候选集大小通常可以提高准确度,但可能会增加搜索所需的时间。

2、常见的 param 参数
- nprobe:用于 IVF 类型索引(如 IVF_FLAT、IVF_SQ8、IVF_PQ)。nprobe 指定了在搜索过程中要访问的最近邻候选列表的数量。nprobe 值越大,搜索越准确,但耗时也越长。
- search_k:用于基于图的索引(如 HNSW、ANNOY)。search_k 指定了搜索过程中要检查的节点数量。增加 search_k 可以提高搜索准确度,但也会增加搜索时间。
- ef:也是用于基于图的索引,特别是 HNSW。ef 参数控制着搜索的深度,影响搜索的准确度和性能。

示例
以下是一个使用 IVF_FLAT 索引进行搜索时设置 param 参数的示例:

search_params = {

    "metric_type": "L2",

    "params": {"nprobe": 10}

}

results = collection.search(

    data=query_vectors,  # 查询向量

    anns_field="vector_field",  # 集合中的向量字段

    param=search_params,

    limit=10  # 返回的相似向量数量

)


在这个示例中,nprobe 被设置为 10,意味着在搜索过程中,每个查询向量将从索引的候选列表中选取 10 个最近的列表进行精确搜索

3、注意事项
- 选择合适的 param 参数需要根据具体的应用场景和需求进行权衡。在实际应用中,可能需要通过实验来找到最佳的参数设置。
- 不同版本的 Milvus 可能支持不同的参数和索引类型。请参考你所使用的 Milvus 版本的官方文档,以获取最准确的信息。