当今科技领域的发展日新月异,向量数据库成为了热门的话题之一。
这些数据库以其高效的向量检索和相似度搜索功能,为各种应用场景提供了强大的支持。
本文旨在汇总向量数据库
Milvus、Zilliz、Faiss、Qdrant、LlamaIndex、Chroma、LanceDB、Pinecone、Weaviate、
基本介绍
1. Milvus
Milvus是一个开源的向量相似度搜索引擎,由Zilliz团队开发。它提供了高性能的向量检索和相似度搜索功能,支持海量数据的快速查询。Milvus支持多种向量类型和距离度量方法,并提供了易于使用的API和丰富的功能,使得开发者可以轻松构建各种应用,如图像搜索、推荐系统和自然语言处理。
2. Zilliz:
Zilliz是一家专注于大规模向量数据分析的公司,他们开发了多个与向量相关的开源项目,其中包括Milvus和Chroma。Zilliz致力于提供高效的向量数据处理和分析解决方案,帮助用户在海量数据中进行快速的相似度搜索和数据分析。
3. Faiss:
Faiss是Facebook AI Research开发的一个高性能向量相似度搜索库。它支持多种向量索引结构和距离度量方法,并提供了高效的搜索算法,能够在大规模数据集上进行快速的相似度搜索。Faiss被广泛应用于图像识别、语音识别和自然语言处理等领域。
4. Qdrant:
Qdrant是一个开源的向量搜索引擎,由Qdrant团队开发。它提供了高性能的向量检索和相似度搜索功能,支持多种向量类型和距离度量方法。Qdrant还提供了丰富的查询语法和灵活的配置选项,使得用户可以根据自己的需求进行定制化的搜索。
Qdrant 因其易用性和用户友好的开发者文档,面世不久即获得关注。
Qdrant 以 Rust 语言构建,提供 Rust、Python、Golang 等客户端 API,能够满足当今主流开发人员的需求。
不过, Qdrant 作为后起之秀,和其他竞品仍然存在一定差距,例如界面及查询功能不够完善。
5. LlamaIndex:
LlamaIndex是一个基于向量的数据库引擎,由Llama Labs开发。它提供了高效的向量存储和检索功能,支持多种向量类型和距离度量方法。LlamaIndex还提供了易于使用的API和丰富的功能,使得开发者可以快速构建各种应用,如推荐系统、广告投放和智能搜索。
6. Chroma:
Chroma是Zilliz团队开发的一个开源的向量数据管理系统。它提供了高效的向量存储和查询功能,支持多种向量类型和距离度量方法。Chroma还提供了可扩展的架构和分布式计算能力,能够处理大规模的向量数据集。
ES vs Milvus
Elasticsearch与milvus作为RAG向量库怎么选?
结论,如果是成熟生产级产品或者应用,elasticsearch > milvus。
如果对于性能要求较高,或者对性能有调优需求,milvus > elasticsearch,不过综合来看,我还是建议使用elasticsearch,特别是8.x/9.x版本,接下来,我从以下几个方面说下我的理由。
稳定性和分布式
架构方面:
https://milvus.io/docs/zh/architecture_overview.md
说实话,从架构方面,我就觉得milvus就逊于elasticsearch,最直观的感受就是太复杂,概念太多,组件太多,模块分层太多,也许你觉得这些描述过于感性,但复杂就会带来脆弱不稳定性以及维护难度大等问题,反观,这确实elasticsearch所擅长的,相对架构会简单很多,也不依赖外部组件,集群算法以及分布式文件存储都是自己多年沉淀出来的最佳实践。
功能与灵活性
作为知识库的存储选型,可能不仅仅局限在向量数据库最擅长的向量操作与检索,毕竟当前知识库构建过程中,最重要的召回阶段,为了提升最终召回的准确率,一般都会采用多路召回,再不济也会提供标准的混合检索实现,除了向量检索,还要求全文检索即相关性检索(当然,有些人也区别向量检索成为稀疏检索),不管变种怎么变化,核心一般还是围绕BM25,而elasticsearch天然支持全文检索,同时elasticsearch支持的script功能,还提供用户自定义算法,当然elasticsearch本身也提供了直接支持,但一些开箱即用的高级特性,要求商业付费。
具体可参考:
https://www.elastic.co/blog/whats-new-elastic-search-9-0-0
除了这些,最坑的要数milvus不支持schema的修改,即collection一旦确定,不允许调整,尽管支持标量字段的json字段,这些限制,无非是为了提高它号称的高性能,尽管我没有去拔代码证实,可能有失偏颇,但这真的蛮重要,特别是对于一些非结构化数据或者基于之上的平台型产品,字段动态变更真的很重要,而这对于elasticsearch号称的no schema或者schemaless特性,真的手拿把掐。
除了在支持混合检索,动态schema等丰富的功能上,在一些查询或者操作的api上,milvus也有很大的差距。
性能
再聊下性能方面,milvus官方的博客,会拿性能来说事,比如下面这些文章:
https://milvus.io/blog/milvus-26-preview-72-memory-reduction-without-compromising-recall-and-4x-faster-than-elasticsearch.md
我没有大规模去压测两个产品在大文档集下的具体表现,从milvus的一些文章来看,应该是有优势的,特别是2.6预览版在6月份号称会发布,引入了RaBitQ向量化实现,在内存占用、QPS、召回率等表现不错,同时加强了语言(jieba分词,国人参与的项目真贴心)、时间感知(也算知识库方面大家关心的文档时效性问题),总之看起来还是不错的,值得尝试。
当然elasticsearch9.0的版本,对于bbq向量化的性能优化也是有较大提升的,至于两者整体性能比较,后续会做一些投入。
生态
至于生态方面,elasticsearch肯定也是强于milvus不少,毕竟elasticsearch是一个通用多模型的引擎,而且有先发优势,发展了这么多年,你看milvus在一些管理工具,都很少,attu用起来都别扭。
Qdrant Cloud VS Zilliz Cloud
--这两个都是云服务,不同点在于
Qdrant 更适合追求低成本基础设施维护的开发人员。
而如果应用系统更注重性能和可扩展性,Zilliz Cloud/Milvus 是更合适的选择。因为 Zilliz Cloud/Milvus 具备可扩展性极强、性能更佳、延时更低的特点,适用于对性能指标有着严格要求的场景。
每秒查询次数(QPS)
测试结果显示,在 10,000,000 条 768 维的向量数据中进行检索时,Zilliz Cloud 两款实例的 QPS 分别是 Qdrant Cloud 实例的 7 倍和 1 倍。
具体见参考资料
Qdrant 用法
架构
同其他数据库一样,支持本地和服务器部署
docker 部署
提取预构建的 Docker 映像并运行容器:
docker pull qdrant/qdrant
docker run -d -p 7541:6333 --ip=10.0.180.16 qdrant/qdrant # 7541对外,6333是容器端口,必须是6333或者6334
-d 后台启动服务后
Access web UI at http://localhost:6333/dashboard 2023-12-06T04:43:43.136073Z INFO storage::content_manager::consensus::persistent: Initializing new raft state at ./storage/raft_state.json 2023-12-06T04:43:43.552838Z INFO qdrant: Distributed mode disabled 2023-12-06T04:43:43.552926Z INFO qdrant: Telemetry reporting enabled, id: 9fcc223f-6fbe-4932-8a31-4663683e1baf 2023-12-06T04:43:43.564727Z INFO qdrant::tonic: Qdrant gRPC listening on 6334 2023-12-06T04:43:43.564772Z INFO qdrant::tonic: TLS disabled for gRPC API 2023-12-06T04:43:43.565817Z INFO qdrant::actix: TLS disabled for REST API 2023-12-06T04:43:43.565952Z INFO qdrant::actix: Qdrant HTTP listening on 6333 2023-12-06T04:43:43.565991Z INFO actix_server::builder: Starting 95 workers
即可访问 http://10.0.180.16:7541/dashboard
安装包
pip install qdrant-client pymilvus
langchain demo
包括 本地 和 url 用法,下面的代码是将 文本 转换成向量 并存储到数据库
from langchain.vectorstores import Qdrant from langchain.schema import Document from langchain.embeddings.huggingface import HuggingFaceEmbeddings docs = [Document(page_content=u'avc')] embeddings = HuggingFaceEmbeddings( model_name=r"F:\weights\text2vec-base-chinese") # qdrant = Qdrant.from_documents( # docs, # embeddings, # location=":memory:", # 这个可以 Local mode with in-memory storage only # # path="emb_qdrant_pickle2", # 不行 # collection_name="my_documents", # ) qdrant = Qdrant.from_documents( docs, embeddings, url='10.0.180.16:7541', prefer_grpc=False, # 上面起服务用 6333,这里就需要False collection_name="my_documents", # 这个随便 ) print(qdrant.similarity_search('a'))
读取已存储的数据
from langchain.vectorstores import Qdrant from langchain.embeddings.huggingface import HuggingFaceEmbeddings import qdrant_client embeddings = HuggingFaceEmbeddings(model_name=r"F:\weights\text2vec-large-chinese") client = qdrant_client.QdrantClient( url='10.0.180.16:7541', prefer_grpc=False ) qdrant = Qdrant( client=client, collection_name="my_documents", # embedding_function=embeddings.embed_query, # 这里报过错,可查看源码 embeddings=embeddings ) found_docs = qdrant.similarity_search('员工绩效管理模式有哪些') print(found_docs)
加上 filter 过滤

embeddings = OpenAIEmbeddings(deployment="text-embedding-ada-002") client = qdrant_client.QdrantClient( url='10.0.180.x6:7541', prefer_grpc=False ) question = 'Idarat Al Mukhabarat Al Jawiyya' vector = embeddings.embed_query(question) search_result = client.search( collection_name="company3", query_vector=vector, query_filter=Filter( must=[FieldCondition(key="metadata.language", match=MatchValue(value="id"))] ), with_payload=True, limit=3, ) print(search_result)
纯 python 代码

from qdrant_client.http.models import PointStruct from langchain.vectorstores import Qdrant import qdrant_client from qdrant_client.http.models import Distance, VectorParams from qdrant_client.http.models import Filter, FieldCondition, MatchValue client = qdrant_client.QdrantClient( url='10.0.180.16:7541', prefer_grpc=False ) ### 创建collection client.create_collection( collection_name="test_collection", vectors_config=VectorParams(size=4, distance=Distance.DOT), ) ### 写入 operation_info = client.upsert( collection_name="test_collection", wait=True, points=[ PointStruct(id=1, vector=[0.05, 0.61, 0.76, 0.74], payload={"page_content": "Berlin", "metadata":{"language": "ru", "recodeid": 523622}}), PointStruct(id=2, vector=[0.19, 0.81, 0.75, 0.11], payload={"page_content": "London", "metadata":{"language": "xx", "recodeid": 523622}}), ], ) ### 带条件查询 search_result = client.search( collection_name="test_collection", query_vector=[0.2, 0.1, 0.9, 0.7], query_filter=Filter( must=[FieldCondition(key="metadata.language", match=MatchValue(value="xx"))] ), with_payload=True, limit=3, ) print(search_result)
FAISS 用法
Faiss是一个高效地稠密向量相似检索和聚类的工具包,
由Facebook开发,由C++编写,并且提供了python2和python3的封装。
安装
pip install faiss-cpu
pip install faiss-gpu
用法
- xb 对于数据库,它包含所有必须编入索引的向量,并且我们将搜索它。它的大小是nb-by-d
- xq对于查询向量,我们需要找到最近的邻居。它的大小是nq-by-d。如果我们只有一个查询向量,则nq = 1
import numpy as np d = 3 # dimension nb = 5 # database size 从多少个里面找最近的 nq = 2 # nb of queries 有多少个被查找的 xb = np.array([[1, 1, 1], [1.2, 1.3, 1.2], [3, 3, 3], [5, 5, 5], [5.2, 5.3, 5.2]]).astype('float32') # xb[:, 0] += np.arange(nb) / 1000. xq = np.array([[1.1, 1, 1], [5.2, 5.2, 5.2]]).astype('float32') # xq[:, 0] += np.arange(nq) / 1000. 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 print(I) # [[0 1 2 3] 第一行代表 和 xb[0]即[1.1, 1, 1] 最近的 4个元素,由近及远 # [1 0 2 3] 第二行代表 和 xb[1]即[1.2, 1.3, 1.2] 最近的 4个元素,由近及远 # [2 1 0 3] # [3 4 2 1] # [4 3 2 1]] print(D) # [[ 0. 0.17000002 12. 48. ] 对应上面的实际距离 # [ 0. 0.17000002 9.37 42.57 ] # [ 0. 9.37 12. 12. ] # [ 0. 0.16999996 12. 42.57 ] # [ 0. 0.16999996 14.969999 47.999996 ]] D, I = index.search(xq, k) # actual search print(I[:5]) # neighbors of the 5 first queries print(I[-5:])
Chroma 用法
非 langchain 用法

import chromadb # 获取Chroma Client对象 chroma_client = chromadb.Client() # 创建Chroma数据集 collection = chroma_client.create_collection(name="my_collection") # 添加数据 collection.add( documents=["This is an apple", "This is a banana"], metadatas=[{"source": "my_source"}, {"source": "my_source"}], ids=["id1", "id2"] ) # 查询数据 results = collection.query( query_texts=["This is a query document"], n_results=2 ) results
langchain 统一用法
暂未验证

### 创建VectorStore对象 # 通过HuggingFace创建embedding_function embeddings = HuggingFaceEmbeddings(model_name=model) # 创建VectorStore的具体实现类Chroma对象,并指定collection_name和持久化目录 vector = Chroma(collection_name = 'cname', embedding_function=embeddings,persist_directory='/vs') # 先将文本拆分并转化为doc loader = TextLoader(url,autodetect_encoding = True) docs = loader.load() text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200) splits = text_splitter.split_documents(docs) # 插入向量数据库 vector.add_documents(documents=splits) ### # 删除id为1的doc对象 vector.delete('1') ### # 根据file_id的条件,查询到所有符合的doc对象的id reuslt = vector.get(where={"file_id":file_id}) # 使用delete方法,批量删除这些id对应的doc对象 if reuslt['ids'] : vector.delete(reuslt['ids']) ### # 删除id为2的doc对象 vector.delete('2') # 插入新的doc对象 vector.add_documents(new_doc) ### # 查询与“语义检索”最相似的doc对象 docs = vector.similarity_search("语义检索") # 打印查询结果 for doc in docs: print(doc) # 查询与“语义检索”最相似的doc对象,并返回分数 docs_with_score = vector.similarity_search_with_score("语义检索") # 打印查询结果和分数 for doc_with_score in docs_with_score: print(doc_with_score[0], doc_with_score[1]) ### # 查询与“LangChain”相关的但不相似的doc对象 docs = vector.max_marginal_relevance_search("LangChain") # 打印查询结果 for doc in docs: print(doc)
出自 https://mp.weixin.qq.com/s/USTWPFyseZt6rEgZbLrUtA
参考资料:
https://mp.weixin.qq.com/s/URSOuAAKhm9HzcAHCaQklw 智王点评:六大向量数据库
https://mp.weixin.qq.com/s/46ry2XXmW0kEXPeaDFKyTg 如何选择一个向量数据库|Qdrant Cloud v.s. Zilliz Cloud
Zilliz联手英伟达发布全球首个GPU加速向量数据库!CUDA加持性能飙升50倍,未来十年或暴涨1000倍-腾讯云开发者社区-腾讯云 (tencent.com)
https://qdrant.tech/documentation/guides/installation/ Qdrant 官网
Qdrant向量数据库-CSDN博客 纯python
RAG应用必备!10种向量数据库全解析、Weaviate、Milvus、pgvector、Qdrant等热门工具谁更强?
https://www.jianshu.com/p/43db601b8af1 faiss 学习笔记(一) | 三种基础索引方式学习
https://zhuanlan.zhihu.com/p/67200902 Faiss库使用方法(一)
未研究
https://mp.weixin.qq.com/s/W7hVVBuxiCDkHYdaQxjX1g 使用LangChain和Qdrant进行无样板代码的问答
https://mp.weixin.qq.com/s/Q1RppVV8Fdti6hIIfCvCVw Qdrant不只是高性能向量数据库
https://mp.weixin.qq.com/s/YOpNf34QIp9im8aA9LMvGw 将Milvus作为 OpenAI 嵌入的向量数据库
https://mp.weixin.qq.com/s/9NB7UUFr_nOwL3CRfcsdtA Milvus 向量数据库的应用场景
https://mp.weixin.qq.com/s/qNCEDFsaGDjcH6g5z-y2xw 大模型应用之Milvus向量数据库实践
https://mp.weixin.qq.com/s/dOrcbQnaWrDxz5lw9aZaBg 5 分钟内搭建一个免费问答机器人:Milvus + LangChain
https://mp.weixin.qq.com/s/jzWlwgOMkYs4CNz1UlP0Rw 【开源】向量数据库
https://mp.weixin.qq.com/s/YENmch0b4rbNJ73bvBLUpQ 大模型中间件 向量数据库原理和选择