Python实战- Milvus 向量库 使用相关方法demo

文章目录

  • 前言
    • [Python实战- Milvus 向量库 使用相关方法demo](#Python实战- Milvus 向量库 使用相关方法demo)
      • [1. 建表场景demo](#1. 建表场景demo)
      • [2. 修改表结构场景demo](#2. 修改表结构场景demo)
      • [3. 批量新增、查询场景demo](#3. 批量新增、查询场景demo)
      • [4. 删除、更新、查询场景demo](#4. 删除、更新、查询场景demo)
      • [5. 向量混合查询场景](#5. 向量混合查询场景)

前言

如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。

而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!


Python实战- Milvus 向量库 使用相关方法demo

1. 建表场景demo

下面是我要用的测试表

字段名 类型 性质
id INT64 普通字段(主键)
user VARCHAR 普通字段(用户名)
timestamp INT64 普通字段(时间)
embedding FLOAT_VECTOR 向量字段
python 复制代码
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility
import random
import time
import numpy as np
import sys


# 定义连接 Milvus 的方法
def connect_to_milvus(host="localhost", port="19530"):
    try:
        connections.connect("default", host=host, port=port)
        print("连接 Milvus 成功")
    except Exception as e:
        print(f"连接 Milvus 失败: {e}")
        raise


# 定义创建表的函数
def creatTable():
    try:
        # 定义要创建的表的名称
        collection_name = "demo_collection"
        flag = False
        # 如果存在就删除
        if utility.has_collection(collection_name):
            print(f"Collection `{collection_name}` 已存在,准备删除")
            Collection(name=collection_name).drop()
            flag = True

        # 定义表的字段,包括字段名称、数据类型、是否为主键、是否自动增长、最大长度、维度等信息
        fields = [
            FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),  # 主键字段,自动增长
            FieldSchema(name="user", dtype=DataType.VARCHAR, max_length=100),  # 用户字段,字符串类型,最大长度100
            FieldSchema(name="timestamp", dtype=DataType.INT64),  # 时间戳字段,整数类型
            FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=4)  # 向量字段,浮点类型,维度为4
        ]
        # 据字段定义创建表的 schema
        schema = CollectionSchema(fields, description="Test collection")
        # 根据表名和 schema 创建表
        collection = Collection(name=collection_name, schema=schema)
        # 打印表建立完成的提示信息
        if flag:
            print("表已重新建立完成")
        else:
            print("表建立完成")
        for field in collection.schema.fields:
            print(f"  - {field.name}: {field.dtype.name}, {'主键' if field.is_primary else ''}")
    except Exception as e:
        print(f"Exception : {e}")
    finally:
        # 断开连接
        connections.disconnect("default")
        print("✅ 程序执行完毕,连接已断开")

if __name__ == '__main__':
    # 链接
    connect_to_milvus()
    # 创建表
    creatTable()
    sys.exit(0)

执行脚本:

2. 修改表结构场景demo

demo逻辑:

  1. 创建一个新的集合:定义新的字段结构。
  2. 数据迁移:将现有数据迁移到新的集合。
  3. 更新引用:更新应用程序中对集合的引用,指向新的集合。
  4. 删除旧集合:在确认数据迁移无误后,删除旧集合。

下面有个两个示例demo,一个新增字段和一个更新字段的示例:

python 复制代码
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility
import sys


# =========================
# 自动连接 Milvus 的上下文
# =========================
class MilvusConnection:
    def __init__(self, host="localhost", port="19530"):
        self.host = host
        self.port = port

    def __enter__(self):
        try:
            connections.connect("default", host=self.host, port=self.port)
            print("连接 Milvus 成功")
        except Exception as e:
            print(f"连接 Milvus 失败: {e}")
            raise
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        connections.disconnect("default")
        print("✅ 程序执行完毕,连接已断开")


# =============================
# 自动建立向量字段的索引
# =============================
def create_vector_index_if_needed(collection: Collection):
    for field in collection.schema.fields:
        if field.dtype == DataType.FLOAT_VECTOR:
            print(f">>>>>>为向量字段 `{field.name}` 创建索引...")
            collection.create_index(
                field_name=field.name,
                index_params={
                    "index_type": "IVF_FLAT",
                    "metric_type": "L2",
                    "params": {"nlist": 128}
                }
            )
            print(f"✅ 向量字段 `{field.name}` 索引创建完成")
            return


# ==================================
# 创建 Collection + 自动建索引
# ==================================
def create_table(collection_name, fields, description="Test collection"):
    try:
        # 如果存在就删除
        if utility.has_collection(collection_name):
            print(f"Collection `{collection_name}` 已存在,准备删除")
            Collection(name=collection_name).drop()
            print(f"Collection `{collection_name}` 删除成功")

        # 根据字段定义创建表的 schema
        schema = CollectionSchema(fields, description=description)
        # 根据表名和 schema 创建表
        collection = Collection(name=collection_name, schema=schema)
        print("表建立完成")
        create_vector_index_if_needed(collection)
        for field in collection.schema.fields:
            print(f"  - {field.name}: {field.dtype.name}, {'主键' if field.is_primary else ''}")
        return collection
    except Exception as e:
        print(f"Exception : {e}")


# ========================================
# 数据迁移(自动 load 和 flush)
# ========================================
def migrate_data(source_collection_name, target_collection_name):
    try:
        source_collection = Collection(name=source_collection_name)
        target_collection = Collection(name=target_collection_name)

        source_collection.load()

        # 源集合中全部字段
        source_fields = [f.name for f in source_collection.schema.fields]
        # 目标集合中需要插入的字段(排除 auto_id 主键字段)
        target_fields = [f.name for f in target_collection.schema.fields if not f.auto_id]

        print(f"源字段: {source_fields}")
        print(f"目标字段: {target_fields}")

        # 确保从源集合中查询到目标集合需要的字段
        missing_fields = [f for f in target_fields if f not in source_fields]
        if missing_fields:
            print(f"⚠ 警告:源集合中缺少字段 {missing_fields},将为这些字段插入 None")

        # 构造用于 query 的字段(在源中存在的字段)
        query_fields = [f for f in target_fields if f in source_fields]
        source_data = source_collection.query(expr="id > 0", output_fields=query_fields)
        if not source_data:
            print(f"⚠ 源集合 `{source_collection_name}` 中没有符合条件的数据,跳过数据迁移")
            print("✅ 数据迁移完成")
            return
        # 构建 columnar_data
        columnar_data = [[] for _ in target_fields]
        for row in source_data:
            for i, field in enumerate(target_fields):
                columnar_data[i].append(row.get(field, None))

        target_collection.insert(columnar_data)
        target_collection.flush()

        print("✅ 数据迁移完成")
    except Exception as e:
        print(f"❌ 数据迁移异常: {e}")


# ====================================
# 模拟字段更新:字段替换
# ====================================
def update_field_in_production(collection_name, new_field_schema):
    try:
        # 创建一个新的集合名称
        new_collection_name = f"{collection_name}_new"
        # 如果新集合已存在,删除它
        if utility.has_collection(new_collection_name):
            print(f"新集合 `{new_collection_name}` 已存在,准备删除")
            Collection(name=new_collection_name).drop()

        # 获取现有集合
        collection = Collection(name=collection_name)
        # 获取现有字段
        existing_fields = collection.schema.fields
        # 创建新的字段列表,包括更新的字段
        updated_fields = [new_field_schema if field.name == new_field_schema.name else field for field in
                          existing_fields]
        # 创建新的 schema
        new_schema = CollectionSchema(updated_fields, description=collection.schema.description)
        # 创建新的集合
        new_collection = Collection(name=new_collection_name, schema=new_schema)
        print(f"新集合 `{new_collection_name}` 创建完成")
        create_vector_index_if_needed(new_collection)

        # 迁移数据
        migrate_data(collection_name, new_collection_name)

        # 更新应用程序中对集合的引用
        print(f"请更新应用程序中对集合的引用,将 `{collection_name}` 替换为 `{new_collection_name}`")

        # 删除旧集合
        print(f"删除旧集合 `{collection_name}`")
        collection.drop()
        print('"最终表结构>>>>> ')
        for field in new_collection.schema.fields:
            print(f"  - {field.name}: {field.dtype.name}, {'主键' if field.is_primary else ''}")
        return new_collection_name
    except Exception as e:
        print(f"异常: {e}")


# ====================================
# 定义新增字段的函数
# ====================================
def add_field_to_collection(collection_name, new_field_schema):
    try:
        # 创建一个新的集合名称
        new_collection_name = f"{collection_name}_new"
        # 如果新集合已存在,删除它
        if utility.has_collection(new_collection_name):
            print(f"新集合 `{new_collection_name}` 已存在,准备删除")
            Collection(name=new_collection_name).drop()

        # 获取现有集合
        collection = Collection(name=collection_name)
        # 获取现有字段
        existing_fields = collection.schema.fields
        # 创建新的字段列表,包括新增的字段
        updated_fields = existing_fields + [new_field_schema]
        # 创建新的 schema
        new_schema = CollectionSchema(updated_fields, description=collection.schema.description)
        # 创建新的集合
        new_collection = Collection(name=new_collection_name, schema=new_schema)
        print(f"新集合 `{new_collection_name}` 创建完成")
        create_vector_index_if_needed(new_collection)

        # 迁移数据
        migrate_data(collection_name, new_collection_name)

        # 更新应用程序中对集合的引用
        print(f"请更新应用程序中对集合的引用,将 `{collection_name}` 替换为 `{new_collection_name}`")

        # 删除旧集合
        print(f"删除旧集合 `{collection_name}`")
        print('"最终表结构>>>>> ')
        for field in new_collection.schema.fields:
            print(f"  - {field.name}: {field.dtype.name}, {'主键' if field.is_primary else ''}")
        collection.drop()
        return new_collection_name

    except Exception as e:
        print(f"异常: {e}")


# ====================================
# 修改表结构场景demo
# ====================================
if __name__ == '__main__':
    # 定义要创建的表的名称
    collection_name = "demo_collection"
    # 定义初始字段
    initial_fields = [
        FieldSchema(name="id", dtype=DataType.INT64, is_primary=True, auto_id=True),  # 主键字段,自动增长
        FieldSchema(name="user", dtype=DataType.INT64, max_length=100),  # 用户字段,字符串类型,最大长度100
        FieldSchema(name="timestamp", dtype=DataType.INT64),  # 时间戳字段,整数类型
        FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=4)  # 向量字段,浮点类型,维度为4
    ]
    # 定义更新的字段
    updated_field = FieldSchema(name="user", dtype=DataType.VARCHAR, max_length=200)  # 更新字段
    # 定义新增的字段
    new_field = FieldSchema(name="tag", dtype=DataType.VARCHAR, max_length=20)  # 新增字段

    # 使用上下文管理器连接 Milvus
    with MilvusConnection():
        # 创建表
        collection = create_table(collection_name, initial_fields)
        try:
            # 更新字段
            print("================更新字段===============")
            new_collection_name = update_field_in_production(collection_name, updated_field)
            # 新增字段
            print("================新增字段===============")
            new_collection_name = add_field_to_collection(new_collection_name, new_field)
        except Exception as e:
            print(f"异常: {e}")

    sys.exit(0)

注意的是,对含有向量字段的表查询时,该向量字段必须添加索引。

更新效果:

新增效果:

3. 批量新增、查询场景demo

代码如下:

python 复制代码
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility
import sys
import random
import time


# =========================
# 自动连接 Milvus 的上下文
# =========================
class MilvusConnection:
    def __init__(self, host="localhost", port="19530"):
        self.host = host
        self.port = port

    def __enter__(self):
        try:
            connections.connect("default", host=self.host, port=self.port)
            print("连接 Milvus 成功")
        except Exception as e:
            print(f"连接 Milvus 失败: {e}")
            raise
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        connections.disconnect("default")
        print("✅ 程序执行完毕,连接已断开")


# =============================
# 自动建立向量字段的索引
# =============================
def create_vector_index_if_needed(collection: Collection):
    for field in collection.schema.fields:
        if field.dtype == DataType.FLOAT_VECTOR:
            print(f">>>>>>为向量字段 `{field.name}` 创建索引...")
            collection.create_index(
                field_name=field.name,
                index_params={
                    "index_type": "IVF_FLAT",
                    "metric_type": "L2",
                    "params": {"nlist": 128}
                }
            )
            print(f"✅ 向量字段 `{field.name}` 索引创建完成")
            return


# ==================================
# 创建 Collection + 自动建索引
# ==================================
def create_table(collection_name, fields, description="Test collection"):
    try:
        # 如果存在就删除
        if utility.has_collection(collection_name):
            print(f"Collection `{collection_name}` 已存在,准备删除")
            Collection(name=collection_name).drop()
            print(f"Collection `{collection_name}` 删除成功")

        # 根据字段定义创建表的 schema
        schema = CollectionSchema(fields, description=description)
        # 根据表名和 schema 创建表
        collection = Collection(name=collection_name, schema=schema)
        print("表建立完成")
        create_vector_index_if_needed(collection)
        for field in collection.schema.fields:
            print(f"  - {field.name}: {field.dtype.name}, {'主键' if field.is_primary else ''}")
        return collection
    except Exception as e:
        print(f"Exception : {e}")


# =========================
# 批量插入
# =========================
def insert_mock_data(collection: Collection, num_rows=10):
    print(f"🚀 插入测试数据,共 {num_rows} 条")

    # 固定几个向量模板(4维)
    fixed_vectors = [
        [0.1, 0.2, 0.3, 0.4],
        [0.4, 0.3, 0.2, 0.1],
        [0.9, 0.8, 0.7, 0.6],
        [0.5, 0.5, 0.5, 0.5]
    ]
    # 固定几个用户模板
    fixed_user = [
        'yangzhenyu',
        'anran',
        'xiaoyu',
        'wanghui',
        'taoyutian'
    ]

    # 构造字段数据
    id_list = [f'pk_id_{i}' for i in range(num_rows)]
    user_list = [random.choice(fixed_user) for _ in range(num_rows)]
    timestamp_list = [int(time.time()) + i for i in range(num_rows)]
    vector_list = [random.choice(fixed_vectors) for _ in range(num_rows)]

    # 按列插入(注意顺序要和 schema 对应:user, timestamp, embedding)
    entities = [
        id_list,
        user_list,
        timestamp_list,
        vector_list
    ]

    try:
        collection.insert(entities)
        collection.flush()
        print("✅ 插入完成")
    except Exception as e:
        print(f"Exception : {e}")


# =========================
# 查询最新N条数据(按 timestamp 降序)
# =========================
def query_latest_data(collection: Collection, num=10):
    print(f"🔍 查询最近 {num} 条数据...")
    try:
        collection.load()
        result = collection.query(
            expr="timestamp >= 0",
            output_fields=["user", "timestamp", "embedding"],
            limit=num,
            order_by=[{"field_name": "timestamp", "order": "desc"}
        ]  # 需要 Milvus >= 2.3 ,注意的是对于大部分全表扫描、简单表达式,排序可能无效(会退化成插入顺序或主键顺序),不是"完全稳定可靠"的功能
        )
        for i, row in enumerate(result, 1):
            print(f"{i}. {row}")
    except Exception as e:
        print(f"Exception : {e}")


def query_latest_data_check(collection: Collection, num=10):
    print(f"🔍 查询最近 {num} 条数据(期望 timestamp 降序)...")
    try:
        collection.load()
        result = collection.query(
            expr="timestamp >= 0",
            output_fields=["id", "user", "timestamp"],
            limit=num,
            order_by=[{"field_name": "timestamp", "order": "desc"}]
        )
        for i, row in enumerate(result, 1):
            print(f"{i}. {row}")
        print("⚠️ 检查是否为降序:")
        for i in range(1, len(result)):
            if result[i]["timestamp"] > result[i-1]["timestamp"]:
                print("❌ 排序异常:不是严格降序")
                break
        else:
            print("✅ 排序正确:为严格降序")
    except Exception as e:
        print(f"Exception : {e}")


# ====================================
# 批量新增、查询场景demo
# ====================================
if __name__ == '__main__':
    # 定义要创建的表的名称
    collection_name = "demo_collection"
    # 定义初始字段
    initial_fields = [
        FieldSchema(name="id", dtype=DataType.VARCHAR, max_length=100, is_primary=True, auto_id=False),  # 主键字段,自动增长
        FieldSchema(name="user", dtype=DataType.VARCHAR, max_length=100),  # 用户字段,字符串类型,最大长度100
        FieldSchema(name="timestamp", dtype=DataType.INT64),  # 时间戳字段,整数类型
        FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=4)  # 向量字段,浮点类型,维度为4
    ]
    # 使用上下文管理器连接 Milvus
    with MilvusConnection():
        # 创建表
        collection = create_table(collection_name, initial_fields)
        try:
            # 批量插入
            print("================批量插入===============")
            insert_mock_data(collection, 3500)
            # 查询最新10条数据验证
            print("================查询最新10条数据验证===============")
            query_latest_data(collection, num=10)

        except Exception as e:
            print(f"异常: {e}")

    sys.exit(0)

执行结果:

4. 删除、更新、查询场景demo

demo流程:

1、查询pk_id_0

2、删除pk_id_0

3、查询pk_id_0

4、查询pk_id_1

5、更新pk_id_1

6、查询pk_id_1

注意点:

1、Milvus 的 upsert() 是更新或插入数据,但它更新后的数据并不会立即反映在 query() 中,因为:

  • upsert() 相当于执行 insert(),如果主键重复则覆盖。
  • 数据是 异步写入的(写入 WAL -> 后台持久化 -> 索引构建),即使你调用了 flush(),也不意味着数据立刻可查。
  • 查询操作依赖的是被加载(load)的 segments,更新后新的 segment 没被加载进内存,所以查询不到。
    解决方法是在更新后查询的环节前,新加 collection.load() 重新加载最新的 segments,前置要求是segments是最新的。

2、释放 Milvus 中当前加载的 Collection 的内存资源,Milvus 的数据不会默认一直加载在内存里。你需要显式调用 collection.load() 才能做查询(query)、搜索(search)等操作, 当你不再需要操作这个集合时,调用collection.release()释放内存中的数据资源,避免资源占用太多。

3、Milvus 的 flush() 和 load() 不保证数据立即可查, 因为flush()是异步的,即使你调用了 flush(), Milvus 可能还在后台处理 segment,

解决方案是等 2 秒再 load,确保 flush 后的数据已经落盘并 segment ready。

4、保持 id 不变 + 更新的话,建表时不能使用auto_id=False

情况 是否能用 upsert 是否能指定 id 备注
auto_id = True(自动 id) ❌ 不能用 upsert ❌ 不能传 id 只能删除后重新插入,id 会变
auto_id = False(手动 id) ✅ 可以用 upsert ✅ 需要传 id 才能根据主键正确更新记录

5、用 auto_id=True的限制

目的 能否实现 原因说明
删除指定 id 的数据 ✅ 可以 delete(expr="id == xxx") 支持
更新指定 id 的数据 ❌ 不行 无法重新插入相同 id,Milvus 不支持指定 id
插入时控制主键 ❌ 不行 auto_id=True 会忽略用户手动设置的 id 值
查询用原始 id 查结果 ✅ 可以 但仅限于原始记录未被删除时

6、排序功能 collection.query() 的 order_by 对于大部分全表扫描、简单表达式,排序可能无效, order_by 主要在有过滤条件且索引支持的情况下效果更好, 这可以视为当前 Milvus SDK 和引擎的一个已知限制,不是"完全稳定可靠"的功能。

代码:

python 复制代码
import time
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility
import sys


# ====================================
# 查询函数
# ====================================
def query_by_id(collection: Collection, id_value: str):
    print(f"🔍 查询 id = {id_value} ...")
    try:
        results = collection.query(expr=f"id == '{id_value}'",
                                   output_fields=["id", "user", "timestamp", "embedding"])
        if results:
            print(f"✅ 查询成功: {results[0]}")
        else:
            print("⚠️ 没有找到该记录")
    except Exception as e:
        print(f"❌ 查询异常: {e}")


# ====================================
# 删除函数
# ====================================
def delete_by_id(collection: Collection, id_value: str):
    print(f"🗑️ 删除 id = {id_value} ...")
    try:
        collection.delete(expr=f"id == '{id_value}'")
        collection.flush()
        print("✅ 删除成功")
    except Exception as e:
        print(f"❌ 删除异常: {e}")


# ====================================
# 更新函数
# ====================================
def update_by_id(collection: Collection, id_value: str, new_user: str):
    print(f"✏️ 更新 id = {id_value} 的 user 字段为 `{new_user}` ...")
    try:
        # 查询旧数据
        old_data = collection.query(expr=f"id == '{id_value}'",
                                    output_fields=["user", "timestamp", "embedding"])
        if not old_data:
            print("==============找不到需要更新的数据")
            return
        # 组织更新数据(主键不能变)
        timestamp = int(time.time())
        embedding = old_data[0]["embedding"]
        # Milvus 的 upsert() 是更新或插入数据,但它更新后的数据并不会立即反映在 query() 中
        collection.upsert([
            [id_value],
            [new_user],
            [timestamp],
            [embedding]
        ])
        collection.flush()
        print("✅ 更新成功")
    except Exception as e:
        print(f"❌ 更新异常: {e}")


# ====================================
# 删除、更新、查询场景demo
# ====================================
if __name__ == '__main__':
    # 定义要创建的表的名称
    collection_name = "demo_collection"

    id1 = 'pk_id_0'
    id2 = 'pk_id_1'
    try:
        connections.connect("default", host="localhost", port="19530")
        collection = Collection(collection_name)
        collection.load()

        # 1. 查询 id1
        print("\n=== Step 1: 查询 id1 ===")
        query_by_id(collection, id1)

        # 2. 删除 id1
        print("\n=== Step 2: 删除 id1 ===")
        delete_by_id(collection, id1)

        # 3. 再查 id1
        print("\n=== Step 3: 再查 id1 ===")
        query_by_id(collection, id1)

        # 4. 查询 id2
        print("\n=== Step 4: 查询 id2 ===")
        query_by_id(collection, id2)

        # 5. 更新 id2 的 user 字段
        print("\n=== Step 5: 更新 id2 的 user 字段 ===")
        update_by_id(collection, id2, "yangzhenyu")

        # 6. 查询 id2 查看更新结果
        print("\n=== Step 6: 查询 id2 查看更新结果 ===")
        time.sleep(2)  # 等 2 秒再 load,确保 flush 后的数据已经落盘并 segment ready
        collection.load()  # 🔁 重新加载最新的 segments
        query_by_id(collection, id2)

        # 释放 Milvus 中当前加载的 Collection 的内存资源
        # Milvus 的数据不会默认一直加载在内存里。你需要显式调用 collection.load() 才能做查询(query)、搜索(search)等操作
        # 当你不再需要操作这个集合时,调用collection.release()释放内存中的数据资源,避免资源占用太多
        collection.release()
    except Exception as e:
        print(f"异常: {e}")
    finally:
        connections.disconnect("default")
        print("✅ 程序执行完毕,连接已断开")

    sys.exit(0)

执行效果:

5. 向量混合查询场景

相关参数说明:

anns_field 是存储向量的字段名,比如你的例子里叫 "embedding"。

param 里传入索引相关的搜索参数,nprobe 控制搜索的精度和性能平衡,越大精度越高,但越慢。

limit 是要返回的最相似条数(top K)。

output_fields 是想返回的附加字段,不指定的话只返回向量的ID和距离。

注意:

Milvus 的混合过滤是基于向量搜索结果的二次过滤,而不是先用普通字段过滤再做向量搜索。

代码:

python 复制代码
import time
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection, utility
import sys


# ====================================
# 查询函数
# ====================================
def query_by_id(collection: Collection, id_value: str):
    print(f"🔍 查询 id = {id_value} ...")
    try:
        results = collection.query(expr=f"id == '{id_value}'",
                                   output_fields=["id", "user", "timestamp", "embedding"])
        if results:
            print(f"✅ 查询成功: {results[0]}")
        else:
            print("⚠️ 没有找到该记录")
    except Exception as e:
        print(f"❌ 查询异常: {e}")


# ====================================
# 删除函数
# ====================================
def delete_by_id(collection: Collection, id_value: str):
    print(f"🗑️ 删除 id = {id_value} ...")
    try:
        collection.delete(expr=f"id == '{id_value}'")
        collection.flush()
        print("✅ 删除成功")
    except Exception as e:
        print(f"❌ 删除异常: {e}")


# ====================================
# 更新函数
# ====================================
def update_by_id(collection: Collection, id_value: str, new_user: str):
    print(f"✏️ 更新 id = {id_value} 的 user 字段为 `{new_user}` ...")
    try:
        # 查询旧数据
        old_data = collection.query(expr=f"id == '{id_value}'",
                                    output_fields=["user", "timestamp", "embedding"])
        if not old_data:
            print("==============找不到需要更新的数据")
            return
        # 组织更新数据(主键不能变)
        timestamp = int(time.time())
        embedding = old_data[0]["embedding"]
        # Milvus 的 upsert() 是更新或插入数据,但它更新后的数据并不会立即反映在 query() 中
        collection.upsert([
            [id_value],
            [new_user],
            [timestamp],
            [embedding]
        ])
        collection.flush()
        print("✅ 更新成功")
    except Exception as e:
        print(f"❌ 更新异常: {e}")


# ====================================
# 向量查询场景demo
# ====================================
if __name__ == '__main__':
    # 定义要创建的表的名称
    collection_name = "demo_collection"

    try:
        connections.connect("default", host="localhost", port="19530")
        collection = Collection(collection_name)
        collection.load()

        # 查询向量(4维示例)
        query_vectors = [
            [0.1, 0.2, 0.3, 0.4]
        ]

        # 搜索参数:根据你建的索引类型,这里用 IVF_FLAT,metric是 L2距离
        search_params = {
            "metric_type": "L2",
            "params": {"nprobe": 10}
        }
        # 执行搜索,topk 是要返回多少条最相似的结果
        expr = "user == 'yangzhenyu'"
        results = collection.search(
            data=query_vectors,
            anns_field="embedding",  # 向量字段名
            param=search_params,
            limit=10,  # top 10 个结果
            expr=expr,
            output_fields=["id", "user", "timestamp"]  # 附带返回的其他字段
        )
        total_count = collection.num_entities
        print(f"总条数: {total_count}")
        # 结果处理打印
        for hits in results:  # 这里results是个list,每个query向量对应一个hits列表
            print("搜索结果:")
            for hit in hits:
                print(f"id: {hit.entity.get('id')}, user: {hit.entity.get('user')}, "
                      f"timestamp: {hit.entity.get('timestamp')}, distance: {hit.distance}")

        # 释放 Milvus 中当前加载的 Collection 的内存资源
        # Milvus 的数据不会默认一直加载在内存里。你需要显式调用 collection.load() 才能做查询(query)、搜索(search)等操作
        # 当你不再需要操作这个集合时,调用collection.release()释放内存中的数据资源,避免资源占用太多
        collection.release()
    except Exception as e:
        print(f"异常: {e}")
    finally:
        connections.disconnect("default")
        print("✅ 程序执行完毕,连接已断开")

    sys.exit(0)

执行效果:

相关推荐
项目題供诗15 分钟前
黑马python(二十四)
开发语言·python
就改了40 分钟前
JUC小册——公平锁和非公平锁
java·开发语言
晓13131 小时前
OpenCV篇——项目(二)OCR文档扫描
人工智能·python·opencv·pycharm·ocr
是小王同学啊~1 小时前
(LangChain)RAG系统链路向量检索器之Retrievers(五)
python·算法·langchain
AIGC包拥它1 小时前
提示技术系列——链式提示
人工智能·python·langchain·prompt
孟陬1 小时前
Python matplotlib 如何**同时**展示正文和 emoji
python
何双新1 小时前
第 1 课:Flask 简介与环境配置(Markdown 教案)
后端·python·flask
一粒沙白猫1 小时前
Java综合练习04
java·开发语言·算法
哎呦你好1 小时前
【CSS】Grid 布局基础知识及实例展示
开发语言·前端·css·css3
一入JAVA毁终身2 小时前
处理Lombok的一个小BUG
java·开发语言·bug