学习路程五 向量数据库Milvus操作

news/2025/2/26 16:39:46

前序

前面安装好了docker且成功拉取Milvus镜像,启动。通过python成功连接上了数据。接下来就继续更多Milvus的操作
在开始之前,先来简单了解一下向量数据库内一些东西的基本概念

概念描述
数据库(Database)类似与MySQL的database,首先需要一个库
集合 (Collection)集合类似于MySQL中的表,它是用来存储向量的容器。集合可以有多个字段,每个字段对应一个向量属性。
向量 (Vector)向量是多维空间中的点,通常用于表示数据的特征,是集合中的基本存储单元。
索引 (Index)索引是用来加速向量搜索的数据结构,有多种索引类型,如 FLAT、IVF、HNSW 等,各自都有特定的适用场景。
Filed字段,可以是结构化数据、向量;
Entity一组Filed,类似表的一条记录。

〇、可视化界面工具attu

在开始之前,可以先安装一个可视化工具,这样能方便查看自己每一步操作后的结果。

下载地址:https://github.com/zilliztech/attu/releases

如果有使用Mac的,和我一样,安装后一直提示已损坏,无法使用的。可以按照下面步骤操作,我按网上搜的,亲测可用。

  1. 打开终端,输入
    sudo spctl --master-disable
    然后输入自己的密码就好

  2. 在终端输入
    sudo xattr -r -d com.apple.quarantine
    然后把这个不能打开的attu拖过来
    在这里插入图片描述
    注意中间需要有个空格。

经过上面操作后,再重新运行,就能正常使用了。

一、数据库操作

有点类似MySQL,最先也得创建database,然后在这个database下使用,建表,查询,删除等。这块没什么特殊的内容

列出数据库

python">from pymilvus import MilvusClient
client = MilvusClient()  # 上面的内容可以简写
# 列出数据库
res = client.list_databases()

print(res)
# 断开连接
client.close()

"""
['default']
"""

创建数据库

python"># 创建数据库
res1 = client.create_database("test")

使用数据库

python">client.using_database('test')

删除数据库

python">client.drop_database("my_database")

二、集合相关操作

创建集合

python"># 创建集合,重复运行,不会反复创建集合。
client.create_collection(
  collection_name="test_collection",  # 集合名称
  dimension=2048  # 向量的维度,这里的维度,关系到后面添加的向量数据的维度
)

这里的维度跟选用的embedding模型有关,不同模型向量化出来的数据维度不同。像之前用的zhipu的embedding-3,向量化出来就是2048维度。
在这里插入图片描述
默认创建的主键名为id,不自增。向量字段名为vector,计算向量相似度的方法是COSINE
在这里插入图片描述

判断集合存在

python">client.has_collection('test_collection')  # 判断集合是否存在

查看集合

python">res = client.describe_collection('test_collection')
print(res)
"""
{'collection_name': 'test_collection', 'auto_id': False, 'num_shards': 1, 'description': '', 'fields': [{'field_id': 100, 'name': 'id', 'description': '', 'type': <DataType.INT64: 5>, 'params': {}, 'is_primary': True}, {'field_id': 101, 'name': 'vector', 'description': '', 'type': <DataType.FLOAT_VECTOR: 101>, 'params': {'dim': 2048}}], 'functions': [], 'aliases': [], 'collection_id': 456228714208843162, 'consistency_level': 2, 'properties': {}, 'num_partitions': 1, 'enable_dynamic_field': True}
"""

删除集合

python">client.drop_collection('demo_collection')

三、数据操作

插入数据&更新数据

首先准备数据,进行向量化,刚才看到了一个其他向量化的东西,不需要key值,先弄来用用试试

python">from langchain_community.embeddings import TensorflowHubEmbeddings

# 向量化
embeddings = TensorflowHubEmbeddings()
text = "苹果"
query_result = embeddings.embed_query(text)
print(query_result, len(query_result))

运行过程会报错,按照报错,缺什么就安装什么。
结果是可用的,但是很慢,我也不确定是不是🪜的问题。
最好还是用之前的那个zhipu的embedding模型,反正有免费的Token数

创建collection时需要注意的是,zhipu那个embedding结果是2048维的。

python"># 创建milvus对象
from pymilvus import MilvusClient

client = MilvusClient()
client.using_database('test')

# 创建一个集合,维度使用向量化后的数据维度
client.create_collection(
    collection_name="collection1",
    dimension=len(query_result)
)

# 组装数据
data = {
    "id": 0,
    "vector": query_result,
    "text":"苹果"
}
# 插入数据
res = client.insert("collection1", data)
print(res)

在这里插入图片描述
在这里插入图片描述

可以看到数据已经成功添加
如果要插入多条数据,把data做成一个列表就行了。

python">data = [{
    "id": 1,
    "vector": [...]"text":"苹果手机"
}, {
    "id": 2,
    "vector": [...],
    "text":"菠萝手机"
}]
# 插入数据
res = client.insert("collection1", data)
print(res)

更新数据id不变,后面数据变一下,重新插入就好了

Milvus异步操作

在Milvus中,为了高性能运作,所以添加或更新数据的操作都是异步非阻塞的,对于刚添加入库的数据,有可能无法立即查询出来或者无法查询到最新的更新的数据。

python">data = [{
    "id": 3,
    "vector": [...]"text":"苹果"
}, {
    "id": 4,
    "vector": [...],
    "text":"菠萝手机"
},{
    "id": 5,
    "vector": [...],
    "text":"菠萝手机"
},]
# 插入数据
res = client.insert("collection1", data)
print(res)

# 刚插入或者刚修改的数据,是无法被查询到的。
res = client.get('collection1', ids=[3, 4, 5],output_fields=["id","text"])
print(res)

client.close()

"""
{'insert_count': 3, 'ids': [3, 4, 5]}
data: []
"""

查询数据

查询相关操作可以访问Milvus官网查阅更多:https://milvus.io/docs/get-and-scalar-query.md
下面只尝试了一下一些基本用法

查询单条数据

python">res = client.get('collection1', 0)

查询多条数据

python">res = client.get('collection1', [0,2])

基于pyhton运算过滤条件查询

python">res = client.query(
    collection_name="collection1",  # 集合名称
    # filter="id in [0,1,2]",  # python的运算符写查询过滤条件,但必须是字符串,而且内容必须符合python语法
    filter="id > 0",
    offset=1,  # 偏移量,开始下标+1
    limit=2,  # 结果限制条数2,限制返回指定数量的结果
    output_fields=["id", "vector"],  # 输出字段,*表示所有字段,可以指定想要的字段字段
)
print(res)

筛选搜索

也可以像SQL查询一样,模糊匹配查询

python">res = client.query(
    collection_name="collection1",  # 集合名称
    # filter="id in [0,1,2]",  # python的运算符写查询过滤条件,但必须是字符串,而且内容必须符合python语法
    filter="text like \"%手机\"",
    # offset=1,  # 偏移量,开始下标+1
    # limit=2,  # 结果限制条数2,限制返回指定数量的结果
    output_fields=["id", "text"],  # 输出字段,*表示所有字段,可以指定想要的字段字段
)
print(res)
"""
data: data: ["{'id': 1, 'text': '苹果手机'}", 
"{'id': 2, 'text': '菠萝手机'}", 
"{'id': 4, 'text': '苹果手机'}", 
"{'id': 5, 'text': '菠萝手机'}"]
"""

基本 近似最近邻 (ANN)搜索

python">query_vector = ...
res = client.search(
    collection_name="collection1",
    anns_field="vector",
    data=[query_vector],
    limit=2,
    search_params={"metric_type": "COSINE"}
)

for hits in res:
    for hit in hits:
        print(hit)

"""
{'id': 0, 'distance': 1.0, 'entity': {}}
{'id': 1, 'distance': 0.9998013377189636, 'entity': {}}
"""

这里我直接把第一个向量数据当做查询数据,进行查询。所以id=0的数据,和查询条件一模一样,余弦0,值就是1。

删除数据

查询条件的写法,与query的条件写法一致。

python">client.delete(
    collection_name="collection1",
    filter="id in [1, 8, 9] and text like \"%手机\""
)

四、字段操作

数据类型

Milvus中提供了Schema类用于定义集合的属性(CollectionSchema)和字段(FieldSchema)的属性。字段存储的数据按不同结构分不同数据类型,这些都是提前通过Schema来进行定义。首先了解关于数据类型部分的内容。

常量常数字段类型描述
BOOL1标量布尔类型
INT82标量8位整型
INT163标量16位整型
INT324标量32位整型
INT645主键,标量64位整型
FLOAT10标量单精度浮点型
DOUBLE11标量双精度浮点型
VARCHAR21主键,标量字符串类型,max_length=65,535
BINARY_VECTOR100向量二进制向量类型
FLOAT_VECTOR101向量32位单精度浮点数向量
FLOAT16_VECTOR102向量16位半精度浮点数向量
BFLOAT16_VECTOR103向量16位半精度浮点数向量,比FLOAT16_VECTOR显存占用量更小,精度更低。
SPARSE_FLOAT_VECTOR104向量稀疏向量,存储非零元素及其相应索引的列表
ARRAY22复合数组,就是python中的列表
JSON23复合json文档,就是python中的字典
NONE0空类型,无法设置为字段类型,milvus返回的格式,
UNKNOWN999未知类型,无法设置为字段类型,milvus返回的格式。

Milvus允许在创建schema时为每个标量字段指定默认值,从而减低插入数据的复杂性,但不包括主键字段。如果在插入数据时将字段留空,则将应用为此字段指定的默认值。

通过schema创建集合

python">from pymilvus import DataType
from pymilvus import MilvusClient

client = MilvusClient()


client.using_database('test')
# enable_dynamic_field=True 表示开启动态字段,开启后,除 id 和 vector 之外的所有字段都被视为动态字段。
# 这些额外的字段被保存为在名为 $meta 的特殊字段内的键值对。在后面的操作当前集合的数据时允许在插入数据时包含未定义的额外字段。
schema = client.create_schema(enable_dynamic_field=True)

# schema.add_field(field_name="字段名", datatype=DataType.字段类型, is_primary=True, auto_id=True, description="字段描述"), # 设置主键字段
# schema.add_field(field_name="字段名", datatype=DataType.字段类型, default_value=默认值, dim=维度, description="字段描述"),
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=5)

index_params = client.prepare_index_params()
# 当把索引设置为AUTOINDEX,则表示将来这里的索引类型是根据存储内容来自动识别。
index_params.add_index(field_name="vector",index_type="AUTOINDEX",metric_type="COSINE")
collection = client.create_collection(
    collection_name="test_01", # 集合名称
    schema=schema, # 字段参数
    index_params=index_params,  # 索引参数
)

在这里插入图片描述

五、索引

索引是提高数据检索效率的关键技术。在 Milvus 中,索引用于加速向量数据的搜索过程。通过索引,可以快速定位到与查询向量最相似的数据向量。

索引类型

Milvus 提供了多种索引类型对字段值进行排序,以实现高效的相似性搜索。

索引适用场景
FLAT原始文件索引,适合在小型、百万级数据集上寻求完全准确和精确搜索结果的,且需要100%召回率的场景。
IVF_FLAT基于量化的索引倒排文件索引,适合寻求在准确性和查询速度之间取得理想平衡的场景。GPU_IVF_FLAT是IVF_FLAT的GPU版本实现。
IVF_SQ8基于量化的索引适合寻求显著减少磁盘、CPU和GPU内存消耗的场景
IVF_PQ基于量化的索引适合寻求高查询速度,即使以牺牲准确性为代价的场景。GPU_IVF_PQ是IVF_PQ的GPU版本实现。
HNSW基于图的索引适合对搜索效率有高要求的场景

注意:

Milvus 目前仅支持对向量和标量字段创建索引。其中给向量字段建立的索引叫向量索引,同理,给标量字段创建的索引叫标量索引。

建议对经常使用的向量字段和标量字段创建索引。
Milvus 目前只支持为集合的每个字段创建一个索引文件。注意:是一个字段只能设置一个索引,不是一个集合只有一个索引!!

Milvus 还提供三种度量类型:余弦相似度 (COSINE)、欧几里得距离 (L2) 和内积 (IP,Inner Product)来测量向量嵌入之间的距离。

常用度量方法参考:https://blog.csdn.net/qq_42222846/article/details/145829907

删除索引

在这里插入图片描述
因为之前创建集合时默认是有索引的,先删除

python">client.release_collection('test_01')  # 先从内存中释放数据
client.drop_index(
    collection_name="test_01",
    index_name="vector"
)

删除完成后就变成没有索引了
在这里插入图片描述

创建索引

python">
index_params = client.prepare_index_params()

index_params.add_index(
    collection_name="test_01",
    field_name="vector",
    index_params=index_params,
    metric_type="L2",
    index_type="IVF_FLAT",
    params={"nlist": 100},  # list,分区设置
)

client.create_index(collection_name='test_01', index_params=index_params)
# 创建完索引以后,需要手动加载下集合
client.load_collection(collection_name='test_01')

创建完成后就是我们设置的索引了
在这里插入图片描述

查看索引

python">res = client.describe_index(
     collection_name="test_01",
     index_name="vector"
 )

print(res)

"""
{'nlist': '100', 
'index_type': 'IVF_FLAT', 
'collection_name': 'test_01',
'index_params': "[{'field_name': 'vector', 'index_type': 'IVF_FLAT', 'index_name': '', 'collection_name': 'test_01', 'index_params': <pymilvus.milvus_client.index.IndexParams object at 0x1278cffd0>, 'metric_type': 'L2', 'params': {'nlist': 100, 'index_type': 'IVF_FLAT', 'collection_name': 'test_01', 'index_params': <pymilvus.milvus_client.index.IndexParams object at 0x1278cffd0>, 'metric_type': 'L2'}}]", 
'metric_type': 'L2', 
'field_name': 'vector',
'index_name': 'vector', 
'total_rows': 0, 
'indexed_rows': 0, 
'pending_index_rows': 0, 
'state': 'Finished'}
"""

六、结合智谱AI向量化存储Milvus,再查询

1. 向量化,存储

python">import os

os.environ["ZHIPUAI_API_KEY"] = "a22568xxx"

from langchain_community.embeddings import ZhipuAIEmbeddings
embeddings = ZhipuAIEmbeddings(
    model="embedding-3",
    dimensions=1024
)

data = [
    "欢迎来到成都。",
    "欢迎来到重庆。",
    "欢迎来到北京。",
    "我喜欢成都。",
    "你是重庆人吗?"
]
embeddings = embeddings.embed_documents(data)
data = [{"vector": item} for item in embeddings]

# 创建milvus对象,操作数据集
from pymilvus import MilvusClient

client = MilvusClient()
client.using_database('test')

from pymilvus import DataType

schema = client.create_schema(enable_dynamic_field=True)
schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True),
schema.add_field(field_name="vector", datatype=DataType.FLOAT_VECTOR, dim=1024)  # 与上面embedding模型得到的dim值保持一致

index_params = client.prepare_index_params()
index_params.add_index(field_name="vector", index_type="IVF_FLAT", metric_type="L2", nlist=128)
collection = client.create_collection(
    collection_name="my_collection",  # 集合名称
    schema=schema,  # 字段参数
    index_params=index_params,  # 索引参数
)

client.load_collection('my_collection')

# 把zhipu ai向量化的数据存储起来
client.insert(collection_name='my_collection', data=data)

client.close()

在这里插入图片描述
可以看到数据被存起来了。度量方式是L2
在这里插入图片描述

2.模拟用户查询(L2)

python"># -*- coding: utf-8 -*-
# @Author : John
# @Time : 2025/02/25
# @File : query.py

import os
from pymilvus import MilvusClient

os.environ["ZHIPUAI_API_KEY"] = "a225xxx"

client = MilvusClient()

# 切换数据库
client.using_database('test')

# 把要查询的内容转换嵌入变量


from langchain_community.embeddings import ZhipuAIEmbeddings

embeddings = ZhipuAIEmbeddings(
    model="embedding-3",
    dimensions=1024
)
# 把用户查询的数据向量化
query_sentence_embedding = embeddings.embed_query("欢迎来到深圳")

# 到milvus中查询
search_params = {
    "metric_type": "L2",  # 因为集合中的索引使用的就是L2(欧氏距离),所以我们这里必须写成欧式距离
    "params": {}
}
result = client.search(
    collection_name="my_collection",
    data=[query_sentence_embedding],
    search_params=search_params
)

print(result)
client.close()

得到结果如下

python">{'id': 456235719503916998, 'distance': 0.23892742395401, 'entity': {}}, 
{'id': 456235719503916999, 'distance': 0.24597115814685822, 'entity': {}}, 
{'id': 456235719503917000, 'distance': 0.2479812204837799, 'entity': {}}, 
{'id': 456235719503917001, 'distance': 0.43177342414855957, 'entity': {}}, 
{'id': 456235719503917002, 'distance': 0.47823566198349, 'entity': {}}]
python">存储的数据:
    "欢迎来到成都。",
    "欢迎来到重庆。",
    "欢迎来到北京。",
    "我喜欢成都。",
    "你是重庆人吗?"
查询的数据:
	"欢迎来到深圳"

可以看出,查询的这句话,与前三句很相近,只有2个字不同,而和下面2句差距就比较大。输出的结果也是如此。
L2距离查询,也就是两点之间的距离,越小就越相近。

milvus_547">七、通过LangChain调用milvus

python"># 1.初始化嵌入模型
import os
os.environ["ZHIPUAI_API_KEY"] = "a2256xxx"

from langchain_community.embeddings import ZhipuAIEmbeddings
embeddings_model = ZhipuAIEmbeddings(
    model="embedding-3",
    dimensions=1024
)

# 2. Milvus数据库配置
milvus_host = "127.0.0.1"  # Milvus服务器的主机名或IP地址
milvus_port = "19530"  # Milvus服务器的端口
collection_name = "my_collection"  # 数据集合的名称

# 3. 初始化Milvus向量存储【
from langchain_milvus import Milvus
vector_store = Milvus(
    embedding_function=embeddings_model,  # 指定嵌入模型
    collection_name=collection_name,
    connection_args={"host": milvus_host, "port": milvus_port},
    auto_id=True,  # 设置集合中的数据为自动增长ID,默认是False
    # primary_field="id",  # 设置主键名称,默认是id,可以不改
)

# 4.嵌入文本数据并存储到Milvus
texts = [
    "小红是公司财务。",
    "小张是开发人员。",
    "小刘是前台。"
]
from langchain.schema import Document
documents = [Document(page_content=text, metadata={'tid': key}) for key,text in enumerate(texts)]
vector_store.add_documents(documents)


# 5. 查询并搜索相似文本
query = "公司的前台是谁?"
embedded_query = embeddings_model.embed_query(query)
# 打印搜索结果【1个结果】
# print(embedded_query)

# 使用Milvus进行相似度搜索
search_results = vector_store.similarity_search(query)
# 6. 打印搜索结果【多个结果】,第一个是相似度最高的结果
for result in search_results:
    print("相关文本:", result.page_content, result.metadata)

"""
相关文本: 小刘是前台。 {'tid': 2, 'pk': 456235719503917023}
相关文本: 小红是公司财务。 {'tid': 0, 'pk': 456235719503917021}
相关文本: 小张是开发人员。 {'tid': 1, 'pk': 456235719503917022}
"""

更换问题后,相似度计算靠前的答案也更改了。

python">....
query = "谁是公司的财务?"
...
"""
相关文本: 小红是公司财务。 {'pk': 456235719503917021, 'tid': 0}
相关文本: 小刘是前台。 {'pk': 456235719503917023, 'tid': 2}
相关文本: 小张是开发人员。 {'pk': 456235719503917022, 'tid': 1}
"""

常用的距离度量方法

如文中出现的 L2, COSIN等这些

可以参考:https://blog.csdn.net/qq_42222846/article/details/145829907


http://www.niftyadmin.cn/n/5868944.html

相关文章

本地部署deepseek大模型后使用c# winform调用(可离线)

介于最近deepseek的大火&#xff0c;我就在想能不能用winform也玩一玩本地部署&#xff0c;于是经过查阅资料&#xff0c;然后了解到ollama部署deepseek,最后用ollama sharp NUGet包来实现winform调用ollama 部署的deepseek。 本项目使用Vs2022和.net 8.0开发&#xff0c;ollam…

矩阵的 正定(Positive Definite)与负定(Negative Definite):从Fisher信息矩阵看“曲率”的秘密

矩阵的正定与负定&#xff1a;从Fisher信息矩阵看“曲率”的秘密 在数学和统计学中&#xff0c;矩阵的“正定性”和“负定性”是一对重要概念&#xff0c;尤其在优化、统计推断和机器学习中频繁出现。比如&#xff0c;Fisher信息矩阵&#xff08;Fisher Information Matrix, F…

STM32 缺一不可的最基础的初始化部分

STM32 缺一不可的最基础的初始化部分 初始化部分必须初始化作用关键配置系统时钟&#xff08;RCC&#xff09;​所有STM32程序的基础为CPU、总线和外设提供时钟信号1.选择时钟源&#xff08;HSI/HSE/PLL&#xff09; 2.配置系统时钟频率&#xff08;如168MHz&#xff09; 3.使…

数据结构(陈越,何钦铭) 第四讲 树(中)

4.1 二叉搜索树 4.1.1 二叉搜索树及查找 Position Find(ElementTyoe X,BinTree BST){if(!BST){return NULL;}if(X>BST->Data){return Find(X,BST->Right)}else if(X<BST->Data){return Find(X,BST->Left)}else{return BST;} } Position IterFind(ElementTyp…

C++中,关于用 size_t 还是用 int,永远要统一标准。

看以下例子&#xff1a; template<class T> class MyArray {public:T* _pData null; //指针&#xff0c;指向第一个元素size_t _nElementCount 0; //无素个数public:MyArray(const T* pt, const int nLen) { }size_t length() const { return _nElementCount…

HAProxy- https、四层负载实现与 负载均衡关键技术

目录 1、HAProxy实现四层负载 四层负载示例 ACL示例-四层访问控制 2、HAProxy- https实现 HAProxy https实现 证书制作 https配置示例 修改后端服务器的日志格式 验证https 3、 负载均衡关键技术 1、什么是 Session 2、什么是 Session 共享 1、基于 Cookie 的 Ses…

python爬虫学习第十一篇爬取指定类型数据

最近在学习Python爬虫的过程中&#xff0c;尝试用爬虫获取指定类型的数据。今天&#xff0c;我想和大家分享一下我的实践过程和遇到的问题。 一、实现目标 目标是从一个网站的API接口获取不同类型的食品数据。 比如&#xff0c;第一步我想获取汉堡、小食、甜品等不同类型的数…

ROS的action通信——实现阶乘运算(三)

在ROS中除了常见的话题(topic&#xff09;通信、服务(server)通信等方式&#xff0c;还有action通信这一方式&#xff0c;由于可以实时反馈任务完成情况&#xff0c;该通信方式被广泛运用于机器人导航等任务中。本文将通过三个小节的分享&#xff0c;实现基于action通信的阶乘运…