Apache Cassandra
本节将指导您完成设置以存储文档嵌入并执行相似性搜索。CassandraVectorStore
什么是 Apache Cassandra?
Apache Cassandra® 是真正的开源分布式数据库,以线性可扩展性、经过验证的容错能力和低延迟而闻名,使其成为任务关键型事务数据的完美平台。
其矢量相似性搜索 (VSS) 基于 JVector 库,可确保一流的性能和相关性。
Apache Cassandra 中的向量搜索非常简单:
SELECT content FROM table ORDER BY content_vector ANN OF query_embedding ;
可以在此处阅读有关此内容的更多文档。
这个 Spring AI Vector Store 旨在适用于全新的 RAG 应用程序,并能够在现有数据和表之上进行改造。
该存储还可用于现有数据库中的非 RAG 用例,例如语义搜索、地理位置邻近搜索等。
存储将根据其配置根据需要自动创建或增强架构。如果您不想修改架构,请使用 .disallowSchemaChanges
使用 spring-boot-autoconfigure 时,根据 Spring Boot 标准默认为 true,您必须通过在适当的构造函数中指定布尔值或在文件中进行设置来选择加入模式创建/修改。disallowSchemaChanges
initializeSchema
…initialize-schema=true
application.properties
什么是 JVector ?
JVector 是一个纯 Java 嵌入式矢量搜索引擎。
它从其他 HNSW 向量相似性搜索实现中脱颖而出,因为它是
-
算法快速。JVector 使用受 DiskANN 和相关研究启发的最先进的图形算法,这些算法提供高召回率和低延迟。
-
实施速度快。JVector 使用 Panama SIMD API 来加速索引构建和查询。
-
内存高效。JVector 使用乘积量化来压缩向量,以便它们在搜索期间可以保留在内存中。(作为 PQ 实现的一部分,我们的 SIMD 加速 kmeans 类比 Apache Commons Math 中的类快 5 倍。
-
磁盘感知。JVector 的磁盘布局旨在在查询时执行最低的必要 IOPS。
-
并发的。索引构建以线性方式扩展到至少 32 个线程。线程翻倍,构建时间减半。
-
增量。在构建索引时查询索引。添加向量和在搜索结果中找到它之间没有延迟。
-
易于嵌入。API 旨在让人们在生产环境中使用它时轻松嵌入。
先决条件
-
用于计算文档嵌入的实例。这通常被配置为 Spring Bean。有几个选项可用:
Embedding
-
Transformers Embedding
- 计算本地环境中的嵌入。默认是通过 ONNX 和全 MiniLM-L6-v2 Sentence Transformers。这很有效。 -
如果要使用 OpenAI 的嵌入 - 使用 OpenAI 嵌入端点。您需要在 OpenAI Signup 上创建一个帐户,并在 API Keys 中生成 api-key 令牌。
-
还有更多选择,请参阅文档。
Embeddings API
-
-
一个 Apache Cassandra 实例,版本 5.0-beta1
-
对于托管产品, Astra DB 提供健康的免费套餐产品。
依赖
将这些依赖项添加到您的项目中:
-
仅适用于 Cassandra Vector Store
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-cassandra-store</artifactId>
</dependency>
-
或者,对于 RAG 应用程序中所需的一切(使用默认的 ONNX 嵌入模型)
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-cassandra-store-spring-boot-starter</artifactId>
</dependency>
请参阅 Dependency Management 部分,将 Spring AI BOM 添加到您的构建文件中。 |
配置属性
您可以在 Spring Boot 配置中使用以下属性来自定义 Apache Cassandra 矢量存储。
财产 | 默认值 |
---|---|
|
springframework (英文) |
|
ai_vector_store |
|
假 |
|
|
|
内容 |
|
嵌入 |
|
假 |
|
16 |
用法
创建连接到 Apache Cassandra 数据库的 CassandraVectorStore 实例:
@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
CassandraVectorStoreConfig config = CassandraVectorStoreConfig.builder().build();
return new CassandraVectorStore(config, embeddingModel);
}
默认配置连接到 Cassandra,并将自动在 keyspace , table 中创建默认模式。 |
Cassandra Java Driver 最容易通过 Classpath 上的文件进行配置。更多信息在这里。 |
然后在主代码中,创建一些文档:
List<Document> documents = List.of(
new Document("Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!! Spring AI rocks!!", Map.of("country", "UK", "year", 2020)),
new Document("The World is Big and Salvation Lurks Around the Corner", Map.of()),
new Document("You walk forward facing the past and you turn back toward the future.", Map.of("country", "NL", "year", 2023)));
现在将文档添加到您的 vector 存储中:
vectorStore.add(documents);
最后,检索类似于查询的文档:
List<Document> results = vectorStore.similaritySearch(
SearchRequest.query("Spring").withTopK(5));
如果一切顺利,您应该检索包含文本 “Spring AI rocks!!” 的文档。
您还可以根据相似性阈值限制结果:
List<Document> results = vectorStore.similaritySearch(
SearchRequest.query("Spring").withTopK(5)
.withSimilarityThreshold(0.5d));
元数据筛选
您还可以将通用的可移植元数据筛选器与 CassandraVectorStore 结合使用。必须在 中配置元数据列。CassandraVectorStoreConfig
例如,您可以使用文本表达式语言:
vectorStore.similaritySearch(
SearchRequest.query("The World").withTopK(TOP_K)
.withFilterExpression("country in ['UK', 'NL'] && year >= 2020"));
或者以编程方式使用表达式 DSL:
Filter.Expression f = new FilterExpressionBuilder()
.and(f.in("country", "UK", "NL"), this.f.gte("year", 2020)).build();
vectorStore.similaritySearch(
SearchRequest.query("The World").withTopK(TOP_K)
.withFilterExpression(f));
可移植的筛选表达式会自动转换为 CQL 查询。
要使元数据列可搜索,它们必须是主键或 SAI 索引。要使非主键列编制索引,请使用 .SchemaColumnTags.INDEXED
高级示例:Vector Store 位于完整的 Wikipedia 数据集之上
以下示例演示如何在现有架构上使用存储。在这里,我们使用 github.com/datastax-labs/colbert-wikipedia-data 项目中的架构,该项目附带了为您准备好的完整维基百科数据集。
用法
首先在 Cassandra 数据库中创建架构:
wget https://s.apache.org/colbert-wikipedia-schema-cql -O colbert-wikipedia-schema.cql
cqlsh -f colbert-wikipedia-schema.cql
然后配置存储,如下所示:
@Bean
public CassandraVectorStore store(EmbeddingModel embeddingModel) {
List<SchemaColumn> partitionColumns = List.of(new SchemaColumn("wiki", DataTypes.TEXT),
new SchemaColumn("language", DataTypes.TEXT), new SchemaColumn("title", DataTypes.TEXT));
List<SchemaColumn> clusteringColumns = List.of(new SchemaColumn("chunk_no", DataTypes.INT),
new SchemaColumn("bert_embedding_no", DataTypes.INT));
List<SchemaColumn> extraColumns = List.of(new SchemaColumn("revision", DataTypes.INT),
new SchemaColumn("id", DataTypes.INT));
CassandraVectorStoreConfig conf = CassandraVectorStoreConfig.builder()
.withKeyspaceName("wikidata")
.withTableName("articles")
.withPartitionKeys(partitionColumns)
.withClusteringKeys(clusteringColumns)
.withContentColumnName("body")
.withEmbeddingColumndName("all_minilm_l6_v2_embedding")
.withIndexName("all_minilm_l6_v2_ann")
.disallowSchemaChanges()
.addMetadataColumns(extraColumns)
.withPrimaryKeyTranslator((List<Object> primaryKeys) -> {
// the deliminator used to join fields together into the document's id is arbitary
// here "§¶" is used
if (primaryKeys.isEmpty()) {
return "test§¶0";
}
return format("%s§¶%s", primaryKeys.get(2), primaryKeys.get(3));
})
.withDocumentIdTranslator((id) -> {
String[] parts = id.split("§¶");
String title = parts[0];
int chunk_no = 0 < parts.length ? Integer.parseInt(parts[1]) : 0;
return List.of("simplewiki", "en", title, chunk_no, 0);
})
.build();
return new CassandraVectorStore(conf, embeddingModel());
}
@Bean
public EmbeddingModel embeddingModel() {
// default is ONNX all-MiniLM-L6-v2 which is what we want
return new TransformersEmbeddingModel();
}
完整的维基百科数据集
而且,如果您想加载完整的 wikipedia 数据集。
首先从此链接下载 s.apache.org/simplewiki-sstable-tar 。这将需要一段时间,文件有几十 GB。simplewiki-sstable.tar
tar -xf simplewiki-sstable.tar -C ${CASSANDRA_DATA}/data/wikidata/articles-*/
nodetool import wikidata articles ${CASSANDRA_DATA}/data/wikidata/articles-*/
如果此表中已有数据,则需要检查 tarball 的文件在执行 .tar |
另一种方法是重新启动 Cassandra。nodetool import |
如果索引中出现任何故障,它们将自动重建。 |