赞
踩
https://www.modb.pro/db/509268
笔记︱几款多模态向量检索引擎:Faiss 、milvus、Proxima、vearch、Jina等 - 知乎 (zhihu.com)
向量数据库入坑指南:聊聊来自元宇宙大厂 Meta 的相似度检索技术 Faiss - 苏洋的文章 - 知乎
向量检索技术,其主要的应用领域如人脸识别、推荐系统、图片搜索、视频指纹、语音处理、自然语言处理、文件搜索
向量检索需要用到向量数据库,而普通的关系型数据库(如 MySQL、PostgreSQL)通常不适合处理向量检索任务。这是因为**【向量检索有其特殊的需求和性能要求】**。
原因如下:
1、向量检索的特性
2、普通数据库的限制
3、向量数据库的优势
向量数据库(如 FAISS、Milvus、Annoy、Weaviate 等)专门为向量检索设计,具备以下优势:
4、结论
向量数据库通过专门的索引结构、优化的相似性计算以及分布式支持,显著提高了高维向量相似性检索的效率和扩展性。因此,对于需要处理大规模向量数据的应用场景(如推荐系统、图像搜索、自然语言处理等),使用向量数据库是更好的选择。
索引类型 | 原理 | 特点 | 适用场景 | 优点 | 缺点 |
---|---|---|---|---|---|
FLAT | 线性扫描: 直接对所有向量进行线性扫描,计算每个向量与查询向量之间的距离。 | 精确度高,速度较慢。 | 小规模数据集或对精度要求非常高的场景。 | 精度高,因为计算了每个可能的距离。 | 对于大数据集,速度非常慢。 |
IVF | 簇划分: 将向量数据集分为多个簇(clusters),然后在这些簇内搜索。 【Inverted File Index】 | 通过缩小搜索范围加速查询。搜索分两步:先找到最相关的簇,再在簇内搜索。 | 中大规模数据集,平衡速度和精度。 | 加速搜索速度,平衡速度和精度。 | 精度稍低于 FLAT。 |
PQ | 子空间划分: 将向量分成多个子空间 量化: 每个子空间独立量化,减少存储和计算复杂度。 【Product Quantization】 | 存储效率高,查询速度快。精度有损,但通常可接受。 | 大规模数据集,对存储和查询速度要求高的场景。 | 存储效率高,查询速度快。 | 量化带来精度损失。 |
HNSW | 多层图结构: 构建一个包含多个层次的小世界图 导航搜索: 从高层次开始,逐层向下搜索,直到找到最近邻。 【Hierarchical Navigable Small World】 | 高查询效率和精度,支持动态更新。 | 高效查询,动态更新的大规模数据集。 | 高效的查询速度和高精度。 | 构建和维护图结构复杂,内存消耗较大。 |
LSH | 哈希映射: 将相似的向量映射到相同的哈希桶。 【Locality-Sensitive Hashing】 | 适用于高维数据,但精度相对较低。 | 高维数据的近似最近邻搜索。 | 适用于高维数据,查询速度快。 | 精度相对较低。 |
ANNOY | 随机投影树: 构建多棵树,每棵树基于不同的随机投影。 【Approximate Nearest Neighbors Oh Yeah】 | 平衡了搜索速度和精度。 | 大规模数据集。 | 平衡速度和精度。 | 构建时间较长。 |
IVF-PQ | 簇划分和量化: 结合 IVF 和 PQ,将向量数据集分为多个簇,并在每个簇内进行量化。 【Inverted File with Product Quantization】 | 进一步优化存储和查询效率。 | 大规模数据集,需要存储和查询效率优化的场景。 | 存储和查询效率进一步优化。 | 构建和维护较复杂。 |
ScaNN | 结合量化和排序: 结合矢量量化和距离排序等技术。 【Scalable Nearest Neighbors】 | 在处理大规模数据集时表现出色。 | 大规模数据集。 | 在大规模数据集上表现出色。 | 算法复杂度较高。 |
——from ChatGPT
以下是主流向量数据库的对比:
数据库 | 发布者 | 时间 | 功能 | 优点 | 缺点 |
---|---|---|---|---|---|
Milvus | Zilliz (阿里巴巴孵化) | 2019 | 多模态检索,分布式架构,数据持久化,查询优化 | 高性能,多模态支持,易用性强 | 部分功能依赖商业支持 |
FAISS | Facebook AI Research | 2017 | 多种索引类型,内存高效利用,GPU 加速 | 高性能(尤其在 GPU 环境),灵活性强,社区支持丰富 | 持久化和分布式支持较弱,使用门槛较高 |
Annoy | Spotify | 2014 | 随机投影树,读多写少,支持磁盘持久化 | 简单易用,支持磁盘持久化 | 写操作不高效,扩展性有限 |
NMSLIB | 非官方开源项目 | 2013 | 多种近似最近邻算法,高性能,多语言绑定 | 性能优秀,灵活性强 | 文档和社区支持较少,缺乏商业支持 |
Weaviate | SeMI Technologies | 2019 | 分布式搜索,知识图谱,RESTful API 和 GraphQL 支持 | 上下文感知,结合知识图谱提供智能搜索,支持分布式和大规模数据 | 部分功能依赖外部服务和插件,社区生态较新 |
Pinecone | Pinecone.io | 2020 | 商业化托管服务,多种索引,自动扩展,实时更新 | 全托管服务,高可靠性,良好文档和客户支持 | 使用成本高,部分功能需要付费订阅 |
Qdrant | Qdrant | 2021 | 高性能搜索,实时更新,分布式架构,数据持久化 | 高性能,实时更新,易用性强,支持分布式和持久化 | 分布式功能较新,社区生态正在发展 |
—— ChatGPT
Milvus 是一个功能强大、支持多模态和分布式架构的向量数据库,适用于需要处理大规模、多样化数据的场景。
FAISS 则以其高性能和灵活性著称,特别适合需要高效向量检索和 GPU 加速的场景。选择合适的向量数据库需要根据具体的应用需求、数据规模和性能要求来决定。
向量数据库 | GitHub Star 数量 | GitHub Fork 数量 | 社区活跃度 | 使用情况及活跃度 |
---|---|---|---|---|
Milvus | 14k+ | 2k+ | 高 | 使用情况:广泛应用于多模态检索、推荐系统等领域。 社区活跃度:活跃,有定期更新和活跃的社区支持。 |
FAISS | 22k+ | 4k+ | 高 | 使用情况:被广泛用于研究和工业界的高性能向量检索任务,尤其在 GPU 环境下。 社区活跃度:非常活跃,有广泛的文档和社区支持。 |
Annoy | 11k+ | 1k+ | 中 | 使用情况:常用于推荐系统和音乐检索,尤其适合读多写少的场景。 社区活跃度:活跃,维护较好,但更新频率相对较低。 |
NMSLIB | 3k+ | 800+ | 中 | 使用情况:用于各种高性能向量检索任务,支持多种算法。 社区活跃度:活跃,有一定的用户基础和贡献者,但相对较小。 |
Weaviate | 2k+ | 300+ | 中 | 使用情况:适用于知识图谱和上下文感知的检索场景。 社区活跃度:活跃,但由于是相对较新的项目,用户基础和生态正在发展中。 |
Pinecone | 无公开仓库 | 无公开仓库 | 高(商业服务) | 使用情况:被多家企业用于生产环境中的向量检索任务。 社区活跃度:高,通过商业支持和客户服务提供持续的更新和支持。 |
【向量数据库】
【支持高效的向量检索】Milvus 采用了高效的算法和数据结构,如倒排索引、HNSW、量化等,优化搜索性能和存储效率,适合于机器学习、人工智能和相似性搜索的应用场景。
【高度可扩展】Milvus 支持容器化部署(如 Kubernetes)
【易用性和灵活性】【强大的社区支持】
https://milvus.io/docs/v2.2.x
Milvus 是由 Zilliz 开发并开源的高性能分布式向量数据库,最初是由阿里巴巴孵化,旨在处理大规模、多模态的向量检索任务。Milvus 是 LF AI & Data 基金会的托管项目之一。
【多模态向量检索支持】
【分布式架构】
Milvus 的架构主要由以下几个组件组成:
【节点】
query node 负责查询,data node 负责数据写入和持久化、index node负责索引建立和加速查询
the query node is in charge of data query; the data node is responsible for data insertion and data persistence; and the index node mainly deals with index building and query acceleration.
The design principles of Milvus 2.0
数据流程
【logs --> log snapshot --> segment】
Both the table and the log are data, In the case of Milvus, it aggregates logs using a processing window from TimeTick. Based on log sequence, multiple logs are aggregated into one small file called log snapshot. Then these log snapshots are combined to form a segment, which can be used individually for load balance.
第三方依赖:MinIO, etcd, and Pulsar.
Milvus cluster includes eight microservice components and three third-party dependencies: MinIO, etcd, and Pulsar.
Storage层有三个部分组成:
Meta store、Log broker、Object storage
Reference
**数据写入和数据持久化:**https://milvus.io/blog/deep-dive-4-data-insertion-and-data-persistence.md
加载数据到内存(实时查询):https://milvus.io/blog/deep-dive-5-real-time-query.md#Load-data-to-query-node
1、数据写入:可以为每个 collection 设置分片数量(每个分片对应一个虚拟通道 vchannel),数据将根据主键的哈希值写入相应的分片。
You can specify a number of shards for each collection in Milvus, each shard corresponding to a virtual channel (vchannel). Any incoming insert/delete request is routed to shards based on the hash value of primary key.
当segment满了,会自动出发data flush (512 MB by default)
三种类型的segment
2、索引建立:index node 从segmeng中将数据加载到内存,建立索引后再写回 object storage
The index node loads the log snapshots to index from a segment (which is in object storage) to memory , deserializes the corresponding data and metadata to build index, serializes the index when index building completes, and writes it back to object storage.
向量检索维度太高,传统基于树的索引不再适应,取而代之的有基于聚类和基于图的索引。
Vectors cannot be efficiently indexed with traditional tree-based indexes due to their high-dimensional nature, but can be indexed with techniques that are more mature in this subject, such as cluster- or graph-based indexes.
3、查询:query node在加载到内存的segment中执行查询
A collection in Milvus is split into multiple segments, and the query nodes loads indexes by segment.
每个query 节点只负责两个任务:按照 query coord 的指令加载或释放段;在本地段中进行搜索。
Each node is responsible only for two tasks: Load or release segments following the instructions from query coord; conduct a search within the local segments.
有两种类型的segment: growing segments 和sealed segments
There are two types of segments, growing segments (for incremental data), and sealed segments (for historical data). Query nodes subscribe to vchannel to receive recent updates (incremental data) as growing segments.
两只类型的数据被加载到query node : growing segments 和sealed segments
There are two types of data that are loaded to query node: streaming data from log broker, and historical data from object storage (also called persistent storage below).
query node 1从持久化存储中加载历史数据S1,从订阅日志代理中的channel 1加载G1
In query node 1 in the image, historical data (batch data), are loaded via the allocated S1 and S3 from persistent storage. In the meanwhile, query node 1 loads incremental data (streaming data) by subscribing to channel 1 in log broker.
In Milvus, a collection is equivalent to a table in a relational database management system (RDBMS)
数据存储在集合(Collection)中,每个集合包含多个实体(Entity),每个实体包含多个字段(Field),但最重要的是向量字段(Vector Field)。
【分组存储】: 将不同类型的数据分别存储在不同的 collections 中。例如,一个用于存储图像特征向量的 collection,另一个用于存储文本特征向量的 collection。
索引构建由索引节点完成。为了避免数据更新时频繁构建索引,Milvus 中的集合被进一步划分为多个段,每个段都有自己的索引。
Schema 用于定义集合的属性以及集合中字段。
Milvus 一个集合中仅支持一个主键字段。
Reference: 字段架构属性
https://milvus.io/docs/schema.md
【Query Node】
Milvus 将一个集合拆分成多个 Segment,查询节点按 Segment 加载索引。当搜索请求到达时,会广播到所有查询节点并发搜索。然后每个节点剪枝本地 Segment,搜索符合条件的向量,并缩减后返回搜索结果。
Knowhere 是 Milvus 的核心向量执行引擎,它整合了多个向量相似性搜索库,包括Faiss、Hnswlib和Annoy。 Knowhere 还旨在支持异构计算。它控制在哪个硬件(CPU 或 GPU)上执行索引构建和搜索请求。
Milvus 支持的向量索引类型大多采用近似最近邻搜索(ANNS)算法。相较于通常非常耗时的精确检索,ANNS 的核心思想不再局限于返回最精确的结果,而是只搜索目标的邻居。ANNS 通过在可接受的范围内牺牲准确率来提高检索效率。
优点:
缺点:
使用场景:推荐系统、图像搜索、文本检索、视频检索等。
Milvus 应用场景示例:电商平台的多模态商品搜索
场景描述: 某大型电商平台需要提供多模态商品搜索功能,包括基于图像、文本和视频的搜索。用户可以通过上传图片、输入文本描述或提供视频片段来查找相似的商品。平台需要处理海量商品数据,支持高并发的搜索请求,并提供实时更新和持久化存储。
具体应用:
Milvus 的优势:
插入操作和查询操作是分离的吗?
插入操作和查询操作由两个相互独立的模块处理。从客户端的角度来看,当插入的数据进入消息队列时,插入操作就完成了。但是,插入的数据在加载到查询节点之前是不可搜索的。如果段大小未达到索引构建阈值(默认为 512 MB),Milvus 将诉诸暴力搜索,查询性能可能会降低。
Milvus 会将重复主键视为更新操作吗?
不会。Milvus 目前不支持更新操作,也不检查实体主键是否重复。您有责任确保实体主键是唯一的,如果不是,Milvus 可能包含多个具有重复主键的实体。
Faiss is a library for efficient similarity search and clustering of dense vectors.
C++ 开发的,一些有用的算法要在GPU上实现
FAISS(Facebook AI Similarity Search)是由 Facebook AI Research 开发的高效向量相似性搜索库,旨在处理大规模、高维向量数据的相似性搜索任务。
FAISS 的架构相对简单,由以下几个核心组件组成:
优点:
缺点:
数据持久化和分布式支持较弱的原因
核心:它能够实现“高性能向量检索”的原因
数据类型:Faiss只使用32位浮点矩阵(32-bit floating)。
Faiss 也能够指定数据类型,比如 IndexFlatL2、IndexHNSW、IndexIVF等二十来种类型
使用场景:推荐系统、图像搜索、文本检索、生物信息学等。
FAISS 应用场景示例:研究机构的大规模基因相似性分析
场景描述: 某研究机构需要进行大规模基因数据的相似性分析,比较数百万条基因序列之间的相似性,以发现潜在的基因关联和突变模式。系统需要高效的计算能力,以在合理时间内完成大规模的相似性计算。
具体应用:
FAISS 的优势:
Elasticsearch 是一个开源的分布式搜索和分析引擎,主要用于全文搜索、结构化搜索、日志和数据分析。尽管 Elasticsearch 强大且多功能,但在替代 Milvus 或 FAISS 用于向量检索方面有其局限性。
Elasticsearch 引入了向量检索功能,通过插件(如 Elasticsearch k-NN 插件)或直接支持向量字段(如 dense_vector 类型)来实现向量相似性搜索。以下是它在向量检索方面的特点:
具体来说,处理大规模高维向量数据时,Elasticsearch 的性能瓶颈会因数据规模和具体的检索需求而有所不同。然而,可以提供一些指导性的数据规模和考虑因素,帮助判断何时应该使用专门设计的向量数据库(如 Milvus 或 FAISS)而不是 Elasticsearch。
高维向量数据(如 128 维、256 维甚至更高)需要更多的计算资源来进行相似性计算。一般来说,当向量维度超过 100 时,就需要考虑优化计算性能的方案。
数据集的规模在向量数量上也是一个关键因素。如果数据集中有数百万到数亿的向量,Elasticsearch 在进行高效检索时可能会遇到性能瓶颈。在这种情况下,专门的向量数据库可能更适合。
对于实时性要求高、并发请求量大的应用场景,Elasticsearch 的性能可能无法满足要求。专门的向量数据库(如 Milvus 和 FAISS)在设计上更适合这种高并发、低延迟的需求。
!!!传统数据库和向量数据库的显著区别在哪里?
传统数据库重IO,向量数据库则需要大量计算资源
传统数据库:
向量数据库:
使用
# 构建索引
import faiss # make faiss available
index = faiss.IndexFlatL2(d) # build the index
print(index.is_trained)
index.add(xb) # add vectors to the index
print(index.ntotal)
# 搜索
k = 4 # we want to see 4 nearest neighbors
D, I = index.search(xb[:5], k) # sanity check 输入为query embeddig和neighbors数
https://faiss.ai/
https://ai.meta.com/tools/faiss/
https://github.com/facebookresearch/faiss/wiki
https://github.com/facebookresearch/faiss/wiki/Faiss-indexes
example Reference
How to Use FAISS to Build Your First Similarity Search-medium
Reference
Milvus性能优化提速之道:揭秘优化技巧,避开十大误区- 知乎
https://github.com/milvus-io/pymilvus/tree/2.2/examples
在 Milvus 中,collection
和 index
是两个核心概念,它们分别负责数据存储和数据检索的组织和优化。
from pymilvus import CollectionSchema, FieldSchema, DataType, Collection
# 定义字段
id_field = FieldSchema(name="id", dtype=DataType.INT64, is_primary=True)
vector_field = FieldSchema(name="vector", dtype=DataType.FLOAT_VECTOR, dim=128)
# 定义 schema
schema = CollectionSchema(fields=[id_field, vector_field], description="example collection")
# 创建 collection
collection = Collection(name="example_collection", schema=schema)
index_params = {
"index_type": "IVF_FLAT",
"params": {"nlist": 128},
"metric_type": "L2"
}
collection.create_index(field_name="vector", index_params=index_params)
通过理解 collection 和 index 的概念及其功能,可以更好地在 Milvus 中组织和优化向量数据的存储和检索。
# 查看index
from pymilvus import Collection
collection = Collection("book") # Get an existing collection.
# 查看collection
collection.schema # Return the schema.CollectionSchema of the collection.
collection.description # Return the description of the collection.
collection.name # Return the name of the collection.
collection.is_empty # Return the boolean value that indicates if the collection is empty.
collection.num_entities # Return the number of entities in the collection.
collection.primary_field # Return the schema.FieldSchema of the primary key field.
collection.partitions # Return the list[Partition] object.
collection.indexes # Return the list[Index] object.
collection.properties # Return the expiration time of data in the collection.
Milvus 中的所有搜索和查询操作都是在内存中执行的。因此在执行搜索或查询之前需要将集合加载到内存。
这个加载过程发生在Milvus服务所在的服务器上,而不是客户端。
# Get an existing collection.
collection = Collection("book")
collection.load(replica_number=2)
utility.loading_progress("book")
# Output: {'loading_progress': 100%}
在搜索或查询之后从内存中释放集合以减少内存使用量。
from pymilvus import Collection
collection = Collection("book") # Get an existing collection.
collection.release()
from pymilvus import Collection collection = Collection("book") # Get an existing collection. mr = collection.insert(data) # 批量插入 API # 使用 NumPy 数组将数据集的每一列组织到单独的文件中。在这种情况下,使用每列的字段名称来命名 NumPy 文件。 from pymilvus import utility task_id = utility.do_bulk_insert( collection_name="book", partition_name="2022", files=["book_id.npy", "word_count.npy", "book_intro.npy", "book_props.npy"] ) def flush_collection(self): """ 刷新数据 """ self.collection.load() # 这个方法用于将 collection 加载到内存中,以便进行查询,如果 collection 已经在内存中,则此操作不会重复加载。 self.collection.flush() # 这个方法用于将内存中的数据刷新到磁盘上,确保所有在内存中的变更(例如插入或删除操作)都持久化到磁盘。 logger.info("Success flush collection")
当插入的数据加载到消息队列中时,Milvus 返回成功,但数据还未刷入磁盘。此时,Milvus 的数据节点会将消息队列中的数据以增量日志的形式写入持久化存储。如果flush()
调用,则强制数据节点立即将消息队列中的所有数据写入持久化存储。如果您**需要在插入后立即搜索数据**,则可以在数据插入后调用该flush()
方法。
Milvus 会自动触发该
flush()
操作。大多数情况下,无需手动调用此操作。
如果需要**全量更新一个 Collection** 的数据,推荐使用新建表 + 导入数据 + Alias 切换的方案
import os import sys from loguru import logger from pymilvus import ( connections, FieldSchema, CollectionSchema, DataType, Collection, utility, BulkInsertState ) class MilvusHandler: def __init__( self, host=MILVUS_HOST, port=MILVUS_PORT ): self.host = host self.port = port self.connect() def connect(self): connections.connect("default", host=self.host, port=self.port) logger.info("Successfully connected to Milvus") @staticmethod def disconnect(): # 断开连接 connections.disconnect("default") logger.info("Successfully disconnected from Milvus") def create_collection(self, collection_name=None, collection_dim=None): # 初始化 Collection 对象 if self.has_collection(collection_name=collection_name): collection = Collection(name=collection_name) logger.info(f"Connected to existing collection:{collection_name}") else: fields = [ FieldSchema(name="id", dtype=DataType.VARCHAR, description="text name", max_length=500, is_primary=True, auto_id=False), FieldSchema(name="vec", dtype=DataType.FLOAT_VECTOR, description="text embedding vectors", dim=collection_dim) ] schema = CollectionSchema(fields, "Collection for text embeddings") collection = Collection(name=collection_name, schema=schema, using='default') self.create_index(collection=collection, filed_name="vec") logger.info(f"Successfully created collection :{collection_name}") return collection @staticmethod def create_alias(collection_name, alias): utility.create_alias(collection_name=collection_name, alias=alias) @staticmethod def drop_alias(alias): utility.drop_alias(alias=alias) @staticmethod def drop_collection(collection_name): utility.drop_collection(collection_name) logger.info(f"Dropped collection: {collection_name}") def has_collection(self, collection_name): return utility.has_collection(collection_name) @staticmethod def list_collections(): collections = utility.list_collections() logger.info(f"List of collections: {collections}") return collections @staticmethod def create_index(collection, filed_name=None, index_param=None): if not index_param: index_param = { "index_type": "FLAT", "metric_type": "IP", "params": {} } collection.create_index(filed_name, index_param) logger.info(f"Success create index") @staticmethod def drop_index(collection): collection.drop_index() logger.info(f"Success drop index") @staticmethod def load_collection(collection): collection.load() @staticmethod def flush_collection(collection): collection.flush() @staticmethod def load_and_flush_collection(collection): """ 刷新数据 """ # 测试加载速度 import time start_time = time.time() collection.load() end_time = time.time() print(f"Loading time: {end_time - start_time} seconds") collection.flush() logger.info("Success flush collection") @staticmethod def release_collection(collection): """释放内存中加载的collection""" collection.release() logger.info("Success release collection") @staticmethod def compact_collection(collection): """合并segement""" collection.compact() logger.info(f" release collection status:{collection.get_compaction_state()}") @staticmethod def insert_entity(collection, entities): """ 单次写入小于 10MB 以下,建议选择流式写入 """ # entities = [ # {"name": "id", "values": ids, "type": DataType.VARCHAR}, # {"name": "vec", "values": vectors, "type": DataType.FLOAT_VECTOR} # ] mr = collection.insert(entities) # (insert count: 10, delete count: 0, upsert count: 0, timestamp: {self._timestamp}, success count: {self.succ_count}, err count: {self.err_count}) logger.info(f"Data inserted successfully.{mr}") return mr @staticmethod def bulk_insert(collection_name=None, files: list = ["id.npy", "vec.npy"]): """ BulkInsert 不会对查询性能造成太大的影响 :param collection_name: :param files: :return: """ task_id = utility.do_bulk_insert( collection_name=collection_name, files=files ) task = utility.get_bulk_insert_state(task_id=task_id) print("Task state:", task.state_name) print("Imported files:", task.files) print("Collection name:", task.collection_name) print("Partition name:", task.partition_name) print("Start time:", task.create_time_str) print("Imported row count:", task.row_count) print("Entities ID array generated by this task:", task.ids) if task.state == BulkInsertState.ImportFailed: print("Failed reason:", task.failed_reason) @staticmethod def delete_entity(collection, ids): expr = f'id in {ids}' dr = collection.delete(expr) logger.info(f"Data deleted successfully.{dr}") return dr def update_entity(self, ids, collection, vectors): self.delete_entity(collection, ids) self.insert_entity(collection, entities=[ids, vectors]) logger.info(f"Data update successfully") @staticmethod def get_entity_num(collection): entity_num = collection.num_entities logger.info(f"Number of entities: {entity_num}") return entity_num @staticmethod def search(collection, query_vector, top_k=10): # "param": {"metric_type": "IP", "params": {"nprobe": _NPROBE}}, search_param = { "data": [query_vector], "anns_field": "vec", "param": {"metric_type": "IP"}, "limit": top_k, "expr": None, "output_fields": ["id"]} results = collection.search(**search_param) # results[0].ids # # results[0].distances # # hit = results[0][0] # hit.entity.get('title') return results
collection.num_entities
返回的是逻辑上的总实体数,包括了已删除但尚未物理移除的实体。compaction
操作会合并数据段,并在此过程中移除标记为删除的数据。当前存在问题:删除未被计算 https://github.com/milvus-io/milvus/issues/17193架构:
资源需求:
性能和扩展性:
运维复杂度:
适用场景
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。