向量相似性搜索与图数据库:数据处理的创新融合
近日热文:全网最全的神经网络数学原理(代码和公式)直观解释
欢迎关注知乎和公众号的专栏内容
LLM架构专栏
知乎LLM专栏
知乎【柏企】
公众号【柏企阅文】
想象一下,你正在解决一个包含零散信息的复杂难题。传统的数据库搜索就像是翻阅名片索引册——你寻找的是完全匹配的内容或简单的属性,比如 “谁有红头发?” 或者 “谁拥有一辆蓝色的汽车?” 这些搜索方式虽然有用,但功能有限。向量相似性搜索则改变了这种局面,它让你可以问:“还有哪些部分和这个相似?” 它擅长发现语义上的相似性,揭示那些可能隐藏的模式。
不过,复杂的难题可不只是单个部分的问题,还关乎所有部分是如何相互联系的。这正是图数据库的优势所在。图数据库能够绘制关系图,例如 “谁和谁有联系?” 或者 “两点之间的最短路径是什么?” 通过图数据库,你能看到更宏观的图景。
现在,再想象一下将这两种能力结合起来。你不仅能找到相似的部分,还能立刻明白它们如何融入更广阔的背景之中。例如,仅仅识别出一个与另一个嫌疑人长相相似的人是不够的,关键是要揭示他们的关系网络,包括他们的同伙、行动轨迹以及互动情况。
向量相似性搜索与图遍历的融合,创造出了一种强大的新范式,让我们能够从语义和关系两个维度理解数据。
向量数据库:挖掘语义相似性
向量数据库擅长揭示语义相似性,比如 “这篇文档和那篇文档感觉很像” 或者 “这张图片和那张图片很相似”。
理解向量嵌入
来看嵌入算法是如何将相似的单词 “分组” 在一起的,以及搜索查询是如何找到含义相似的单词或短语的!
向量嵌入是将复杂的数据(如文本、图像或图中的节点)转换为固定长度的数值向量。虽然上面的图片展示的是在三维平面上的情况,但OpenAI的API,例如text - embedding - 3 - small,会生成1536维的向量。这些高维表示能够实现对上下文的详细理解,这对于语义搜索、推荐系统等任务至关重要。
我们可以使用诸如余弦相似度搜索这样的算法来计算相似度得分,以此确定两个单词的相似程度。
可以把向量嵌入看作是一种将单词、短语或图像翻译成计算机能够理解的语言的方式,也就是将它们的含义和关系封装在紧凑的数值表示中。
速度与性能
- 查询延迟:像PineconeDB这样的工具,即使在拥有数百万个嵌入的数据集上,也能将查询时间优化到50毫秒以内。
- 批量处理:像OpenAI的嵌入API每秒可以处理数百个文本,这使得它们适用于实时应用程序。
- 维度与速度的权衡:虽然更高的维度(例如1536维)能提供更丰富的上下文信息,但它们需要更多的计算能力,尤其是在进行相似性搜索时。
自己动手试试
from openai import OpenAI
import numpy as np
from numpy.linalg import norm
client = OpenAI(api_key='YOUR_API_KEY')
texts = ["apple", "banana", "computer"]
responses = client.embeddings.create(
input=texts,
model="text-embedding-3-small"
)
embeddings = [r.embedding for r in responses.data]
sim1 = np.dot(embeddings[0], embeddings[1]) / (norm(embeddings[0]) * norm(embeddings[1]))
sim2 = np.dot(embeddings[0], embeddings[2]) / (norm(embeddings[0]) * norm(embeddings[2]))
sim3 = np.dot(embeddings[0], embeddings[3]) / (norm(embeddings[0]) * norm(embeddings[3]))
print(f"Similarity (apple-banana): {sim1:.3f}")
print(f"Similarity (apple-computer): {sim2:.3f}")
print(f"Similarity (apple-{user_text}): {sim3:.3f}")
一般来说,维度越高,存储的 “上下文” 信息就越多,因此相似性搜索也就越准确!
向量数据库提供商示例
- PineconeDB:针对大规模相似性搜索进行了优化,延迟较低。它支持实时查询,并能与机器学习工作流程集成。
- Weaviate:提供模块化的、基于模式的存储,内置向量索引。它支持将向量和符号过滤器相结合的混合搜索。
- pgvector:这是PostgreSQL的一个扩展,用于将向量搜索嵌入到关系数据库中,使得在进行传统SQL查询的同时也能进行向量操作。
知识图谱基础
为了充分理解向量相似性搜索与图数据库的融合,我们先来剖析一下它们的核心组件。
图数据库通过将数据建模为相互连接的实体,提供了一种独特的视角。其中的关键概念包括:
- 节点:代表实体(例如用户或产品)。
- 边:定义关系(例如 “购买”、“是朋友”)。
- 属性:存储节点和边的元数据(例如时间戳或权重)。
速度与性能
- 查询效率:像Neo4j这样的图数据库针对复杂的遍历查询进行了优化,即使对于深度连接的数据,也常常能在几毫秒内返回结果。
- 可扩展性:这些数据库旨在高效处理数十亿个节点和边,在大规模数据下仍能保持高性能。
- 遍历与连接:通过直接遍历相连的节点,图数据库在关系查询上实现了O(n)的效率,这与带有多个连接的SQL查询的O(n^k)复杂度形成了鲜明对比。这使得图数据库在分析相互关联的数据(如社交网络或推荐系统)时具有特别的优势。
图数据库提供商示例
- Neo4j:它是最受欢迎的图数据库之一,提供先进的图算法,并且能与分析和机器学习工作流程集成。
- ArangoDB:这是一个多模型数据库,支持图、文档和键值数据,旨在实现灵活性和可扩展性。
- Amazon Neptune:这是一个完全托管的图数据库服务,支持属性图和RDF(资源描述框架)图。
有趣的是,资源描述框架(RDF)图是一种将数据表示为三元组的方式:主语、谓语、宾语。例如,“Alice(主语)知道(谓语)Bob(宾语)” 就是一个三元组。这种结构使得RDF图在语义网应用和知识图谱中特别有用,因为它们以一种机器能够理解的方式对数据进行了标准化,并且可以使用SPARQL(一种专为RDF数据定制的强大查询语言)进行查询。
融合图与向量:两种方法
记住:向量数据库能告诉你哪些内容感觉相似,而图数据库能告诉你它们是如何相互连接的。
方法一:在图数据库中存储向量嵌入
正如前面所讨论的,图数据库本质上是将数据存储为节点、边和属性,但其结构是为了检索、查询执行和图遍历进行优化的(例如,查找用户的所有朋友及其发布的内容)。
节点、边和……子图?
然而,大多数机器学习模型、相似性计算以及下游任务(例如推荐系统、欺诈检测、聚类分析)都需要固定长度的数值向量作为输入(就像前面提到的OpenAI生成的1536维向量)!
- 节点嵌入:捕捉单个节点的特征,例如用户的个人资料数据或连接性(例如,社交图中用户的年龄、兴趣和朋友数量)。
- 边嵌入:量化关系或交互,例如电子商务图中的购买频率或评分。
- 子图嵌入:总结模式或聚类,比如检测社区或欺诈团伙(例如,购买相似产品的一组客户)。
例如,在社交网络中:
- 一个节点嵌入可能代表一个用户的个人资料和连接情况。
- 一条边嵌入可以对用户与他人的互动强度进行建模。
- 一个子图嵌入可能总结了具有相似兴趣的用户社区。
自己动手试试
from openai import OpenAI
import networkx as nx
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
import numpy as np
client = OpenAI(api_key='YOUR_API_KEY')
G = nx.Graph()
G.add_edges_from([("User1", "Movie1"), ("User1", "Movie2"),
("User2", "Movie1"), ("User2", "Movie3"),
("User3", "Movie3"), ("User3", "Movie4")])
nx.draw(G, with_labels=True, node_color="lightblue", font_size=10)
plt.title("Graph: Users and Movies")
plt.show()
def get_embedding(node):
return client.embeddings.create(input=node, model="text-embedding-3-small")["data"][0]["embedding"]
embeddings = np.array([get_embedding(node) for node in G.nodes()])
embeddings_2d = PCA(n_components=2).fit_transform(embeddings)
plt.scatter(embeddings_2d[:, 0], embeddings_2d[:, 1], c="lightblue")
for i, node in enumerate(G.nodes()):
plt.text(embeddings_2d[i, 0], embeddings_2d[i, 1], node, font_size=9)
plt.title("Node Embeddings Visualization")
plt.show()
节点、边和子图如何变成向量?
为了将图元素转换为向量,需要应用像Node2Vec、TransE和GraphSAGE这样的技术。它们的工作原理如下:
- 节点嵌入:像Node2Vec这样的技术会围绕节点进行随机游走,并将其在图中的上下文信息编码为一个向量。例如,一个 “Netflix” 节点可能通过捕捉与相关节点(如 “Movies”、“Shows” 和 “Subscribers”)的连接来嵌入其上下文信息。
- 边嵌入:像TransE这样的技术将节点之间的关系建模为向量转换。例如,在知识图谱中,“巴黎是法国的首都” 这一关系可以表示为向量运算:巴黎 + is_capital_of ≈ 法国。
- 子图嵌入:像GraphSAGE这样的聚合方法会将子图中的特征和关系总结为单个向量。例如,一个包含房屋、学校、杂货店等节点的社区地图,可以被嵌入为其连接性、交通模式和建筑类型的总结。
方法二:结合独立的图数据库和向量数据库
在结合图遍历和向量相似性搜索时,我们的目标是高效地处理这两种类型的查询。为此,我们需要一种称为混合索引结构的东西。可以把它想象成一个智能系统,它以一种能够让关系分数(图数据)和相似性分数(向量数据)无缝协作的方式来组织数据。
关系分数用于量化图中连接的强度或性质。例如,两个频繁互动的用户可能关系分数为5。相似性分数则根据向量嵌入告诉你两个实体的相似程度。例如,在本文前面的例子中,“apple” 和 “banana” 的相似性分数接近1。
它是如何工作的?
- 图索引:想象有一张地图,每个城市(节点)都通过道路(边)连接。这个索引存储这些连接信息,以帮助回答诸如 “我如何从A城市到达B城市?”(最短路径查询)这样的问题。
- 向量索引:这部分将城市的 “概况” 信息(如人口、气候或氛围)组织成一个系统,相似的城市会被归为一组。可以把它看作是一种能够回答 “哪个城市和A城市感觉最相似?” 的方式。
- 集成层:这一层就像一个翻译器,让你能够将这些系统结合起来。例如:“哪些与A城市相似的城市也与B城市直接相连?”
想象一个电子商务推荐系统。Pinecone中的向量索引可以根据产品描述或评论识别出与用户之前购买的产品相似的产品。与此同时,ArangoDB中的图索引可以揭示经常一起购买的产品。通过将两者结合起来,你可以推荐不仅相似,而且在上下文上也相关的产品。
高效规划查询
为了充分利用混合系统,我们需要一种在不使系统过载的情况下结合两种搜索的策略。以下是一些方法:
- 逐步执行(顺序执行):首先,使用向量相似性来缩小结果范围。例如,找出最相似的10个产品。接下来,使用图遍历根据关系对这些结果进行筛选,比如找出与这10个相似产品一起被购买的其他产品。
- 同时执行(并行执行):同时运行两种搜索,然后合并结果。例如,找出与产品A最相似的产品,以及与产品A一起被购买的其他产品,并比较相似性和关系分数,对商品进行排名。
- 预过滤(优化过滤):在应用计算量较大的图算法之前,使用向量相似性快速缩小搜索空间。
提高速度:性能优化
高级技巧:处理大型图和向量可能对系统要求较高,但有一些方法可以提高效率:
- 预计算:保存频繁查询的结果,这样就无需重新运行。例如,缓存常用的搜索关系或聚类结果。
- 索引调优:针对最常见的查询模式对图索引和向量索引进行微调。对于图索引,这可能意味着优化边的存储方式,或者对频繁访问的节点进行聚类。对于向量索引,可能涉及选择合适的维度,或者修剪掉不太相关的嵌入。
- 分布式处理:使用多台机器来分担工作负载。与依赖一台强大的机器不同,分布式处理允许在数据集上并行执行查询,减少瓶颈,并实现水平扩展,从而高效处理更大的工作负载。
那么……哪种方法更好呢?
方法一:在图数据库中嵌入向量
现在许多现代图数据库,如Neo4j、ArangoDB和Amazon Neptune,都支持直接在图中嵌入向量,这使得可以在一个查询中无缝结合关系遍历和语义相似性,进行混合查询。
- 优点
- 统一的数据管理:直接在图中存储嵌入减少了管理多个系统的复杂性。
- 混合查询:允许在单个查询中无缝结合向量相似性和图遍历,例如在探索目标用户所在社区的同时,识别与该目标用户相似的用户。
- 降低延迟:消除了系统之间的数据传输,这对于实时应用程序至关重要。
- 挑战
- 可扩展性:当数据集的节点数超过数千万,或者维度高于1500时,图数据库在处理嵌入时可能会出现性能下降。
- 搜索精度:专门的向量数据库在处理极高维度的数据时,通常能提供更快、更准确的相似性搜索。
记住:维度越高,能表示的数据就越多。在需要捕捉数据的许多细微特征的任务中,比如处理几乎相同的图像、长篇复杂文本等,你会使用极高维度的向量。
方法二:结合独立的系统
直到去年,图数据库还不能直接在图中支持向量嵌入。这仍然是一项相对较新的技术,而专门的向量数据库在速度上仍然更胜一筹,尤其是在高维相似性搜索方面。
- 优点
- 领域专业化:像Pinecone这样的向量数据库在高维相似性搜索方面表现出色,而图数据库则针对复杂关系进行了优化。
- 可扩展性:每个系统都可以独立扩展,这使得管理包含数十亿个节点或嵌入的数据集成为可能。
- 定制优化:两个系统都可以针对各自的工作负载进行微调,例如优化图遍历算法或相似性索引。
- 挑战
- 集成开销:维持系统之间的同步需要额外的基础设施,如ETL管道或中间件。
- 查询延迟:结合两个系统的结果可能会引入延迟,特别是对于低延迟要求的场景。
考虑一下:结合独立的数据库可以提供特定领域的优势,比如更快的相似性搜索,但系统间通信带来的额外延迟可能并不值得。
下一步:构建带有专业网络的电影推荐引擎
考虑使用TMDB 5000电影数据集构建一个电影推荐引擎。这将结合向量嵌入和图遍历,根据电影内容和专业关系来推荐电影,从而巩固你对这些概念的理解。
注意:这只是一个高层次的项目概述。真正的乐趣和学习在于细节和实践探索!
- 数据收集:下载TMDB 5000电影元数据数据集。
- 数据预处理:清理数据,重点关注电影描述、类型和演员阵容。将电影描述向量化为嵌入向量。
- 向量嵌入:使用OpenAI的嵌入API将电影描述转换为高维向量,用于基于相似性的推荐。
- 图数据库:搭建一个图数据库(例如ArangoDB),对专业网络(如演员、导演、制片人)及其与电影的关系进行建模。
- 相似性搜索:实现余弦相似度计算,根据向量嵌入找到内容相似的电影。
- 图遍历:使用图遍历根据专业关系(例如同一导演、同一演员)推荐电影。
- 混合系统:将基于内容的推荐(向量相似性)与基于网络的推荐(图遍历)相结合。
- 优化:预计算常见查询,并对图索引和向量索引进行性能优化。
后续我们会持续带来更多相关技术的深度解析和实践案例,敬请关注公众号 柏企科技圈 和 柏企阅文
评论