Vector Databases

矢量数据库是一种专门类型的数据库,在 AI 应用程序中起着至关重要的作用。 在向量数据库中,查询与传统的关联数据库不同。它并不执行精确匹配,而是执行相似性搜索。当将向量作为一个查询提供时,向量数据库会返回与查询向量 “similar” 的向量。在 Vector Similarity 中以高层次提供了有关如何计算此相似性的进一步详细信息。 向量数据库用于将您的数据与 AI 模型集成在一起。使用它们的第一步是将您的数据加载到向量数据库中。然后,当要将用户的查询发送到 AI 模型时,首先检索一组相似的文档。然后,这些文档充当用户问题的上下文,并与用户的查询一起发送到 AI 模型。此技术称为 Retrieval Augmented Generation (RAG)。 以下部分描述了用于使用多个矢量数据库实现以及一些高级样本用法 Spring AI 接口。 最后一部分旨在揭开矢量数据库中相似性搜索的底层方法的神秘面纱。

API Overview

本节充当 VectorStore 接口及其在 Spring AI 框架内的相关类的一个指南。

Spring AI 通过 VectorStore 接口提供一个抽象的 API,用于与矢量数据库进行交互。

以下是 VectorStore 接口定义:

public interface VectorStore {

    void add(List<Document> documents);

    Optional<Boolean> delete(List<String> idList);

    List<Document> similaritySearch(String query);

    List<Document> similaritySearch(SearchRequest request);
}

和相关的 SearchRequest 生成器:

public class SearchRequest {

	public final String query;
	private int topK = 4;
	private double similarityThreshold = SIMILARITY_THRESHOLD_ALL;
	private Filter.Expression filterExpression;

	public static SearchRequest query(String query) { return new SearchRequest(query); }

	private SearchRequest(String query) { this.query = query; }

	public SearchRequest withTopK(int topK) {...}
	public SearchRequest withSimilarityThreshold(double threshold) {...}
	public SearchRequest withSimilarityThresholdAll() {...}
	public SearchRequest withFilterExpression(Filter.Expression expression) {...}
	public SearchRequest withFilterExpression(String textExpression) {...}

	public String getQuery() {...}
	public int getTopK() {...}
	public double getSimilarityThreshold() {...}
	public Filter.Expression getFilterExpression() {...}
}

要将数据插入到矢量数据库中,请将其封装在一个 Document 对象中。Document 类封装来自数据源的内容,例如 PDF 或 Word 文档,并包含作为字符串表示的文本。它还包含 key-value 形式的元数据,包括文件名等详细信息。

在插入到矢量数据库后,文本内容将使用嵌入模型转换为数字数组或 List<Double>,称为矢量嵌入。Word2Vec、GLoVE 和 BERT 等嵌入模型或 OpenAI 的 text-embedding-ada-002 用于将单词、句子或段落转换为这些矢量嵌入。

矢量数据库的作用是存储这些嵌入并为它们提供相似性搜索。它本身不生成嵌入。应利用 EmbeddingClient 来创建矢量嵌入。

该接口中的 similaritySearch 方法允许检索与给定查询字符串相似的文档。可以通过使用以下参数来微调这些方法:

  • k:指定要返回的相似文档的最大数量的整数。这通常被称为“前 K”搜索或“K 最近邻”(KNN)。

  • threshold:介于 0 到 1 之间的双精度值,接近 1 的值表示更高的相似性。举例而言,默认情况下,如果您设置 0.75 的阈值,则只返回相似度高于此值的文档。

  • Filter.Expression:用于传递流畅的 DSL(领域特定语言)表达式的类,其作用类似于 SQL 中的“where”子句,但它仅应用于 Document 的元数据键值对。

  • filterExpression:基于 ANTLR4 的外部 DSL,接受字符串作为过滤器表达式。例如,对于诸如国家、年份和 isActive 等元数据键,您可以使用如下表达式:country == 'UK' &amp;&amp; year &gt;= 2020 &amp;&amp; isActive == true.

Metadata Filters 部分中查找有关 Filter.Expression 的更多信息。

Available Implementations

以下是 VectorStore 接口的可用实现:

以后的版本中可能会支持更多实现。

如果你有一个需要 Spring AI 支持的矢量数据库,请在 GitHub 上提出问题,或者更好的是,提交一个带有实现的 pull 请求。

可以在本章的子部分中找到有关每个 VectorStore 实现的信息。

Example Usage

要计算矢量数据库的嵌入,您需要选择与正在使用的更高级别 AI 模型相匹配的嵌入模型。

例如,对于 OpenAI 的 ChatGPT,我们使用 OpenAiEmbeddingClient 和模型名称 text-embedding-ada-002

OpenAI 的 Spring Boot 启动器的自动配置使 EmbeddingClient 实现可用于 Spring 应用程序上下文中,以进行依赖项注入。

将数据加载到向量存储中的常规用法是您在类似批处理的工作中要执行的操作,首先将数据加载到 Spring AI 的 Document 类中,然后调用 save 方法。

给定一个引用 JSON 文件的 String,该 JSON 文件包含我们要加载到向量数据库中的数据,我们使用 Spring AI 的 JsonReader 加载 JSON 中的特定字段,将其拆分为小部分,然后将这些小部分传递到向量存储实现中。 VectorStore 实现计算嵌入,并将 JSON 和嵌入存储在向量数据库中:

  @Autowired
  VectorStore vectorStore;

  void load(String sourceFile) {
            JsonReader jsonReader = new JsonReader(new FileSystemResource(sourceFile),
                    "price", "name", "shortDescription", "description", "tags");
            List<Document> documents = jsonReader.get();
            this.vectorStore.add(documents);
  }

稍后,当用户问题传入 AI 模型时,将执行相似性搜索以检索类似文档,然后将其“填充”到提示中作为用户问题的上下文。

   String question = <question from user>
   List<Document> similarDocuments = store.similaritySearch(question);

可以将其他选项传递到 similaritySearch 方法中,以定义检索多少文档以及相似性搜索的阈值。

Metadata Filters

本部分介绍您可以对查询结果使用的各种筛选器。

Filter String

您可以将类似 SQL 的筛选器表达式作为 String 传递给 similaritySearch 重载之一。

考虑以下示例:

  • "country == 'BG'"

  • "genre == 'drama' &amp;&amp; year &gt;= 2020"

  • "genre in ['comedy', 'documentary', 'drama']"

Filter.Expression

您可以使用公开 FluentAPI 的 FilterExpressionBuilder 创建 Filter.Expression 实例。一个简单的示例如下:

FilterExpressionBuilder b = new FilterExpressionBuilder();
Expression expression = b.eq("country", "BG").build();

您可以使用以下运算符构建复杂表达式:

EQUALS: '=='
MINUS : '-'
PLUS: '+'
GT: '>'
GE: '>='
LT: '<'
LE: '<='
NE: '!='

您可以使用以下运算符组合表达式:

AND: 'AND' | 'and' | '&&';
OR: 'OR' | 'or' | '||';

考虑到以下示例:

Expression exp = b.and(b.eq("genre", "drama"), b.gte("year", 2020)).build();

您还可以使用以下运算符:

IN: 'IN' | 'in';
NIN: 'NIN' | 'nin';
NOT: 'NOT' | 'not';

请考虑以下示例:

Expression exp = b.and(b.eq("genre", "drama"), b.gte("year", 2020)).build();

Understanding Vectors