Skip to content
LangChain4j 文档版本 1.22.0 源快照 91516dfc 更新于 2026-10-14

CockroachDB

CockroachDB 是一个讲 PostgreSQL 线路协议的分布式 SQL 数据库。自 v24.2 起,它自带一个原生 VECTOR 列类型;自 v25.2 起,它提供一个称为 C-SPANN 的分布式近似最近邻索引。langchain4j-community-cockroachdb 模块把二者作为以下方式与 LangChain4j 集成:

  • 一个向量 EmbeddingStore<TextSegment>(CockroachDbEmbeddingStore)
  • 一个 ChatMemoryStore(CockroachDbChatMemoryStore)

该 Java 模块在存在 Java 对应物的地方,镜像了官方 Python langchain-cockroachdb 库的特性集。

版本要求

特性CockroachDB 最低版本
VECTOR(n) 列类型v24.2
CREATE VECTOR INDEX(C-SPANN)v25.2
通过 ttl_expiration_expression 的行级 TTLv23.1

在 CockroachDB v25.2 上,向量索引由一个集群设置把关。在用 CSpannIndex 创建存储之前,先在集群上启用它一次:

sql
SET CLUSTER SETTING feature.vector_index.enabled = true;

Maven 依赖

NOTE

由于 CockroachDB 支持属于 langchain4j-community,它将从 1.22.0-beta32 或更新版本起可用。

xml
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-community-cockroachdb</artifactId>
    <version>1.22.0-beta32</version>
</dependency>

如果你导入 Community BOM,可以省略版本号。

API

该模块暴露四个公共类:

CockroachDbEngine

包装一个 HikariCP DataSource 并处理连接池。它可以从独立的 host/port/database/username/password 字段、从一个完整的连接字符串(Python 风格的 cockroachdb:// scheme 会被自动改写为 jdbc:postgresql://),或经由 CockroachDbEngine.from(dataSource) 从一个已有的 DataSource 构建。

CockroachDbSchema

封装嵌入表布局:表名与列名、向量维度、距离度量、用于多租户的可选命名空间列、所选的向量索引策略,以及一个用于未来混合搜索的可选生成 tsvector 列。

CockroachDbEmbeddingStore

针对原生 CockroachDB VECTOR 列实现了 LangChain4j 的 EmbeddingStore<TextSegment>。支持批量插入、JSONB 元数据过滤、按 id / 按 Filter / 批量移除、可选的命名空间作用域,以及针对 C-SPANN 的可选逐查询 vector_search_beam_size 调优。

CockroachDbChatMemoryStore

实现了 LangChain4j 的 ChatMemoryStore。它把序列化后的聊天消息持久化在一个 JSONB 列中,按一个显式的插入序号排序,并可选带行级 TTL。

连接

CockroachDbEngine 包装一个 HikariDataSource。你可以从一个连接字符串或从独立字段构建它。

java
import dev.langchain4j.community.store.embedding.cockroachdb.CockroachDbEngine;

CockroachDbEngine engine = CockroachDbEngine.builder()
        .host("localhost")
        .port(26257)
        .database("defaultdb")
        .username("root")
        .password("")
        .sslMode("disable")
        .build();

builder 也接受一个完整的连接字符串。Python 风格的 cockroachdb:// scheme 会被自动改写为 jdbc:postgresql://,因此你可以直接粘贴 Python 库所用的那个 URL:

java
CockroachDbEngine engine = CockroachDbEngine.fromConnectionString(
        "cockroachdb://root@localhost:26257/defaultdb?sslmode=disable");

如果你已有一个 DataSource,请使用 CockroachDbEngine.from(dataSource)。

向量存储

一个最小的向量存储使用顺序扫描(NoIndex),它适合小数据集与测试:

java
import dev.langchain4j.community.store.embedding.cockroachdb.CockroachDbEmbeddingStore;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.allminilml6v2q.AllMiniLmL6V2QuantizedEmbeddingModel;

EmbeddingModel model = new AllMiniLmL6V2QuantizedEmbeddingModel();

CockroachDbEmbeddingStore store = CockroachDbEmbeddingStore.builder()
        .engine(engine)
        .dimension(model.dimension())
        .tableName("embeddings")
        .build();

TextSegment segment = TextSegment.from("Cockroaches are surprisingly resilient.");
Embedding embedding = model.embed(segment).content();
store.add(embedding, segment);

对于 CockroachDB v25.2+ 上的生产工作负载,请添加一个 C-SPANN 向量索引:

java
import dev.langchain4j.community.store.embedding.cockroachdb.index.CSpannIndex;

CockroachDbEmbeddingStore store = CockroachDbEmbeddingStore.builder()
        .engine(engine)
        .dimension(model.dimension())
        .vectorIndex(CSpannIndex.builder()
                .minPartitionSize(16)
                .maxPartitionSize(128)
                .build())
        .build();

为该索引发出的 DDL 是:

sql
CREATE VECTOR INDEX IF NOT EXISTS embeddings_embedding_vector_idx
  ON public.embeddings (embedding)
  WITH (min_partition_size = 16, max_partition_size = 128);

C-SPANN 会从查询运算符挑选距离函数(余弦用 <=>、L2 用 <->、内积用 <#>),因此 MetricType 是在存储上于查询时选定的,而不绑定到索引。

搜索

EmbeddingSearchRequest 的用法与在任何其他 LangChain4j 存储中相同:

java
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
import dev.langchain4j.store.embedding.EmbeddingSearchResult;

EmbeddingSearchResult<TextSegment> result = store.search(
        EmbeddingSearchRequest.builder()
                .queryEmbedding(model.embed("resilience").content())
                .maxResults(5)
                .minScore(0.6)
                .build());

result.matches().forEach(m ->
        System.out.printf("%s (%.3f) %s%n", m.embeddingId(), m.score(), m.embedded().text()));

在查询时调优 C-SPANN

CockroachDB 暴露了一个会话变量 vector_search_beam_size,它控制召回/延迟的权衡。在存储 builder 上设置它,会让每次搜索都被包进一个用 SET LOCAL 限定该设置作用域的事务:

java
CockroachDbEmbeddingStore store = CockroachDbEmbeddingStore.builder()
        .engine(engine)
        .dimension(model.dimension())
        .vectorIndex(CSpannIndex.builder().build())
        .searchBeamSize(32)
        .build();

更高的值以延迟换取召回。若你把该字段留空,默认束宽由 CockroachDB 决定。

元数据过滤

元数据存储在 JSONB 列中,并在查询时用 LangChain4j 的 Filter 表达式过滤:

java
import dev.langchain4j.store.embedding.filter.MetadataFilterBuilder;

EmbeddingSearchResult<TextSegment> result = store.search(
        EmbeddingSearchRequest.builder()
                .queryEmbedding(query)
                .maxResults(10)
                .filter(MetadataFilterBuilder.metadataKey("category").isEqualTo("biology")
                        .and(MetadataFilterBuilder.metadataKey("year").isGreaterThan(2020)))
                .build());

比较过滤器(>、>=、<、<=)会把 JSONB 值转换为 numeric。字符串的相等比较的是 JSON 文本。过滤键只能包含字母数字字符、点、下划线或连字符。

用命名空间列实现多租户

要按租户限定行的作用域,请在 schema 中加一个 namespaceColumn,并在每个存储实例上配置一个命名空间值。该列会作为前缀加到 C-SPANN 索引上,从而使逐租户的查询保持快速:

java
CockroachDbEmbeddingStore tenantA = CockroachDbEmbeddingStore.builder()
        .engine(engine)
        .dimension(model.dimension())
        .namespaceColumn("tenant_id")
        .namespace("acme")
        .vectorIndex(CSpannIndex.builder().build())
        .build();

生成的索引变为 CREATE VECTOR INDEX ... ON embeddings (tenant_id, embedding),且经由该存储执行的每次读/写都会被过滤到 tenant_id = 'acme'。

可选的全文列

如果你打算之后把向量搜索与全文搜索结合,请在建表时启用一个生成的 tsvector 列。一个 GIN 索引会随之创建:

java
CockroachDbEmbeddingStore store = CockroachDbEmbeddingStore.builder()
        .engine(engine)
        .dimension(model.dimension())
        .createTsvectorColumn(true)
        .build();

混合(向量 + FTS)查询执行尚未实现;创建该列是为了它能被应用代码或未来版本使用。

聊天记忆

CockroachDbChatMemoryStore 实现了 ChatMemoryStore,并把序列化后的聊天消息持久化在一个按插入时间排序的 JSONB 列中:

java
import dev.langchain4j.community.store.memory.chat.cockroachdb.CockroachDbChatMemoryStore;

CockroachDbChatMemoryStore memory = CockroachDbChatMemoryStore.builder()
        .engine(engine)
        .tableName("chat_memory")
        .build();

其结构为:

sql
CREATE TABLE chat_memory (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  session_id TEXT NOT NULL,
  message JSONB NOT NULL,
  created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX chat_memory_session_idx ON chat_memory (session_id, created_at);

updateMessages 在一个事务内替换整个会话,因此部分写入对读者不可见。

行级 TTL

CockroachDB 能自动让行过期。传入一个 ttl 时长,以在聊天记忆表上启用行级 TTL:

java
import java.time.Duration;

CockroachDbChatMemoryStore memory = CockroachDbChatMemoryStore.builder()
        .engine(engine)
        .tableName("chat_memory")
        .ttl(Duration.ofDays(7))
        .ttlJobCron("@daily")
        .build();

结构设置会发出:

sql
ALTER TABLE chat_memory SET (
  ttl_expiration_expression = $$(created_at + '7 days')$$,
  ttl_job_cron = '@daily'
);

要在一个已有表上禁用 TTL:

java
memory.disableTtl();

重试

当某个事务在其默认的 SERIALIZABLE 隔离级别下必须重试时,CockroachDB 会返回 SQLSTATE 40001。该存储把每个工作单元包在一个带指数退避与抖动的重试循环中(默认 5 次尝试,从 100 毫秒起,倍增至上限 10 秒)。无需额外配置。

连接字符串格式

以下形式都能被 CockroachDbEngine.fromConnectionString 接受:

形式示例
Python 风格cockroachdb://root@localhost:26257/defaultdb?sslmode=disable
psycopg 风格cockroachdb+psycopg://user:pw@host:26257/db
libpq 风格postgresql://user@host:26257/db
JDBC 风格jdbc:postgresql://localhost:26257/defaultdb

对于 CockroachDB Cloud,请使用集群控制台里的连接字符串,通常是:

cockroachdb://USER:PASSWORD@HOST:26257/DATABASE?sslmode=verify-full

参数总览

CockroachDbEngine 参数

参数描述默认值必填/可选
hostCockroachDB 服务器的主机名localhost必填(若无 connectionString)
portCockroachDB 服务器的端口号26257必填(若无 connectionString)
database要连接的数据库defaultdb必填(若无 connectionString)
username认证的用户名root必填
password认证的密码""(空)可选
schema默认 schema 名public可选
sslModeSSL 模式(disable、require、verify-full 等)disable可选
maxPoolSizeHikariCP 池的最大大小10可选
minPoolSize最小空闲连接数5可选
connectionTimeoutMs连接超时(毫秒)10000可选
idleTimeoutMs空闲超时(毫秒)300000可选
maxLifetimeMs连接最大存活时间(毫秒)3600000可选
connectionString完整 URL;设置时会覆盖独立的 host/port/dbnull可选

CockroachDbEmbeddingStore 参数

参数描述默认值必填/可选
engineCockroachDbEngine 实例无必填
dimension嵌入向量维度无必填
tableName嵌入表名embeddings可选
schemaName数据库 schema 名public可选
metricType距离度量:COSINE、EUCLIDEAN 或 DOT_PRODUCTCOSINE可选
vectorIndexCSpannIndex 或 NoIndexNoIndex(顺序扫描)可选
namespaceColumn用于多租户的租户列名null(禁用)可选
namespace在每次读与写上应用的租户值null可选,需要 namespaceColumn
searchBeamSize逐查询的 vector_search_beam_size 会话变量null(CockroachDB 默认)可选
createTableIfNotExists在构建时建表true可选
createTsvectorColumn添加一个生成的 tsvector 列 + GIN 索引false可选

CSpannIndex 参数(CockroachDB v25.2+)

参数描述默认值必填/可选
name自定义索引名{table}_{column}_vector_idx可选
minPartitionSize最小分区大小(经 WITH 发出)CockroachDB 默认可选
maxPartitionSize最大分区大小(经 WITH 发出)CockroachDB 默认可选

CockroachDbChatMemoryStore 参数

参数描述默认值必填/可选
engineCockroachDbEngine 实例无必填
tableName聊天历史表名message_store可选
schemaName数据库 schema 名public可选
ttl行级 TTL 时长;设置时在 CockroachDB 上启用 TTLnull(禁用)可选
ttlJobCronTTL 任务调度@daily可选,需要 ttl
createTableIfNotExists在构建时建表true可选

示例

一个最小的端到端 RAG 演示,它会启动一个 CockroachDB Testcontainer、为两个文本片段建索引,并运行一次相似度搜索:

java
import dev.langchain4j.community.store.embedding.cockroachdb.CockroachDbEmbeddingStore;
import dev.langchain4j.community.store.embedding.cockroachdb.CockroachDbEngine;
import dev.langchain4j.data.embedding.Embedding;
import dev.langchain4j.data.segment.TextSegment;
import dev.langchain4j.model.embedding.EmbeddingModel;
import dev.langchain4j.model.embedding.onnx.allminilml6v2.AllMiniLmL6V2EmbeddingModel;
import dev.langchain4j.store.embedding.EmbeddingMatch;
import dev.langchain4j.store.embedding.EmbeddingSearchRequest;
import dev.langchain4j.store.embedding.EmbeddingStore;
import java.util.List;
import org.testcontainers.containers.CockroachContainer;

public class CockroachDbEmbeddingStoreExample {

    public static void main(String[] args) {
        try (CockroachContainer cockroach = new CockroachContainer("cockroachdb/cockroach:latest-v25.2")) {
            cockroach.start();

            CockroachDbEngine engine = CockroachDbEngine.builder()
                    .connectionString(cockroach.getJdbcUrl())
                    .username(cockroach.getUsername())
                    .password(cockroach.getPassword())
                    .build();

            EmbeddingModel embeddingModel = new AllMiniLmL6V2EmbeddingModel();

            EmbeddingStore<TextSegment> embeddingStore = CockroachDbEmbeddingStore.builder()
                    .engine(engine)
                    .dimension(embeddingModel.dimension())
                    .tableName("demo_embeddings")
                    .build();

            TextSegment segment1 = TextSegment.from("I like football.");
            Embedding embedding1 = embeddingModel.embed(segment1).content();
            embeddingStore.add(embedding1, segment1);

            TextSegment segment2 = TextSegment.from("The weather is good today.");
            Embedding embedding2 = embeddingModel.embed(segment2).content();
            embeddingStore.add(embedding2, segment2);

            Embedding queryEmbedding = embeddingModel.embed("What is your favourite sport?").content();
            EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
                    .queryEmbedding(queryEmbedding)
                    .maxResults(1)
                    .build();

            List<EmbeddingMatch<TextSegment>> matches = embeddingStore.search(request).matches();
            EmbeddingMatch<TextSegment> match = matches.get(0);

            System.out.println(match.score());           // ~0.81
            System.out.println(match.embedded().text()); // I like football.

            engine.close();
        }
    }
}

该示例使用默认的默认顺序扫描索引,因此它无需额外集群配置就能在任何 CockroachDB v24.2 或更新版本上运行。要在 v25.2 或更新版本上切换到 C-SPANN 分布式 ANN 索引,请在集群上启用该特性开关一次,并通过 .vectorIndex(...) 向存储传入 CSpannIndex.builder().build():

sql
SET CLUSTER SETTING feature.vector_index.enabled = true;

一个更完整的可运行版本位于 langchain4j-examples/cockroachdb-example。

已知限制

  • C-SPANN 向量索引需要 CockroachDB v25.2 或更新版本,且必须启用 feature.vector_index.enabled 集群设置。
  • 向量值以文本发送并用 ?::vector 转换,因为 CockroachDB 的 pgwire 层不接受 VECTOR 类型的二进制格式。
  • 混合(向量 + 全文)查询执行尚未实现。tsvector 列与 GIN 索引可通过 createTsvectorColumn 创建,以供应用代码或未来版本使用。
  • Python 的 langchain-cockroachdb 库还带有一个 LangGraph checkpointer(CockroachDBSaver 与 AsyncCockroachDBSaver)。其 Java 对应物位于第三方 langgraph4j 项目中,名为 langgraph4j-cockroachdb-saver。langgraph4j 的 checkpoint 契约没有异步 API,因此只提供同步的 CockroachDBSaver;在 JDK 21 或更新版本上的调用方可以从一个虚拟线程调用它,以获得非阻塞并发。

BytesRouter 是社区翻译站点,所有译文仅供参考,一切以官方英文原文为准。