使用Sentence Transformers和Qdrant构建神经网络搜索服务
| 时间:30分钟 | 级别:新手 | 输出:GitHub |
|---|
本教程将向您展示如何构建和部署自己的神经网络搜索服务,以从startups-list.com的公司描述中查找与您的查询最相似的公司。该网站包含每个条目的公司名称、描述、位置和图片。
神经网络搜索服务使用人工神经网络来提高搜索结果的准确性和相关性。除了提供简单的关键词结果外,该系统还可以通过含义检索结果。它可以理解和解释复杂的搜索查询,并提供更具上下文相关性的输出,有效增强用户的搜索体验。
工作流程
要创建神经网络搜索服务,您需要转换原始数据,然后创建一个搜索函数来操作它。首先,您将1)使用BERT机器学习模型的修改版本下载并准备一个示例数据集。然后,您将2)将数据加载到Qdrant,3)创建一个神经网络搜索API,并4)使用FastAPI提供服务。

注意:本教程的代码可以在此处找到: | 步骤1:数据准备过程 | 步骤2:神经网络搜索的完整代码。 |
先决条件
要完成本教程,您需要
- Docker - 使用Qdrant最简单的方法是运行预构建的Docker镜像。
- 来自startups-list.com的原始解析数据。
- Python版本 >=3.8
准备示例数据集
要对初创公司描述进行神经网络搜索,您必须首先将描述数据编码为向量。要处理文本,您可以使用预训练模型,如BERT或sentence transformers。sentence-transformers库允许您方便地下载和使用许多预训练模型,例如DistilBERT、MPNet等。
- 首先,您需要下载数据集。
wget https://storage.googleapis.com/generall-shared-data/startups_demo.json
- 安装SentenceTransformer库以及其他相关软件包。
pip install sentence-transformers numpy pandas tqdm
- 导入所需的模块。
from sentence_transformers import SentenceTransformer
import numpy as np
import json
import pandas as pd
from tqdm.notebook import tqdm
您将使用一个名为all-MiniLM-L6-v2的预训练模型。这是一个性能优化的句子嵌入模型,您可以在此处阅读更多关于它和其他可用模型的信息。
- 下载并创建一个预训练的句子编码器。
model = SentenceTransformer(
"all-MiniLM-L6-v2", device="cuda"
) # or device="cpu" if you don't have a GPU
- 读取原始数据文件。
df = pd.read_json("./startups_demo.json", lines=True)
- 编码所有初创公司描述,为每个描述创建一个嵌入向量。在内部,
encode函数将输入分成批次,这将显著加快处理速度。
vectors = model.encode(
[row.alt + ". " + row.description for row in df.itertuples()],
show_progress_bar=True,
)
所有描述现在都已转换为向量。共有40474个384维向量。模型的输出层具有此维度。
vectors.shape
# > (40474, 384)
- 将保存的向量下载到一个名为
startup_vectors.npy的新文件中。
np.save("startup_vectors.npy", vectors, allow_pickle=False)
在Docker中运行Qdrant
接下来,您需要使用向量引擎管理所有数据。Qdrant允许您存储、更新或删除创建的向量。最重要的是,它允许您通过方便的API搜索最近的向量。
注意:在开始之前,请创建一个项目目录并在其中创建一个虚拟Python环境。
- 从DockerHub下载Qdrant镜像。
docker pull qdrant/qdrant
- 在Docker内部启动Qdrant。
docker run -p 6333:6333 \
-v $(pwd)/qdrant_storage:/qdrant/storage \
qdrant/qdrant
您应该看到如下输出
...
[2021-02-05T00:08:51Z INFO actix_server::builder] Starting 12 workers
[2021-02-05T00:08:51Z INFO actix_server::builder] Starting "actix-web-service-0.0.0.0:6333" service on 0.0.0.0:6333
通过访问https://:6333/测试服务。您应该在浏览器中看到Qdrant版本信息。
所有上传到Qdrant的数据都保存在./qdrant_storage目录中,即使您重新创建容器也会持久化。
将数据上传到Qdrant
- 安装官方Python客户端以更好地与Qdrant交互。
pip install qdrant-client
此时,您应该在startups_demo.json文件中拥有初创公司记录,在startup_vectors.npy中拥有编码向量,并且Qdrant正在本地机器上运行。
现在您需要编写一个脚本,将所有初创公司数据和向量上传到搜索引擎中。
- 为Qdrant创建一个客户端对象。
# Import client library
from qdrant_client import QdrantClient
from qdrant_client.models import VectorParams, Distance
client = QdrantClient("https://:6333")
- 相关的向量需要添加到集合中。为您的初创公司向量创建一个新集合。
if not client.collection_exists("startups"):
client.create_collection(
collection_name="startups",
vectors_config=VectorParams(size=384, distance=Distance.COSINE),
)
- 创建初创公司数据和向量的迭代器。
Qdrant客户端库定义了一个特殊函数,允许您将数据集加载到服务中。然而,由于数据可能太多,无法放入单个计算机内存中,因此该函数将数据迭代器作为输入。
fd = open("./startups_demo.json")
# payload is now an iterator over startup data
payload = map(json.loads, fd)
# Load all vectors into memory, numpy array works as iterable for itself.
# Other option would be to use Mmap, if you don't want to load all data into RAM
vectors = np.load("./startup_vectors.npy")
- 上传数据
client.upload_collection(
collection_name="startups",
vectors=vectors,
payload=payload,
ids=None, # Vector ids will be assigned automatically
batch_size=256, # How many vectors will be uploaded in a single request?
)
向量现在已上传到Qdrant。
构建搜索API
现在所有准备工作都已完成,让我们开始构建神经网络搜索类。
为了处理传入请求,神经网络搜索需要两件事:1)将查询转换为向量的模型,以及2)执行搜索查询的Qdrant客户端。
- 创建一个名为
neural_searcher.py的文件并指定以下内容。
from qdrant_client import QdrantClient
from sentence_transformers import SentenceTransformer
class NeuralSearcher:
def __init__(self, collection_name):
self.collection_name = collection_name
# Initialize encoder model
self.model = SentenceTransformer("all-MiniLM-L6-v2", device="cpu")
# initialize Qdrant client
self.qdrant_client = QdrantClient("https://:6333")
- 编写搜索函数。
def search(self, text: str):
# Convert text query into vector
vector = self.model.encode(text).tolist()
# Use `vector` for search for closest vectors in the collection
search_result = self.qdrant_client.query_points(
collection_name=self.collection_name,
query=vector,
query_filter=None, # If you don't want any filters for now
limit=5, # 5 the most closest results is enough
).points
# `search_result` contains found vector ids with similarity scores along with the stored payload
# In this function you are interested in payload only
payloads = [hit.payload for hit in search_result]
return payloads
- 添加搜索过滤器。
使用Qdrant,还可以为搜索添加一些条件。例如,如果您想搜索某个城市的初创公司,搜索查询可能如下所示:
from qdrant_client.models import Filter
...
city_of_interest = "Berlin"
# Define a filter for cities
city_filter = Filter(**{
"must": [{
"key": "city", # Store city information in a field of the same name
"match": { # This condition checks if payload field has the requested value
"value": city_of_interest
}
}]
})
search_result = self.qdrant_client.query_points(
collection_name=self.collection_name,
query=vector,
query_filter=city_filter,
limit=5
).points
...
您现在已经创建了一个用于神经网络搜索查询的类。现在将其封装到一个服务中。
使用FastAPI部署搜索
要构建服务,您将使用FastAPI框架。
- 安装FastAPI。
要安装它,请使用命令
pip install fastapi uvicorn
- 实现服务。
创建一个名为service.py的文件并指定以下内容。
该服务将只有一个API端点,看起来像这样
from fastapi import FastAPI
# The file where NeuralSearcher is stored
from neural_searcher import NeuralSearcher
app = FastAPI()
# Create a neural searcher instance
neural_searcher = NeuralSearcher(collection_name="startups")
@app.get("/api/search")
def search_startup(q: str):
return {"result": neural_searcher.search(text=q)}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
- 运行服务。
python service.py
- 在浏览器中打开https://:8000/docs。
您应该能够看到您的服务的调试界面。

随意使用它,对我们语料库中的公司进行查询,并查看结果。
下一步
本教程中的代码已用于开发实时在线演示。您可以尝试它来直观了解神经网络搜索有用的情况。该演示包含一个在神经网络搜索和全文搜索之间进行选择的开关。您可以打开和关闭神经网络搜索,将您的结果与常规全文搜索进行比较。
注意:本教程的代码可以在此处找到: | 步骤1:数据准备过程 | 步骤2:神经网络搜索的完整代码。 |
加入我们的Discord社区,我们在那里讨论向量搜索和相似性学习,发布神经网络和其他神经网络搜索应用的示例。