在 Neo4j 中实现向量化存储:从文本到高效语义搜索
在当今数据驱动的时代,图数据库因其强大的关系表达能力和高效的查询性能,逐渐成为处理复杂数据结构的首选工具之一。Neo4j 作为领先的图数据库,不仅支持传统的图数据存储和查询,还通过向量化存储功能,为语义搜索和推荐系统提供了强大的支持。本文将详细介绍如何在 Neo4j 中实现向量化存储,并通过一个完整的示例展示其应用。
1. 什么是向量化存储?
向量化存储是一种将文本或其他数据转换为向量形式并存储在数据库中的技术。向量是一种数学表示,可以用于计算相似性、距离等,非常适合用于语义搜索和推荐系统。通过将文本数据转换为向量,我们可以在数据库中高效地进行语义相似性查询,而不仅仅是基于关键词的匹配。
2. 为什么选择 Neo4j?
Neo4j 是一种高性能的图数据库,擅长处理复杂的关系数据。它不仅支持传统的图数据存储和查询,还通过向量化功能,为语义搜索和推荐系统提供了强大的支持。通过将文本数据转换为向量并存储在 Neo4j 中,我们可以结合图结构的优势,实现高效的语义搜索和关系分析。
3. 完整的操作流程
步骤 1:环境配置
在开始之前,需要配置环境变量,以便连接到 Neo4j 数据库。这些环境变量包括数据库的 URI、用户名和密码。
export NEO4J_URI=<YOUR_NEO4J_URI>
export NEO4J_USERNAME=<YOUR_NEO4J_USERNAME>
export NEO4J_PASSWORD=<YOUR_NEO4J_PASSWORD>
NEO4J_URI
:Neo4j 数据库的地址,例如bolt://localhost:7687
。NEO4J_USERNAME
:登录 Neo4j 的用户名,通常是neo4j
。NEO4J_PASSWORD
:登录 Neo4j 的密码。
步骤 2:数据填充
假设你有一些文本数据(例如一个文本文件 dune.txt
),需要将这些文本数据处理后存储到 Neo4j 中。这通常需要以下步骤:
- 读取文本数据:从文件中读取文本内容。
- 分段处理:将文本分割成较小的段落或句子。
- 生成向量:使用某种嵌入模型(如 OpenAI 的
text-embedding-ada-002
或 Hugging Face 的sentence-transformers
)将文本转换为向量。 - 存储到 Neo4j:将文本和对应的向量存储到 Neo4j 数据库中。
以下是一个简单的 Python 示例代码,展示如何完成这些步骤:
import os
import neo4j
from transformers import AutoModel, AutoTokenizer
import torch# 连接到 Neo4j 数据库
uri = os.getenv("NEO4J_URI")
username = os.getenv("NEO4J_USERNAME")
password = os.getenv("NEO4J_PASSWORD")
driver = neo4j.GraphDatabase.driver(uri, auth=(username, password))# 加载文本嵌入模型
model_name = "sentence-transformers/all-MiniLM-L6-v2"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)# 读取文本文件
with open("dune.txt", "r") as file:text = file.read()# 分段处理文本
paragraphs = text.split("\n\n") # 假设每两行是一个段落# 将文本和向量存储到 Neo4j
def store_paragraphs(paragraphs):with driver.session() as session:for i, paragraph in enumerate(paragraphs):# 生成向量inputs = tokenizer(paragraph, return_tensors="pt", padding=True, truncation=True)outputs = model(**inputs)vector = outputs.last_hidden_state.mean(dim=1).detach().numpy().tolist()[0]# 存储到 Neo4jsession.run("""CREATE (p:Paragraph {id: $id, text: $text, embedding: $embedding})""",id=i,text=paragraph,embedding=vector)store_paragraphs(paragraphs)
步骤 3:创建向量索引
在 Neo4j 中,为了高效地查询向量数据,需要创建向量索引。向量索引可以帮助快速计算向量之间的相似性。
以下是一个创建向量索引的 Cypher 查询示例:
CREATE VECTOR INDEX `paragraph-embeddings`
FOR (p:Paragraph) ON (p.embedding)
OPTIONS {indexConfig: {`vector.dimensions`: 384, // 假设向量维度是 384`vector.similarity_function`: 'cosine' // 使用余弦相似性
}}
vector.dimensions
:向量的维度,取决于你使用的嵌入模型。vector.similarity_function
:用于计算相似性的函数,常见的有余弦相似性(cosine
)和欧几里得距离(euclidean
)。
步骤 4:查询向量索引
创建索引后,可以通过向量查询来找到与给定向量最相似的节点。以下是一个查询示例:
CALL db.index.vector.queryNodes('paragraph-embeddings', 10, $queryVector)
YIELD node AS paragraph, score
RETURN paragraph.text AS text, score
ORDER BY score DESC
paragraph-embeddings
:向量索引的名称。10
:返回最相似的 10 个结果。$queryVector
:查询向量,你需要提前生成这个向量。
例如,如果你想查询与某个文本最相似的段落,可以先将文本转换为向量,然后作为 $queryVector
传入查询。
步骤 5:设置向量属性
如果需要为节点或关系设置向量属性,可以使用以下 Cypher 查询:
MATCH (n:Paragraph {id: $id})
CALL db.create.setNodeVectorProperty(n, 'embedding', $vector)
RETURN n
n:Paragraph
:目标节点。embedding
:向量属性的名称。$vector
:要设置的向量值。
4. 总结
通过以上步骤,你可以在 Neo4j 数据库中实现高效的向量化存储和查询。具体步骤包括:
- 环境配置:设置连接到 Neo4j 的环境变量。
- 数据填充:读取文本数据,生成向量,并存储到 Neo4j 中。
- 创建向量索引:在 Neo4j 中为向量数据创建索引,以便快速查询。
- 查询向量索引:使用向量查询找到与目标向量最相似的节点。
- 设置向量属性:为节点或关系设置向量属性。
希望这些内容能帮助你更好地理解如何在 Neo4j 中使用向量化存储,从而为你的项目带来更强大的语义搜索和推荐功能。