索引与约束管理
索引与约束管理
相关源文件
本章引用的主要源码文件:
graphiti_core/driver/driver.pygraphiti_core/driver/falkordb_driver.pygraphiti_core/driver/neo4j_driver.pygraphiti_core/graph_queries.pygraphiti_core/helpers.pygraphiti_core/models/edges/edge_db_queries.pygraphiti_core/models/nodes/node_db_queries.py
本文档描述了 Graphiti 如何在不同图数据库提供商之间创建和管理数据库索引与约束。索引对查询性能至关重要,能够通过节点属性、标签、时间字段和全文搜索实现高效查找。
目的与范围
Graphiti 中的索引和约束服务于以下几个目的:
- 范围索引:支持对
uuid、created_at、valid_at、group_id和时间字段等属性的快速查找。 - 全文索引:为
name、summary和fact等字段提供 BM25 文本搜索能力。 - 向量索引:支持嵌入向量字段上的余弦相似度搜索(取决于数据库提供商)。
- 约束:在支持的数据库中强制实施唯一性和数据完整性。
每个数据库提供商(Neo4j、FalkorDB、Kuzu、Neptune)在创建和管理这些结构时具有不同的能力和语法。
来源: graphiti_core/driver/driver.py:128-129, graphiti_core/driver/driver.py:53-56
索引类型及其用途
Graphiti 使用两种主要的索引类别,这些类别从集中的 graph_queries.py 模块中获取。
| 索引类型 | 用途 | 应用对象 | 性能影响 |
|---|---|---|---|
| 范围索引 | 属性相等性和范围查询 | uuid、group_id、时间字段(created_at、valid_at、invalid_at、expired_at) | 对节点/边查找和时间过滤至关重要 |
| 全文索引 | 带分词的 BM25 文本搜索 | name(实体、社区)、summary、fact(RELATES_TO)、content(情节性) | 支持结合语义和关键词检索的混合搜索 |
按节点和边类型的索引覆盖范围
来源: graphiti_core/graph_queries.py:28-82, graphiti_core/graph_queries.py:85-140
索引创建工作流
所有驱动程序遵循一致的初始化模式,在驱动构造期间异步创建索引。
自然语言空间到代码实体空间:初始化
来源: graphiti_core/driver/neo4j_driver.py:92-101, graphiti_core/driver/falkordb_driver.py:160-168
序列图:异步索引构建
来源: graphiti_core/driver/neo4j_driver.py:92-101, graphiti_core/driver/falkordb_driver.py:160-168
各提供商实现细节
Neo4j 实现
Neo4j 驱动程序使用 CREATE INDEX IF NOT EXISTS 语句创建索引。它使用 semaphore_gather 来限制并发索引创建任务的数量。
_execute_index_query() 方法会捕获当多个并发的 CREATE INDEX IF NOT EXISTS 查询发生竞态时出现的 EquivalentSchemaRuleAlreadyExists 错误。由于所需索引已存在,因此可以安全地忽略此错误。
来源: graphiti_core/driver/neo4j_driver.py:206-216, graphiti_core/driver/neo4j_driver.py:191-204, graphiti_core/helpers.py:123-133
FalkorDB 实现
FalkorDB 使用 CALL db.idx.fulltext.createNodeIndex 进行全文搜索。它在初始化期间包含自动重复检测。
FalkorDB 的 execute_query() 方法会捕获包含 'already indexed' 的异常,并将其记录为信息性消息而非错误。
来源: graphiti_core/driver/falkordb_driver.py:299-304, graphiti_core/driver/falkordb_driver.py:228-236, graphiti_core/graph_queries.py:86-121
Kuzu 实现
Kuzu 使用 CALL CREATE_FTS_INDEX 创建全文索引。对于 Kuzu,范围索引目前不会通过驱动程序显式创建,因为它使用不同的索引策略。
来源: graphiti_core/graph_queries.py:123-129, graphiti_core/graph_queries.py:51-52
删除和重建索引
每个驱动程序都提供 delete_all_indexes() 方法用于清理操作。
Neo4j 索引删除
Neo4j 使用系统调用来删除所有索引: CALL db.indexes() YIELD name DROP INDEX name
来源: graphiti_core/driver/neo4j_driver.py:186-189
FalkorDB 索引删除
FalkorDB 需要检查索引元数据,并为 RANGE 和 FULLTEXT 类型生成特定于提供商的 DROP 命令。
来源: graphiti_core/driver/falkordb_driver.py:267-297
索引名称的环境变量
索引名称可以通过环境变量自定义:
| 环境变量 | 默认值 | 用途 |
|---|---|---|
ENTITY_INDEX_NAME | entities | 实体节点全文索引的名称 |
EPISODE_INDEX_NAME | episodes | 情节节点全文索引的名称 |
COMMUNITY_INDEX_NAME | communities | 社区节点全文索引的名称 |
ENTITY_EDGE_INDEX_NAME | entity_edges | 实体边全文索引的名称 |
来源: graphiti_core/driver/driver.py:53-56
全文查询构建与消毒
由于 FalkorDB 使用 RedisSearch 后端,因此需要特殊的全文查询语法。驱动程序提供了 build_fulltext_query() 方法,将用户查询转换为 RedisSearch 格式。
代码实体空间:全文搜索处理
| 处理点 | 说明 |
|---|---|
lucene_sanitize | helpers.py 会在查询进入 Lucene / RedisSearch 之前转义特殊字符,例如 + - && ! ( ) { } [ ] ^ " ~ * ? : \ /。 |
来源: graphiti_core/helpers.py:79-113, graphiti_core/driver/falkordb_driver.py:388-422
索引管理最佳实践
- 异步初始化:驱动程序在
__init__()期间使用asyncio.create_task调度索引创建,以避免阻塞主线程。 - 并发控制:通过
semaphore_gather使用SEMAPHORE_LIMIT(默认 20)来防止在批量索引创建期间压垮数据库。 - 竞态条件韧性:驱动程序会捕获并忽略"已存在"错误,以允许在多节点环境中安全地并发执行。
来源: graphiti_core/driver/neo4j_driver.py:92-101, graphiti_core/helpers.py:38, graphiti_core/helpers.py:123-133, graphiti_core/driver/neo4j_driver.py:196-204