Apache Cassandra Vector Store
本节将引导您完成配置CassandraVectorStore以存储文档嵌入并执行相似性搜索的过程。
什么是阿帕奇·卡斯丹纳?What is Apache Cassandra?
Apache Cassandra® 是一款真正开放源代码的分布式数据库,以其线性可扩展性、 proven fault-tolerance 和低延迟著称,是实现关键事务数据的完美平台。
其向量相似性搜索(VSS)基于JVector库,能够确保最佳级别的性能和相关性。
在Apache Cassandra中进行向量搜索实现起来非常简单:
SELECT content FROM table ORDER BY content_vector ANN OF query_embedding;
更多文档在此处阅读 这里.
本Spring AI向量存储旨在支持全新的RAG应用,并且能够嵌入现有数据和表。
该存储库还可以在现有数据库中用于非RAG场景,例如语义搜索、地理位置搜索等。
The store will automatically create, or enhance, the schema as needed according to its configuration. If you don’t want the schema modifications, configure the store with initializeSchema.
当使用 spring-boot-autoconfigure 0,默认会设置为 1,按照 Spring Boot 标准。并且,您必须启用数据库创建或修改功能,通过在 3 文件中设置 2。
什么是JVector?
JVector 是一个基于Java的嵌入式向量搜索引擎。
它之所以脱颖而出,是因为它是高效率且可扩展的相似性搜索框架(Java版本)。
-
算法快速版。JVector采用了最先进的图算法,这些算法受到DiskANN及相关研究的启发,并且在高召回率和低延迟方面表现优异。
-
实现非常快速。JVector使用PANAMA SIMD API来加速索引构建和查询。
-
内存高效。JVector通过乘积量化方法压缩向量,以便在搜索过程中保持内存中的状态。
-
磁盘意识的。JVector的磁盘布局设计为尽量减少查询时所需的I/O操作。
-
多线程池规模按线性方式增长,当线程数达到至少32个时,线程数加倍,构建时间减半。
-
增量式。在构建索引的同时实时查询。无需在添加向量和搜索结果之间有任何延迟。
-
易嵌入。API是为易嵌入而设计的,由使用它在生产中的人开发的。
前提条件
-
A
EmbeddingModel实例来计算文档嵌入。通常,这会被配置为SpringBean。有几个选项可用:-
Transformers Embedding- 在你的本地环境中计算嵌入。默认方式是通过ONNX和all-MiniLM-L6-v2 Sentence Transformers实现的。这就可以了。 -
如果要使用 OpenAI 的嵌入式服务 - 请使用 OpenAI 的嵌入式服务端点。您需要在 OpenAI 签up 账户并生成 API密钥。
-
There are many more choices, see
Embeddings APIdocs.
-
-
一个Apache Cassandra实例,版本号5.0-内测版
依赖项
|
There has been a significant change in the Spring AI auto-configuration, starter modules' artifact names. Please refer to the 升级说明以获取更多信息。 |
| 对于依赖管理,我们推荐使用Spring AI BOM,如《依赖管理》部分所述。 |
将这些依赖项添加到您的项目中:
-
仅用于Cassandra向量存储:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-cassandra-store</artifactId>
</dependency>
-
或者,对于一个使用默认ONNX嵌入模型的检索增强生成应用(RAG)来说,您需要的所有内容是:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-cassandra</artifactId>
</dependency>
配置属性
你可以使用以下属性在Spring Boot配置中自定义Apache Cassandra向量存储。
| 属性 | 默认值 |
|---|---|
|
Spring Framework |
|
ai_vector_store |
|
false |
|
|
|
内容 |
|
嵌入 |
|
16 |
用法
基本用法
创建一个Cassandra向量存储实例作为SpringBean:
@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'")
);
高级配置
对于更复杂的场景,您可以在您的SpringBean中配置额外的设置:
@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();
}
元数据过滤
你可以利用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 查询。
高级示例:在维基百科数据集上构建向量存储
The following example demonstrates how to use the store on an existing schema. Here we use the schema from the github.com/datastax-labs/colbert-wikipedia-data project which comes with the full wikipedia dataset ready vectorized for you.
首先,在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();
}
载入完整的维基百科数据集
加载整个维基百科数据集:
-
Download
零from 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-*/
|
访问原生客户端
Cassandra向量存储实现通过提供的内建的Cassandra客户端(0)实现了(1)方法。
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
}
native client提供访问 Cassandra 特定功能和操作的方式,这些功能和操作可能不会通过 VectorStore 接口暴露出来。