Apache Cassandra Vector Store
本节将引导您设置 CassandraVectorStore
,以存储文档嵌入并执行相似性搜索。
什么是 Cassandra?
Apache Cassandra® 是一款真正的开源分布式数据库,以其线性可扩展性、经过验证的容错能力和低延迟而闻名,是处理关键事务数据的理想平台。
其向量最近邻搜索(VSS)基于 JVector 库,确保了顶级的性能和相关性。
在 Cassandra 中进行向量搜索操作简单如下:
SELECT content FROM table ORDER BY content_vector ANN OF query_embedding;
这款 Spring AI 向量存储库旨在既适用于全新的 RAG 应用,又能无缝集成到现有数据和表格之上。
该存储同样适用于现有数据库中的非 RAG 应用场景,例如语义搜索、地理位置邻近搜索等。
商店将根据其配置自动创建或增强模式。如果您不希望模式被修改,请通过 initializeSchema 配置商店。
使用 spring-boot-autoconfigure
时,按照 Spring Boot 的标准,initializeSchema
默认为 false,您必须通过在 application.properties
文件中设置 initialize-schema=true
来明确选择启用模式创建 / 修改。
什么是 JVector?
JVector 是一个纯 Java 嵌入式向量搜索引擎。
它之所以在众多 HNSW 向量最近邻搜索实现中脱颖而出,原因在于:
- 算法高效:JVector 采用了受 DiskANN 及相关研究启发的尖端图算法,确保了高召回率和低延迟。
- 实现迅速:JVector 采用 Panama SIMD API 加速索引构建与查询过程。
- 内存高效:JVector 采用乘积量化技术压缩向量,确保其在搜索过程中能常驻内存。
- 磁盘优化:JVector 的磁盘布局设计旨在查询时执行最少的必要 IOPS 操作。
- 并发性:索引构建至少可线性扩展至 32 线程。线程数翻倍,构建时间减半。
- 增量式:在构建索引的同时即可进行查询。添加向量后,无需等待即可在搜索结果中找到它。
- 易于集成:API 设计旨在简化嵌入过程,深受生产环境使用者的青睐。
先决条件
- 用于计算文档嵌入的 EmbeddingModel 实例。通常配置为 Spring Bean,有多种选项可供选择:
- Transformers 嵌入 —— 在您的本地环境中计算嵌入。默认通过 ONNX 和 all-MiniLM-L6-v2 Sentence Transformers 实现。开箱即用。
- 若欲使用 OpenAI 的嵌入功能 —— 需调用 OpenAI 的嵌入端点。请先在 OpenAI 注册页面 创建账户,并在 API 密钥 处生成 API 密钥令牌。
- 还有更多选择,请参阅 Embeddings API 文档。
- 一个 Cassandra 实例,自 5.0-beta1 版本起
依赖关系
对于依赖管理,我们建议按照 依赖管理 章节所述,使用 Spring AI BOM。
将这些依赖项添加到您的项目中:
- 仅针对 Cassandra 向量存储:
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-cassandra-store</artifactId> </dependency>
- 或者,获取构建 RAG 应用所需的一切(使用默认的 ONNX 嵌入模型):
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-vector-store-cassandra</artifactId> </dependency>
配置属性
您可以在 Spring Boot 配置中使用以下属性来自定义 Cassandra 向量存储。
使用用例
基本使用用例
创建 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
.initializeSchema(true)
// 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(); }
元数据过滤(Metadata Filtering)
您可以利用 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 查询 。
高级示例:基于维基百科数据集的向量存储
以下示例展示了如何在现有模式上使用存储。这里我们采用 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 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")
.initializeSchema(false)
.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();
}
加载完整的维基百科数据集
要加载完整的维基百科数据集:
- 从 s.apache.org/simplewiki-sstable-tar 下载 simplewiki-sstable.tar(这将需要一些时间,文件大小达数十 GB)。
- 加载数据:
tar -xf simplewiki-sstable.tar -C ${CASSANDRA_DATA}/data/wikidata/articles-*/ nodetool import wikidata articles ${CASSANDRA_DATA}/data/wikidata/articles-*/
访问原生客户端
Cassandra 向量存储实现通过‘getNativeClient ()‘方法提供了对底层原生 Cassandra 客户端(CqlSession)的访问:
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
}
原生客户端使您能够访问可能未通过 VectorStore
接口暴露的 Cassandra
特有功能和操作。
最后编辑:Jeebiz 更新时间:2025-09-10 21:18