最新快照版本请使用Spring AI 1.1.0spring-doc.cadn.net.cn

Apache Cassandra 向量存储

本节将引导你如何设置CassandraVectorStore用于存储文档嵌入并进行相似性搜索。spring-doc.cadn.net.cn

什么是Apache Cassandra?

Apache Cassandra® 是一个真正的开源分布式数据库,以线性可扩展性、经过验证的容错性和低延迟著称,是关键任务事务数据的理想平台。spring-doc.cadn.net.cn

其向量相似度搜索(VSS)基于JVector库,确保同级最佳性能和相关性。spring-doc.cadn.net.cn

Apache Cassandra 中的向量搜索方法很简单:spring-doc.cadn.net.cn

SELECT content FROM table ORDER BY content_vector ANN OF query_embedding;

更多相关文档可以在这里阅读。spring-doc.cadn.net.cn

这个Spring AI向量商店设计时既适用于全新的RAG应用,也能在现有数据和表格基础上进行改造。spring-doc.cadn.net.cn

该存储还可以用于现有数据库中的非 RAG 用例,例如语义搜索、地理邻近搜索等。spring-doc.cadn.net.cn

存储会自动根据配置创建或增强该模式。如果你不想修改模式,可以配置存储初始化模式.spring-doc.cadn.net.cn

使用 spring-boot-autoconfigure 时初始化模式默认为false根据 Spring Boot 标准,你必须通过设置来选择加入模式的创建/修改…​initialize-schema=trueapplication.properties文件。spring-doc.cadn.net.cn

什么是JVector?

JVector 是一个纯粹的 Java 嵌入式向量搜索引擎。spring-doc.cadn.net.cn

它与其他HNSW向量相似性搜索实现不同,特点如下:spring-doc.cadn.net.cn

  • 算法快速。JVector 采用了受 DiskANN 及相关研究启发的先进图算法,具备高召回率和低延迟。spring-doc.cadn.net.cn

  • 实施快速。JVector 使用巴拿马 SIMD API 来加速索引构建和查询。spring-doc.cadn.net.cn

  • 内存高效。JVector 通过乘积量化压缩向量,使其在搜索时能够保持内存。spring-doc.cadn.net.cn

  • 磁盘感知。JVector 的磁盘布局设计为在查询时执行最低必要的IOPS。spring-doc.cadn.net.cn

  • 并发的。Index 构建线性扩展,至少可达32个线程。螺纹数量翻倍,制作时间减半。spring-doc.cadn.net.cn

  • 增量。在构建索引时查询它。添加向量到能在搜索结果中找到之间没有延迟。spring-doc.cadn.net.cn

  • 很容易嵌入。API 设计方便人们在生产环境中使用,方便嵌入。spring-doc.cadn.net.cn

前提条件

  1. 一个嵌入模型实例用于计算文档嵌入。这通常被配置为春豆。有几种选择:spring-doc.cadn.net.cn

  2. Apache Cassandra 实例,版本 5.0-beta1spring-doc.cadn.net.cn

    1. DIY快速入门spring-doc.cadn.net.cn

    2. 作为托管套餐,Astra DB提供健康的免费套餐。spring-doc.cadn.net.cn

依赖

春季AI自动配置、起始模块的工件名称发生了重大变化。 更多信息请参阅升级说明spring-doc.cadn.net.cn

依赖管理方面,我们建议使用依赖管理部分中解释的 Spring AI 物料清单。

将以下依赖项添加到你的项目中:spring-doc.cadn.net.cn

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-cassandra-store</artifactId>
</dependency>
  • 或者,对于RAG应用中你需要的所有内容(使用默认的ONNX嵌入模型):spring-doc.cadn.net.cn

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-vector-store-cassandra</artifactId>
</dependency>

配置属性

你可以在 Spring Boot 配置中使用以下属性来自定义 Apache Cassandra 向量存储。spring-doc.cadn.net.cn

属性 默认值

spring.ai.vectorstore.cassandra.keyspacespring-doc.cadn.net.cn

Springframeworkspring-doc.cadn.net.cn

spring.ai.vectorstore.cassandra.tablespring-doc.cadn.net.cn

ai_vector_storespring-doc.cadn.net.cn

Spring.ai.vectorstore.cassandra.initialize-schemaspring-doc.cadn.net.cn

falsespring-doc.cadn.net.cn

spring.ai.vectorstore.cassandra.index-namespring-doc.cadn.net.cn

spring.ai.vectorstore.cassandra.content-column-namespring-doc.cadn.net.cn

内容spring-doc.cadn.net.cn

spring.ai.vectorstore.cassandra.embedding-column-namespring-doc.cadn.net.cn

嵌入spring-doc.cadn.net.cn

spring.ai.vectorstore.cassandra.fixed-thread-pool-executor-sizespring-doc.cadn.net.cn

16spring-doc.cadn.net.cn

用法

基本用途

创建一个CassandraVectorStore实例作为Spring Bean:spring-doc.cadn.net.cn

@Bean
public VectorStore vectorStore(CqlSession session, EmbeddingModel embeddingModel) {
    return CassandraVectorStore.builder(embeddingModel)
        .session(session)
        .keyspace("my_keyspace")
        .table("my_vectors")
        .build();
}

一旦你有了向量存储实例,就可以添加文档并进行搜索:spring-doc.cadn.net.cn

// 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 中配置更多设置:spring-doc.cadn.net.cn

@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连接有两种方式:spring-doc.cadn.net.cn

@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.spring-doc.cadn.net.cn

例如,你可以使用以下文本表达式语言:spring-doc.cadn.net.cn

vectorStore.similaritySearch(
    SearchRequest.builder().query("The World")
        .topK(5)
        .filterExpression("country in ['UK', 'NL'] && year >= 2020").build());

或通过程序化使用表达式 DSL:spring-doc.cadn.net.cn

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查询spring-doc.cadn.net.cn

高级示例:维基百科数据集之上的矢量存储

以下示例演示了如何在现有模式上使用存储。这里我们使用 github.com/datastax-labs/colbert-wikipedia-data 项目的模式,里面附带完整的维基百科数据集,已经为你矢量化。spring-doc.cadn.net.cn

首先,在Cassandra数据库中创建该模式:spring-doc.cadn.net.cn

wget https://s.apache.org/colbert-wikipedia-schema-cql -O colbert-wikipedia-schema.cql
cqlsh -f colbert-wikipedia-schema.cql

然后用构建模式配置存储:spring-doc.cadn.net.cn

@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();
}

加载完整的维基百科数据集

要加载完整的维基百科数据集:spring-doc.cadn.net.cn

  1. 下载simplewiki-sstable.tar来自 s.apache.org/simplewiki-sstable-tar(这会花点时间,文件有几十GB)spring-doc.cadn.net.cn

  2. 加载数据:spring-doc.cadn.net.cn

tar -xf simplewiki-sstable.tar -C ${CASSANDRA_DATA}/data/wikidata/articles-*/
nodetool import wikidata articles ${CASSANDRA_DATA}/data/wikidata/articles-*/

访问本地客户端

Cassandra 向量存储实现提供了对底层原生 Cassandra 客户端的访问(CqlSession)通过getNativeClient()方法:spring-doc.cadn.net.cn

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接口。spring-doc.cadn.net.cn