此版本仍在开发中,尚未被视为稳定版本。最新的快照版本请使用 Spring AI 1.0.0-SNAPSHOT! |
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 用例,例如语义搜索、地理位置邻近搜索等。
存储将根据其配置根据需要自动创建或增强架构。如果您不需要 schema 修改,请使用disallowSchemaChanges
.
使用 spring-boot-autoconfigure 时disallowSchemaChanges
根据 Spring Boot 标准,默认为 true,您必须通过设置…initialize-schema=true
在application.properties
文件。
什么是 JVector?
JVector 是一个纯 Java 嵌入式矢量搜索引擎。
它从其他 HNSW 向量相似性搜索实现中脱颖而出,具有以下特点:
-
算法快速。JVector 使用受 DiskANN 和相关研究启发的最先进的图形算法,这些算法提供高召回率和低延迟。
-
实施速度快。JVector 使用 Panama SIMD API 来加速索引构建和查询。
-
内存高效。JVector 使用乘积量化来压缩向量,以便它们在搜索期间可以保留在内存中。
-
磁盘感知。JVector 的磁盘布局旨在在查询时执行最低的必要 IOPS。
-
并发的。索引构建以线性方式扩展到至少 32 个线程。线程翻倍,构建时间减半。
-
增量。在构建索引时查询索引。添加向量和在搜索结果中找到它之间没有延迟。
-
易于嵌入。API 旨在让人们在生产环境中使用它时轻松嵌入。
先决条件
-
一个
EmbeddingModel
实例来计算文档嵌入。这通常被配置为 Spring Bean。有几个选项可用:-
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 提供健康的免费套餐产品。
依赖
对于依赖项管理,我们建议使用 Spring AI BOM,如依赖项管理部分所述。 |
将这些依赖项添加到您的项目中:
-
仅适用于 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>
配置属性
您可以在 Spring Boot 配置中使用以下属性来自定义 Apache Cassandra 矢量存储。
财产 | 默认值 |
---|---|
|
springframework (英文) |
|
ai_vector_store |
|
假 |
|
|
|
内容 |
|
嵌入 |
|
16 |
用法
基本用法
创建一个 CassandraVectorStore 实例作为 Spring Bean:
@Bean
public VectorStore vectorStore(CqlSession session, EmbeddingModel embeddingModel) {
return CassandraVectorStore.builder(embeddingModel)
.session(session)
.keyspace("my_keyspace")
.table("my_vectors")
.build();
}
拥有矢量存储实例后,您可以添加文档并执行搜索:
// Add documents
vectorStore.add(List.of(
new Document("1", "content1", Map.of("key1", "value1")),
new Document("2", "content2", Map.of("key2", "value2"))
));
// Search with filters
List<Document> results = vectorStore.similaritySearch(
SearchRequest.query("search text")
.withTopK(5)
.withSimilarityThreshold(0.7f)
.withFilterExpression("metadata.key1 == 'value1'")
);
高级配置
对于更复杂的用例,您可以在 Spring Bean 中配置其他设置:
@Bean
public VectorStore vectorStore(CqlSession session, EmbeddingModel embeddingModel) {
return CassandraVectorStore.builder(embeddingModel)
.session(session)
.keyspace("my_keyspace")
.table("my_vectors")
// Configure primary keys
.partitionKeys(List.of(
new SchemaColumn("id", DataTypes.TEXT),
new SchemaColumn("category", DataTypes.TEXT)
))
.clusteringKeys(List.of(
new SchemaColumn("timestamp", DataTypes.TIMESTAMP)
))
// Add metadata columns with optional indexing
.addMetadataColumns(
new SchemaColumn("category", DataTypes.TEXT, SchemaColumnTags.INDEXED),
new SchemaColumn("score", DataTypes.DOUBLE)
)
// Customize column names
.contentColumnName("text")
.embeddingColumnName("vector")
// Performance tuning
.fixedThreadPoolExecutorSize(32)
// Schema management
.disallowSchemaChanges(false)
// Custom batching strategy
.batchingStrategy(new TokenCountBatchingStrategy())
.build();
}
连接配置
有两种方法可以配置与 Cassandra 的连接:
-
使用注入的 CqlSession(推荐):
@Bean
public VectorStore vectorStore(CqlSession session, EmbeddingModel embeddingModel) {
return CassandraVectorStore.builder(embeddingModel)
.session(session)
.keyspace("my_keyspace")
.table("my_vectors")
.build();
}
-
直接在生成器中使用连接详细信息:
@Bean
public VectorStore vectorStore(EmbeddingModel embeddingModel) {
return CassandraVectorStore.builder(embeddingModel)
.contactPoint(new InetSocketAddress("localhost", 9042))
.localDatacenter("datacenter1")
.keyspace("my_keyspace")
.build();
}
元数据筛选
您可以将通用的可移植元数据筛选器与 CassandraVectorStore 结合使用。要使元数据列可搜索,它们必须是主键或 SAI 索引。要使非主键列编制索引,请使用SchemaColumnTags.INDEXED
.
例如,您可以使用文本表达式语言:
vectorStore.similaritySearch(
SearchRequest.builder().query("The World")
.topK(5)
.filterExpression("country in ['UK', 'NL'] && year >= 2020").build());
或者以编程方式使用表达式 DSL:
Filter.Expression f = new FilterExpressionBuilder()
.and(
f.in("country", "UK", "NL"),
f.gte("year", 2020)
).build();
vectorStore.similaritySearch(
SearchRequest.builder().query("The World")
.topK(5)
.filterExpression(f).build());
可移植的筛选表达式会自动转换为 CQL 查询。
高级示例:Vector Store on top of Wikipedia Dataset
以下示例演示如何在现有架构上使用存储。在这里,我们使用 github.com/datastax-labs/colbert-wikipedia-data 项目中的架构,该项目附带了为您准备好的完整 wikipedia 数据集。
首先,在 Cassandra 数据库中创建架构:
wget https://s.apache.org/colbert-wikipedia-schema-cql -O colbert-wikipedia-schema.cql
cqlsh -f colbert-wikipedia-schema.cql
然后使用生成器模式配置 store:
@Bean
public VectorStore vectorStore(CqlSession session, 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)
);
return CassandraVectorStore.builder()
.session(session)
.embeddingModel(embeddingModel)
.keyspace("wikidata")
.table("articles")
.partitionKeys(partitionColumns)
.clusteringKeys(clusteringColumns)
.contentColumnName("body")
.embeddingColumnName("all_minilm_l6_v2_embedding")
.indexName("all_minilm_l6_v2_ann")
.disallowSchemaChanges(true)
.addMetadataColumns(extraColumns)
.primaryKeyTranslator((List<Object> primaryKeys) -> {
if (primaryKeys.isEmpty()) {
return "test§¶0";
}
return String.format("%s§¶%s", primaryKeys.get(2), primaryKeys.get(3));
})
.documentIdTranslator((id) -> {
String[] parts = id.split("§¶");
String title = parts[0];
int chunk_no = parts.length > 1 ? Integer.parseInt(parts[1]) : 0;
return List.of("simplewiki", "en", title, chunk_no, 0);
})
.build();
}
@Bean
public EmbeddingModel embeddingModel() {
// default is ONNX all-MiniLM-L6-v2 which is what we want
return new TransformersEmbeddingModel();
}
加载完整的 Wikipedia 数据集
要加载完整的 wikipedia 数据集:
-
下载
simplewiki-sstable.tar
从 s.apache.org/simplewiki-sstable-tar 开始(这需要一段时间,文件有几十 GB) -
加载数据:
tar -xf simplewiki-sstable.tar -C ${CASSANDRA_DATA}/data/wikidata/articles-*/ nodetool import wikidata articles ${CASSANDRA_DATA}/data/wikidata/articles-*/
|
访问 Native Client
Cassandra Vector Store 实现提供对底层原生 Cassandra 客户端 (CqlSession
) 通过getNativeClient()
方法:
CassandraVectorStore vectorStore = context.getBean(CassandraVectorStore.class);
Optional<CqlSession> nativeClient = vectorStore.getNativeClient();
if (nativeClient.isPresent()) {
CqlSession session = nativeClient.get();
// Use the native client for Cassandra-specific operations
}
本机客户端允许您访问特定于 Cassandra 的功能和作,这些功能和作可能不会通过VectorStore
接口。