diff --git a/图数据库结构设计 b/图数据库结构设计 new file mode 100644 index 0000000..9afebf1 --- /dev/null +++ b/图数据库结构设计 @@ -0,0 +1,254 @@ +以下是完整的 Neo4j 图数据库结构设计,针对 OpenClaw 对话记忆场景优化,边上带完整时间戳和元数据: + 1. 节点(Node)设计 + 实体节点(Entity) + (:Entity { + name: string, // 实体名称(唯一标识) + type: string, // 类型:concept | technology | person | project | decision + created_at: datetime, // 首次出现时间 + updated_at: datetime, // 最后更新时间 + mention_count: int // 被提及次数(用于权重) + }) + + 会话节点(Session) + (:Session { + session_id: string, // 会话唯一ID(如 20260408-a7f3) + created_at: datetime, // 会话开始时间 + summary: string, // 会话摘要(可选) + status: string // active | archived | compacted + }) + + 2. 关系(Edge)设计 + 核心关系(RELATES) + 所有对话关系统一使用 RELATES 类型,属性承载时间戳和元数据: + (source:Entity)-[:RELATES { + // 基础关系属性 + type: string, // 关系类型:uses | implements | depends_on | rejects | prefers | leads_to | contradicts + + // 时间戳(核心) + created_at: datetime, // 关系创建时间(精确到秒) + updated_at: datetime, // 最后更新时间(纠错时更新) + + // 来源追踪 + session_id: string, // 所属会话ID + turn_id: int, // 轮次序号(该会话中的第几轮) + + // 角色标记 + role: string, // "user" | "assistant" | "system" + + // 内容快照 + context_snippet: string, // 原始文本片段(前100字符) + + // 状态管理 + status: string, // active | deleted | archived | superseded(被取代) + confidence: float, // 置信度(0.0-1.0,提取算法给出) + + // 时序检索辅助 + date_bucket: string // 日期分区(2026-04-08),用于快速范围查询 + }]->(target:Entity) + + 时序链(NEXT)- 可选 + 用于严格保持对话顺序: + (:Entity)-[:NEXT { + session_id: string, + created_at: datetime + }]->(:Entity) + + 3. 索引与约束 + // 实体唯一性约束 + CREATE CONSTRAINT entity_name_constraint IF NOT EXISTS + FOR (e:Entity) REQUIRE e.name IS UNIQUE; + + // 会话唯一性约束 + CREATE CONSTRAINT session_id_constraint IF NOT EXISTS + FOR (s:Session) REQUIRE s.session_id IS UNIQUE; + + // 关系查询索引(按时间戳检索关键) + CREATE INDEX rel_created_at IF NOT EXISTS + FOR ()-[r:RELATES]-() ON r.created_at; + + CREATE INDEX rel_session_id IF NOT EXISTS + FOR ()-[r:RELATES]-() ON r.session_id; + + CREATE INDEX rel_type IF NOT EXISTS + FOR ()-[r:RELATES]-() ON r.type; + + CREATE INDEX rel_status IF NOT EXISTS + FOR ()-[r:RELATES]-() ON r.status; + + CREATE INDEX rel_date_bucket IF NOT EXISTS + FOR ()-[r:RELATES]-() ON r.date_bucket; + + // 复合索引(会话+时间) + CREATE INDEX rel_session_time IF NOT EXISTS + FOR ()-[r:RELATES]-() ON (r.session_id, r.created_at); + + 4. 数据模型示例 + 插入场景 + 用户说:"我想用 Neo4j 改造 OpenClaw 的记忆系统,替换掉原来的 SQLite 方案。" + 生成的图结构: + // 节点 + (:Entity {name: "OpenClaw", type: "project", created_at: now()}) + (:Entity {name: "Neo4j", type: "technology", created_at: now()}) + (:Entity {name: "SQLite", type: "technology", created_at: now()}) + (:Entity {name: "记忆系统改造", type: "decision", created_at: now()}) + + // 关系(带时间戳) + (OpenClaw)-[:RELATES { + type: "uses", + created_at: datetime("2026-04-08T19:45:00"), + session_id: "20260408-a7f3", + turn_id: 1, + role: "user", + context_snippet: "我想用 Neo4j 改造 OpenClaw...", + status: "active", + confidence: 0.95, + date_bucket: "2026-04-08" + }]->(Neo4j) + + (OpenClaw)-[:RELATES { + type: "replaces", + created_at: datetime("2026-04-08T19:45:00"), + session_id: "20260408-a7f3", + turn_id: 1, + role: "user", + context_snippet: "替换掉原来的 SQLite 方案", + status: "active", + confidence: 0.92, + date_bucket: "2026-04-08" + }]->(SQLite) + + (记忆系统改造)-[:RELATES { + type: "involves", + created_at: datetime("2026-04-08T19:45:00"), + session_id: "20260408-a7f3", + turn_id: 1, + role: "user", + status: "active", + date_bucket: "2026-04-08" + }]->(OpenClaw) + + 5. 关键查询模式 + A. 时序检索(最新记忆优先) + // 查询实体相关的最新关系(按时间戳倒序) + MATCH (e:Entity {name: $entity_name})-[r:RELATES]-(target:Entity) + WHERE r.status = 'active' + RETURN e, r, target + ORDER BY r.created_at DESC + LIMIT 20 + + B. 会话范围查询(上下文隔离) + // 仅查询特定会话内的关系 + MATCH (s:Entity)-[r:RELATES]->(t:Entity) + WHERE r.session_id = $session_id + RETURN s.name, r.type, t.name, r.created_at + ORDER BY r.turn_id + + C. 时间范围查询(最近N天) + // 利用 date_bucket 或时间戳范围 + MATCH (s:Entity)-[r:RELATES]->(t:Entity) + WHERE r.date_bucket >= date().isoDate - duration('P7D') // 最近7天 + OR r.created_at >= datetime() - duration('P7D') + RETURN s, r, t + ORDER BY r.created_at DESC + + D. 多跳路径查询(关联推理) + // 查询两个实体间的路径(带时间约束) + MATCH path = (start:Entity {name: $start})-[:RELATES*1..3]->(end:Entity {name: $end}) + WHERE ALL(r IN relationships(path) WHERE r.status = 'active') + RETURN path, + [r IN relationships(path) | r.created_at] as path_timestamps, + length(path) as hops + ORDER BY path_timestamps[-1] DESC // 按最后关系时间排序 + LIMIT 5 + + E. 纠错更新(软删除) + // 用户更正时,不物理删除,而是标记为 superseded 并创建新关系 + MATCH (s:Entity {name: $source})-[r:RELATES {type: $old_relation}]->(t:Entity {name: $target}) + WHERE r.status = 'active' + SET r.status = 'superseded', + r.updated_at = datetime(), + r.superseded_by = $new_relation_id // 指向新关系的ID + + // 创建新关系(带新的时间戳) + CREATE (s)-[:RELATES { + type: $new_relation, + created_at: datetime(), + session_id: $session_id, + turn_id: $turn_id, + role: $role, + status: 'active', + supersedes: $old_relation_id + }]->(t) + + 6. 存储过程(APOC)优化 + 批量插入(高性能) + // 使用 APOC 批量合并,避免逐条插入开销 + CALL apoc.periodic.iterate( + "UNWIND $triples as t RETURN t", + " + MERGE (s:Entity {name: t.source}) + ON CREATE SET s.created_at = datetime(), s.type = coalesce(t.source_type, 'unknown') + ON MATCH SET s.updated_at = datetime(), s.mention_count = coalesce(s.mention_count, 0) + 1 + + MERGE (e:Entity {name: t.target}) + ON CREATE SET e.created_at = datetime(), e.type = coalesce(t.target_type, 'unknown') + ON MATCH SET e.updated_at = datetime(), e.mention_count = coalesce(e.mention_count, 0) + 1 + + CREATE (s)-[r:RELATES { + type: t.relation, + created_at: datetime(), + session_id: t.session_id, + turn_id: t.turn_id, + role: t.role, + status: 'active', + date_bucket: date().isoDate, + confidence: coalesce(t.confidence, 1.0) + }]->(e) + ", + {batchSize: 100, params: {triples: $triples}} + ) + + 时序压缩(归档旧关系) + // 将N天前的关系标记为 archived,但保留节点 + MATCH ()-[r:RELATES]->() + WHERE r.created_at < datetime() - duration('P30D') // 30天前 + AND r.status = 'active' + SET r.status = 'archived', + r.archived_at = datetime() + RETURN count(r) as archived_count + + 7. 与 Bridge API 的映射 + API 端点 Cypher 操作 时间戳处理 + POST /insert MERGE 节点 + CREATE 关系 datetime() 自动生成 + POST /search MATCH 带时间戳排序 返回 r.created_at 等字段 + POST /delete SET r.status = 'deleted' 软删除,保留 updated_at + 8. 数据保留策略 + // 节点保留:永久(实体名词长期有效) + // 关系保留策略: + // - active: 最近30天(高频查询) + // - archived: 30-90天(低频查询,需指定时间范围) + // - deleted: 逻辑删除,保留90天后物理清理(APOC 定时任务) + + // 物理清理(谨慎操作) + MATCH ()-[r:RELATES]->() + WHERE r.status = 'deleted' + AND r.updated_at < datetime() - duration('P90D') + DELETE r + WITH count(*) as deleted_relations + MATCH (e:Entity) + WHERE NOT (e)-[:RELATES]-() // 无关系的孤立节点 + DELETE e + RETURN deleted_relations, count(e) as deleted_orphans + + 这个设计支持时间旅行查询(查看任意时刻的图状态)、会话隔离(只看当前对话历史)和渐进式遗忘(旧关系归档但不删除),符合 OpenClaw 的增量记忆需求。 + + }] + ) + }] + }] + }] + }] + }] + }] + }) + }) \ No newline at end of file