跳到主要内容

ArcadeDB

https://arcadedb.com/

ArcadeDB 是一款多模型 NoSQL 数据库,支持图、文档、键值、时序和向量数据。它提供内置的 LSM_VECTOR 索引(由 JVector/HNSW 驱动),用于高性能近似最近邻(ANN)向量搜索。

langchain4j 集成支持两种运行模式:

  • 远程模式 — 通过 HTTP 连接到 ArcadeDB 服务器。适合生产部署和共享基础设施。
  • 嵌入模式 — 在同一 JVM 内以进程内方式运行 ArcadeDB。无需服务器或 Docker 容器;数据库存储在本地文件系统上。适合测试、桌面应用或单进程工作负载。

Maven 依赖

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-arcadedb</artifactId>
<version>${latest version here}</version>
</dependency>

注意:这是一个社区集成模块。你可能需要将 langchain4j-community 仓库添加到项目配置中。

API

  • ArcadeDBEmbeddingStore

功能

  • 两种运行模式:远程(通过 HTTP 客户端连接 ArcadeDB 服务器)或嵌入(ArcadeDB 在进程内运行,无需服务器)
  • 多模型数据库:将 embedding 作为顶点存储在 ArcadeDB 的图模型中,可与文档、键值和时序数据并存
  • HNSW 向量索引:使用 ArcadeDB 的 LSM_VECTOR 索引(基于 JVector)进行快速近似最近邻搜索
  • 元数据过滤:支持使用比较和逻辑运算符按元数据过滤搜索结果
  • 持久化存储:远程和嵌入模式下数据在重启后均保持持久
  • 自动创建模式:首次使用时自动创建顶点类型、属性和向量索引
  • 多种相似度函数:支持 COSINE(默认)、EUCLIDEAN 和 SQUARED_EUCLIDEAN 距离度量(远程模式)
  • 批量操作:单次调用添加多个 embedding
  • 灵活删除:按 ID、按过滤条件删除 embedding,或清空全部

基本用法

远程模式

远程模式连接到正在运行的 ArcadeDB 服务器。参见 使用 Docker 运行 ArcadeDB 在本地启动一台。

连接到已有数据库

EmbeddingStore<TextSegment> embeddingStore = ArcadeDBEmbeddingStore.builder()
.host("localhost")
.port(2480)
.databaseName("my_database")
.username("root")
.password("playwithdata")
.dimension(384) // Must match your embedding model's dimension
.build();

自动创建数据库

EmbeddingStore<TextSegment> embeddingStore = ArcadeDBEmbeddingStore.builder()
.host("localhost")
.port(2480)
.databaseName("my_database")
.username("root")
.password("playwithdata")
.dimension(384)
.createDatabase(true) // Create database if it doesn't exist
.build();

嵌入模式

嵌入模式在同一 JVM 内运行 ArcadeDB。无需服务器 — 只需提供本地文件系统上用于存储数据库的路径。如果数据库尚不存在,会自动创建。

使用完毕后请始终调用 close() 以释放资源。

ArcadeDBEmbeddingStore embeddingStore = ArcadeDBEmbeddingStore.embeddedBuilder()
.databasePath("/path/to/my-database")
.dimension(384) // Must match your embedding model's dimension
.build();

// ... use the store ...

embeddingStore.close();

使用 try-finally(或通过包装器使用 try-with-resources)确保始终调用 close()

ArcadeDBEmbeddingStore embeddingStore = ArcadeDBEmbeddingStore.embeddedBuilder()
.databasePath("/path/to/my-database")
.dimension(384)
.build();
try {
// ... use the store ...
} finally {
embeddingStore.close();
}

添加与搜索 Embedding

两种模式下的搜索 API 完全相同:

// Add a text segment with its embedding
TextSegment segment = TextSegment.from("Hello, world!", Metadata.from("source", "example"));
Embedding embedding = embeddingModel.embed(segment).content();
embeddingStore.add(embedding, segment);

// Search for similar embeddings
EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(5)
.minScore(0.7)
.build();

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

配置选项

远程模式

EmbeddingStore<TextSegment> embeddingStore = ArcadeDBEmbeddingStore.builder()
.host("localhost") // Required: ArcadeDB server hostname
.port(2480) // Default: 2480 (HTTP port)
.databaseName("my_database") // Required: database name
.username("root") // Required: username
.password("playwithdata") // Required: password
.typeName("EmbeddingDocument") // Default: "EmbeddingDocument" — vertex type name
.dimension(384) // Required: embedding vector dimension
.similarityFunction("COSINE") // Default: "COSINE" — similarity metric
.maxConnections(16) // Default: 16 — HNSW graph connections per node
.beamWidth(100) // Default: 100 — HNSW search beam width
.createDatabase(false) // Default: false — auto-create the database
.metadataPrefix("meta_") // Default: "meta_" — prefix for metadata properties
.build();

嵌入模式

ArcadeDBEmbeddingStore embeddingStore = ArcadeDBEmbeddingStore.embeddedBuilder()
.databasePath("/path/to/my-database") // Required: local filesystem path for the database
.typeName("EmbeddingDocument") // Default: "EmbeddingDocument" — vertex type name
.dimension(384) // Default: 384 — embedding vector dimension
.maxConnections(16) // Default: 16 — HNSW graph connections per node
.beamWidth(100) // Default: 100 — HNSW search beam width
.metadataPrefix("") // Default: "" (no prefix) — prefix for metadata properties
.build();

参数指南

共享参数(两种模式):

  • typeName:用于存储 embedding 文档的顶点类型。更改此值可在同一数据库中使用多个 embedding store
  • dimension:必须与 embedding 模型的输出维度完全匹配
  • maxConnections:控制 HNSW 索引中的图连通性。更高的值可提高召回率,但会增加内存和索引构建时间。推荐:16–128
  • beamWidth:控制 HNSW 索引构建和搜索的质量。更高的值以速度为代价获得更好的召回率。推荐:100–500
  • metadataPrefix:将元数据键存储为顶点属性时应用的前缀。如果元数据键与内置属性冲突,请更改此值

仅远程模式参数:

  • host:ArcadeDB 服务器的主机名或 IP 地址(必需)
  • port:ArcadeDB REST API 的 HTTP 端口(默认:2480)
  • databaseName:要连接或创建的数据库(必需)
  • username / password:ArcadeDB 凭证(必需)
  • similarityFunction
    • COSINE — 余弦相似度;最适合归一化向量(默认)
    • EUCLIDEAN — 欧氏距离
    • SQUARED_EUCLIDEAN — 平方欧氏距离;比 EUCLIDEAN 更快
  • createDatabase:设为 true 可在数据库不存在时自动创建

仅嵌入模式参数:

  • databasePath:嵌入式数据库存储目录的路径。如果不存在则自动创建
  • database:或者,直接提供已有的 com.arcadedb.database.Database 实例,而不是路径

元数据过滤

ArcadeDB 支持按元数据过滤搜索结果。过滤器在向量索引查找之后应用。

// Filter by a single metadata value
Filter filter = new IsEqualTo("source", "wikipedia");

EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(5)
.filter(filter)
.build();

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

支持的过滤类型

比较运算符:

  • IsEqualToIsNotEqualTo
  • IsGreaterThanIsGreaterThanOrEqualTo
  • IsLessThanIsLessThanOrEqualTo
  • IsInIsNotIn

逻辑运算符:

  • AndOrNot

删除操作

// Remove by list of IDs
embeddingStore.removeAll(List.of("id1", "id2"));

// Remove by metadata filter
embeddingStore.removeAll(new IsEqualTo("source", "old-source"));

// Remove all embeddings
embeddingStore.removeAll();

当前限制

  • 近似搜索:HNSW 索引是近似的。在包含大量近乎相同向量的超大结果集中,部分文档可能不会被返回
  • 内存中应用过滤:元数据过滤在向量搜索之后于内存中应用,而非在索引级别。store 会获取最多请求数量 5 倍的结果,以应对过滤导致的结果减少
  • 浮点精度:ArcadeDB 以 JSON double 返回向量,与原始存储值相比可能引入轻微的浮点精度差异。Double.MIN_VALUE(4.9E-324)会下溢为 0.0,无法精确存储
  • 无字符串内容过滤:不支持基于字符串的内容过滤(例如 ContainsString);仅支持上方列出的元数据过滤类型
  • 嵌入模式无法选择相似度函数:嵌入构建器不暴露 similarityFunction 选项;索引使用其默认度量

使用 Docker 运行 ArcadeDB

远程模式所必需。最快的入门方式:

docker run -d \
--name arcadedb \
-p 2480:2480 \
-e JAVA_OPTS="-Darcadedb.server.rootPassword=playwithdata" \
arcadedata/arcadedb:latest

然后连接你的 store:

EmbeddingStore<TextSegment> embeddingStore = ArcadeDBEmbeddingStore.builder()
.host("localhost")
.port(2480)
.databaseName("embeddings")
.username("root")
.password("playwithdata")
.dimension(384)
.createDatabase(true)
.build();

示例