数据库设计文档-0211会议版.md 61 KB

灵越智报 2.0 数据库设计文档

基于 2026-02-11 会议讨论设计(完整版)

使用模型: Claude Opus 4.5

最后更新: 2026-02-11

负责人: 何文松(后端接口+Mock数据)


目录

  1. 设计理念
  2. 业务流程与数据模型
  3. 核心概念
  4. 表结构总览
  5. 表详细设计
  6. 视图设计
  7. 索引设计
  8. 核心操作流程

1. 设计理念

1.1 图数据库思想在关系型数据库中的实现

来源: 2026-02-11 会议 - 吕强讲解

传统做法的问题:

  • 安源项目采用"一个报告类型一张表"的方式,导致有 140 张表还没建完
  • 每次有新报告类型,就需要新建表,表数量无限膨胀
  • 维护成本高,扩展性差

我们的解决方案

将图数据库的核心概念(节点 Node、关系 Relationship)平铺到关系型数据库中:

┌─────────────────────────────────────────────────────────────┐
│                    图数据库核心概念                          │
├─────────────────────────────────────────────────────────────┤
│  节点 (Node)     →  圆圈圈,代表实体                         │
│  关系 (Edge)     →  连线,描述节点之间的关联                  │
│  属性 (Property) →  节点或关系上的附加信息                    │
└─────────────────────────────────────────────────────────────┘
                              ↓
                        平铺到关系型数据库
                              ↓
┌─────────────────────────────────────────────────────────────┐
│                    关系型数据库实现                          │
├─────────────────────────────────────────────────────────────┤
│  nodes 表        →  存储所有节点(实体)                      │
│  edges 表        →  存储所有关系                             │
│  properties 表   →  存储节点/关系的属性                       │
│  视图 (View)     →  组合出业务接口                           │
└─────────────────────────────────────────────────────────────┘

1.2 设计优势

优势 说明
表结构稳定 不管有多少种报告类型,底层表结构不变
扩展性强 新增报告类型只需新增数据,不需要改表结构
AI 友好 结构化的关系描述,AI 容易理解和操作
查询灵活 通过视图组合出任意业务接口
实体复用 同一个实体(如手机号)不管出现在哪里,只存一份

1.3 读写分离

  • 写入: 通过基础表(nodes、edges、properties)
  • 读取: 通过视图(View)组合出业务接口
  • 好处: 一个视图对应一个前端接口,底层表结构不用改

2. 业务流程与数据模型

2.1 用户使用流程

┌─────────────────────────────────────────────────────────────────────────────┐
│                              用户使用流程                                    │
└─────────────────────────────────────────────────────────────────────────────┘

  ┌───────────────────────────────────────────────────────┐
  │ 1. 用户上传文件                                        │
  │    • 样本文档(人工整理好的报告)                        │
  │    • 附件(可选,可同时上传多个)                        │
  └──────────────────────────┬────────────────────────────┘
                             │
              ┌──────────────┴──────────────┐
              │                             │
              ▼                             ▼
  ┌──────────────────┐          ┌──────────────────┐
  │ 2. 解析样本文档   │          │ 3. 解析附件       │
  │    识别要素结构   │          │    提取实体(NER)  │
  └────────┬─────────┘          └────────┬─────────┘
           │                             │
           └──────────────┬──────────────┘
                          │
                          ▼
  ┌───────────────────────────────────────────────────────┐
  │ 4. 要素提取 + 规则提取(现阶段 Mock)                    │
  │    • 从样本中提取动态要素定义                           │
  │    • 从附件实体中推荐规则配置                           │
  └──────────────────────────┬────────────────────────────┘
                             │
                             ▼
  ┌───────────────────────────────────────────────────────┐
  │ 5. 页面确认                                            │
  │    • 确认要素定义                                       │
  │    • 确认/编辑规则配置                                  │
  │    • 【用户可从附件实体中添加规则】                       │
  │    • 确认后形成【模板】                                  │
  └──────────────────────────┬────────────────────────────┘
                             │
              ┌──────────────┴──────────────┐
              │                             │
              ▼                             ▼
  ┌──────────────────┐          ┌──────────────────┐
  │ 6. 规则执行       │          │ 7. 复制到新项目   │
  │    填充要素值     │          │    复用模板+规则  │
  └────────┬─────────┘          └────────┬─────────┘
           │                             │
           ▼                             ▼
  ┌──────────────────┐          ┌──────────────────┐
  │ 8. 生成文档       │          │  新报告实例       │
  │    导出下载       │          │ (重新上传附件)   │
  └──────────────────┘          └──────────────────┘

关键说明

  • 附件可与样本同时上传:用户在上传样本文档时,可以同时上传相关附件
  • 用户可从附件添加规则:附件解析后,用户可以在页面上选择附件中的实体,配置规则来填充动态要素

2.2 三层数据模型

基于业务流程,我们设计了 三层数据模型

┌─────────────────────────────────────────────────────────────────────────────┐
│                            三层数据模型                                      │
└─────────────────────────────────────────────────────────────────────────────┘

  ┌─────────────────────────────────────────────────────────────────────────┐
  │  第一层:原始文件 (SOURCE_FILE)                                          │
  │  ─────────────────────────────                                          │
  │  • 用户上传的样本文档                                                     │
  │  • 存储原文内容、文档结构                                                  │
  │  • 作为溯源和重新解析的依据                                                │
  │  • 生命周期:上传后基本不变                                                │
  └─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    │ PARSED_TO(解析生成)
                                    ▼
  ┌─────────────────────────────────────────────────────────────────────────┐
  │  第二层:模板 (TEMPLATE)                                                 │
  │  ─────────────────────────                                              │
  │  • 从样本中提取的"规则骨架"                                               │
  │  • 包含:要素定义、规则配置、占位符、DSL                                    │
  │  • 【可复用】- 一个模板可生成多个报告                                       │
  │  • 生命周期:确认后相对稳定                                                │
  └─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    │ INSTANCE_OF(实例化)
                                    ▼
  ┌─────────────────────────────────────────────────────────────────────────┐
  │  第三层:报告 (REPORT)                                                   │
  │  ─────────────────────────                                              │
  │  • 基于模板生成的项目实例                                                  │
  │  • 包含:要素值、附件、生成结果                                            │
  │  • 每个项目一份,可独立编辑                                                │
  │  • 生命周期:每个项目不同,可编辑                                           │
  └─────────────────────────────────────────────────────────────────────────┘

2.3 为什么要分三层?

问题 如果不分层 分层后
复用 复制时需要复制整个记录,清空要素值,保留规则,逻辑混乱 模板独立存在,报告只需引用模板
多项目 无法表达"一个模板对应多个报告"的关系 清晰的一对多关系
溯源 无法追溯原始样本 原始文件保留,可重新解析
维护 修改模板会影响所有报告 模板和报告独立,互不影响

2.4 各层存储内容

层次 node_type 存储内容 关联的子节点
原始文件 SOURCE_FILE 原文HTML、文档结构、上传信息 -
模板 TEMPLATE 模板名称、分类、描述 ELEMENT(要素定义)
报告 REPORT 报告标题、状态、项目关联 VALUE(要素值)、ATTACHMENT(附件)、RULE(规则)

2.5 实体提取与规则添加

用户可以从两个来源提取实体并添加规则:

  1. 样本文件(本文/原文):用户上传的样本文档本身
  2. 附件:与样本相关的参考文件

2.5.1 样本文件的实体提取

样本文件解析后,系统会提取其中的实体,用户可以直接从本文中选择实体绑定到动态要素:

原始文件 (SOURCE_FILE)
    │
    │ HAS_ENTITY(本文实体)
    ▼
实体 (ENTITY)  ←── 从样本文件中提取的实体
    │
    │ INPUT_FROM(被规则引用)
    ▼
规则 (RULE)  ←── 规则可以引用本文中的实体作为输入

2.5.2 附件的实体提取

附件可以在两个时机上传:

  1. 与样本文件同时上传:用户上传样本时可同时上传附件
  2. 后续单独上传:在报告编辑过程中随时上传

    报告 (REPORT)
    │
    │ HAS_ATTACHMENT
    ▼
    附件 (ATTACHMENT)  ←── 解析状态、解析文本
    │
    │ HAS_ENTITY(附件实体)
    ▼
    实体 (ENTITY)  ←── 从附件中提取的实体
    │
    │ INPUT_FROM(被规则引用)
    ▼
    规则 (RULE)  ←── 规则可以引用附件中的实体作为输入
    

2.5.3 实体解析流程

样本文件解析

  1. 用户上传样本文件
  2. 系统解析样本内容
  3. 提取样本中的实体(NER)
  4. 页面展示本文实体列表

附件解析

  1. 用户上传附件(可与样本同时上传,或后续单独上传)
  2. 系统解析附件内容
  3. 提取附件中的实体(NER)
  4. 页面展示附件实体列表

2.5.4 用户从实体添加规则

用户可以从本文附件中选择实体,绑定到动态要素:

  1. 用户在页面上查看实体列表(本文实体 / 附件实体)
  2. 选择某个实体(如"中国电建集团成都勘测设计研究院有限公司")
  3. 将该实体绑定到某个动态要素(如"评审对象")
  4. 系统自动创建规则,配置 INPUT_FROM 关系指向该实体
  5. 执行规则时,直接使用该实体的值填充要素

    用户操作示例:
    
    ┌─────────────────────────────────────────────────────────────────────────┐
    │  📄 本文:成都院复审报告样本.docx                                        │
    │  ────────────────────────────                                           │
    │  识别的实体:                                                            │
    │  ┌───────────────────────────────────────────────────────────────┐     │
    │  │ ☑ 中国电建集团成都勘测设计研究院有限公司  [ORG]                 │     │
    │  │   └─ [添加规则] → 绑定到要素:评审对象                         │     │
    │  │ ☐ 成都院  [ORG]                                               │     │
    │  │ ☑ BZ-0092-2024  [CODE]                                        │     │
    │  │   └─ [添加规则] → 绑定到要素:项目编号                         │     │
    │  └───────────────────────────────────────────────────────────────┘     │
    ├─────────────────────────────────────────────────────────────────────────┤
    │  📎 附件:复审通知.docx                                                  │
    │  ─────────────────────                                                  │
    │  识别的实体:                                                            │
    │  ┌───────────────────────────────────────────────────────────────┐     │
    │  │ ☐ 何彦锋  [PERSON]                                            │     │
    │  │ ☑ 2024年7月13日  [DATE]                                       │     │
    │  │   └─ [添加规则] → 绑定到要素:评审开始日期                     │     │
    │  │ ☑ 2024年10月17日  [DATE]                                      │     │
    │  │   └─ [添加规则] → 绑定到要素:评审结束日期                     │     │
    │  │ ☐ 93.33  [NUMBER]                                             │     │
    │  └───────────────────────────────────────────────────────────────┘     │
    └─────────────────────────────────────────────────────────────────────────┘
    

3. 核心概念

3.1 节点类型 (Node Types)

类型 所属层 说明 示例
SOURCE_FILE 第一层 用户上传的原始样本文件 成都院复审报告样本.docx
TEMPLATE 第二层 报告模板(规则骨架) 电力安全生产标准化复审报告模板
ELEMENT 第二层 动态要素定义(属于模板) 项目编号、评审对象
REPORT 第三层 报告实例(属于项目) 成都院复审报告
VALUE 第三层 要素值(属于报告) "BZ-0092-2024"
RULE 第三层 规则实例(属于报告) 项目编号提取规则
ATTACHMENT 第三层 附件(属于报告) 复审通知.docx
ENTITY 跨层 识别实体(属于样本文件或附件) 中国电建集团成都勘测设计研究院有限公司
USER 基础 用户 管理员
PROJECT 基础 项目 电力安全评审项目

注意ENTITY 是跨层的,可以从 SOURCE_FILE(本文)或 ATTACHMENT(附件)中提取,通过 HAS_ENTITY 关系关联。

3.2 关系类型 (Edge Types)

关系 说明 方向
PARSED_TO 原始文件解析生成模板 原始文件 → 模板
HAS_ELEMENT 模板包含要素定义 模板 → 要素定义
INSTANCE_OF 报告基于模板 报告 → 模板
HAS_VALUE 报告有要素值 报告 → 要素值
HAS_RULE 报告有规则 报告 → 规则
FOR_ELEMENT 规则/值对应的要素 规则/值 → 要素定义
HAS_ATTACHMENT 报告有附件 报告 → 附件
HAS_ENTITY 文件有实体(本文或附件) 原始文件/附件 → 实体
INPUT_FROM 规则输入来源 规则 → 原始文件/附件/实体/要素值
COPIED_FROM 复制来源 报告 → 源报告
BELONGS_TO 归属关系 报告 → 项目
CREATED_BY 创建者 节点 → 用户

3.3 动态要素类型

类型 占位符格式 说明
text {{namespace.field}} 短文本
paragraph {{namespace.field}} 长文本/段落
table {{+tableName}} 表格数据

3.4 实体类型

类型 说明 示例
ORG 组织机构 中国电建集团成都勘测设计研究院有限公司
PERSON 人名 何彦锋
DATE 日期 2024年7月13日
NUMBER 数值 93.33
LOCATION 地址 成都市温江区政和街8号

3.5 完整关系图

┌─────────────────────────────────────────────────────────────────────────────┐
│                           节点与关系完整图                                    │
└─────────────────────────────────────────────────────────────────────────────┘

                              ┌─────────┐
                              │  USER   │
                              └────┬────┘
                                   │ CREATED_BY
                                   ▼
┌─────────────┐  PARSED_TO   ┌─────────────┐  HAS_ELEMENT  ┌─────────────┐
│ SOURCE_FILE │─────────────▶│  TEMPLATE   │──────────────▶│   ELEMENT   │
│ (原始文件)   │              │   (模板)    │               │ (要素定义)   │
└──────┬──────┘              └──────┬──────┘               └──────┬──────┘
       │                            │                             │
       │ HAS_ENTITY                 │ INSTANCE_OF                 │ FOR_ELEMENT
       │ (本文实体)                  ▼                             │
       │                     ┌─────────────┐                      │
       │  ┌─────────────┐    │   REPORT    │   ┌─────────────┐    │
       │  │   PROJECT   │◀───│   (报告)    │───▶│   PROJECT   │    │
       │  │   (项目)    │    └──────┬──────┘    └─────────────┘    │
       │  └─────────────┘           │  BELONGS_TO                 │
       │                            │                             │
       │             ┌──────────────┼──────────────┐              │
       │             │              │              │              │
       │             ▼              ▼              ▼              │
       │      ┌───────────┐  ┌───────────┐  ┌───────────┐        │
       │      │   VALUE   │  │   RULE    │  │ATTACHMENT │        │
       │      │ (要素值)   │  │  (规则)   │  │  (附件)   │        │
       │      └─────┬─────┘  └─────┬─────┘  └─────┬─────┘        │
       │            │              │              │               │
       │            │              │              │ HAS_ENTITY    │
       │            │              │              │ (附件实体)     │
       │            │              │              ▼               │
       │            │              │        ┌───────────┐         │
       └────────────┼──────────────┼───────▶│  ENTITY   │         │
                    │              │        │  (实体)   │         │
                    │              │        └─────┬─────┘         │
                    │              │              │               │
                    │              │◀─────────────┘               │
                    │              │  INPUT_FROM                  │
                    │◀─────────────┘                              │
                    │  INPUT_FROM                                 │
                    │                                             │
                    └─────────────────────────────────────────────┘
                                   FOR_ELEMENT

说明:
- SOURCE_FILE(本文)和 ATTACHMENT(附件)都可以通过 HAS_ENTITY 关联到 ENTITY
- RULE 可以通过 INPUT_FROM 引用来自本文或附件的实体

4. 表结构总览

4.1 核心图结构表(与业务弱关联)

表名 说明
nodes 节点表 - 存储所有实体
edges 关系表 - 存储节点间关系
node_properties 节点属性表
edge_properties 关系属性表

4.2 业务辅助表

表名 说明
node_types 节点类型定义
edge_types 关系类型定义
property_definitions 属性定义

4.3 表关系图

┌─────────────────────────────────────────────────────────────────────┐
│                         核心图结构                                   │
│                                                                     │
│    ┌──────────────┐         ┌──────────────┐                       │
│    │  node_types  │         │  edge_types  │                       │
│    │  (节点类型)   │         │  (关系类型)   │                       │
│    └──────┬───────┘         └──────┬───────┘                       │
│           │                        │                               │
│           ▼                        ▼                               │
│    ┌──────────────┐         ┌──────────────┐                       │
│    │    nodes     │◄────────│    edges     │                       │
│    │   (节点)     │         │   (关系)     │                       │
│    └──────┬───────┘         └──────┬───────┘                       │
│           │                        │                               │
│           ▼                        ▼                               │
│    ┌──────────────┐         ┌──────────────┐                       │
│    │node_properties│        │edge_properties│                      │
│    │  (节点属性)   │         │  (关系属性)   │                       │
│    └──────────────┘         └──────────────┘                       │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
                                  │
                                  │ 通过视图组合
                                  ▼
┌─────────────────────────────────────────────────────────────────────┐
│                         业务视图层                                   │
│                                                                     │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐   │
│  │ v_templates │ │ v_reports   │ │ v_elements  │ │ v_rules     │   │
│  │  (模板视图)  │ │ (报告视图)  │ │ (要素视图)  │ │ (规则视图)  │   │
│  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘   │
│                                                                     │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐                   │
│  │v_attachments│ │ v_entities  │ │v_rule_config│                   │
│  │  (附件视图)  │ │ (实体视图)  │ │(规则配置视图)│                   │
│  └─────────────┘ └─────────────┘ └─────────────┘                   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

5. 表详细设计

5.1 node_types - 节点类型定义表

字段 类型 约束 说明
id SERIAL PRIMARY KEY 类型ID
type_code VARCHAR(50) NOT NULL, UNIQUE 类型编码
type_name VARCHAR(100) NOT NULL 类型名称
description TEXT 描述
icon VARCHAR(100) 图标
color VARCHAR(20) 颜色
created_at TIMESTAMP DEFAULT NOW() 创建时间

5.2 edge_types - 关系类型定义表

字段 类型 约束 说明
id SERIAL PRIMARY KEY 类型ID
type_code VARCHAR(50) NOT NULL, UNIQUE 类型编码
type_name VARCHAR(100) NOT NULL 类型名称
from_node_type VARCHAR(50) 起始节点类型
to_node_type VARCHAR(50) 目标节点类型
description TEXT 描述
created_at TIMESTAMP DEFAULT NOW() 创建时间

5.3 nodes - 节点表(核心)

字段 类型 约束 说明
id BIGSERIAL PRIMARY KEY 节点ID
node_type VARCHAR(50) NOT NULL 节点类型
node_key VARCHAR(200) 节点唯一标识(业务键)
name VARCHAR(500) NOT NULL 节点名称
status VARCHAR(50) DEFAULT 'active' 状态
created_by BIGINT 创建人ID
created_at TIMESTAMP DEFAULT NOW() 创建时间
updated_at TIMESTAMP DEFAULT NOW() 更新时间

唯一约束: (node_type, node_key) - 同类型下 node_key 唯一

5.4 edges - 关系表(核心)

字段 类型 约束 说明
id BIGSERIAL PRIMARY KEY 关系ID
edge_type VARCHAR(50) NOT NULL 关系类型
from_node_id BIGINT NOT NULL, FK 起始节点ID
to_node_id BIGINT NOT NULL, FK 目标节点ID
sort_order INT DEFAULT 0 排序
created_at TIMESTAMP DEFAULT NOW() 创建时间

唯一约束: (edge_type, from_node_id, to_node_id) - 防止重复关系

5.5 node_properties - 节点属性表

字段 类型 约束 说明
id BIGSERIAL PRIMARY KEY 属性ID
node_id BIGINT NOT NULL, FK 节点ID
prop_key VARCHAR(100) NOT NULL 属性键
prop_value TEXT 文本值
prop_json JSONB JSON值
prop_number DECIMAL(20,4) 数值
prop_date TIMESTAMP 日期值
created_at TIMESTAMP DEFAULT NOW() 创建时间
updated_at TIMESTAMP DEFAULT NOW() 更新时间

唯一约束: (node_id, prop_key) - 同节点下属性键唯一

5.6 edge_properties - 关系属性表

字段 类型 约束 说明
id BIGSERIAL PRIMARY KEY 属性ID
edge_id BIGINT NOT NULL, FK 关系ID
prop_key VARCHAR(100) NOT NULL 属性键
prop_value TEXT 文本值
prop_json JSONB JSON值
created_at TIMESTAMP DEFAULT NOW() 创建时间

唯一约束: (edge_id, prop_key)

5.7 property_definitions - 属性定义表

字段 类型 约束 说明
id SERIAL PRIMARY KEY 定义ID
owner_type VARCHAR(20) NOT NULL 所属类型: node/edge
target_type VARCHAR(50) NOT NULL 目标节点/关系类型
prop_key VARCHAR(100) NOT NULL 属性键
prop_name VARCHAR(200) NOT NULL 属性名称
data_type VARCHAR(50) NOT NULL 数据类型: text/json/number/date
required BOOLEAN DEFAULT false 是否必填
default_value TEXT 默认值
description TEXT 描述
created_at TIMESTAMP DEFAULT NOW() 创建时间

6. 视图设计

设计原则: 一个视图对应一个前端接口,底层表结构不用改

6.1 v_source_files - 原始文件视图

CREATE OR REPLACE VIEW v_source_files AS
SELECT 
    n.id,
    n.name AS file_name,
    n.node_key AS file_key,
    n.status,
    n.created_at,
    n.updated_at,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'original_name') AS original_name,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'file_path') AS file_path,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'file_type') AS file_type,
    (SELECT prop_number FROM node_properties WHERE node_id = n.id AND prop_key = 'file_size')::bigint AS file_size,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'content_html') AS content_html,
    (SELECT prop_json FROM node_properties WHERE node_id = n.id AND prop_key = 'content_json') AS content_json,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'parse_status') AS parse_status,
    (SELECT prop_date FROM node_properties WHERE node_id = n.id AND prop_key = 'parsed_at') AS parsed_at,
    -- 生成的模板
    (SELECT n2.id FROM edges e JOIN nodes n2 ON n2.id = e.to_node_id 
     WHERE e.from_node_id = n.id AND e.edge_type = 'PARSED_TO' LIMIT 1) AS template_id,
    -- 创建人
    n.created_by,
    (SELECT n2.name FROM nodes n2 WHERE n2.id = n.created_by) AS created_by_name
FROM nodes n
WHERE n.node_type = 'SOURCE_FILE';

6.2 v_templates - 模板视图

CREATE OR REPLACE VIEW v_templates AS
SELECT 
    n.id,
    n.name,
    n.node_key AS template_code,
    n.status,
    n.created_at,
    n.updated_at,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'category') AS category,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'description') AS description,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'content_html') AS content_html,
    (SELECT prop_json FROM node_properties WHERE node_id = n.id AND prop_key = 'content_json') AS content_json,
    (SELECT COUNT(*) FROM edges e WHERE e.from_node_id = n.id AND e.edge_type = 'HAS_ELEMENT') AS element_count,
    (SELECT n2.name FROM nodes n2 WHERE n2.id = n.created_by) AS created_by_name
FROM nodes n
WHERE n.node_type = 'TEMPLATE';

6.3 v_reports - 报告视图

CREATE OR REPLACE VIEW v_reports AS
SELECT 
    n.id,
    n.name AS title,
    n.node_key AS report_code,
    n.status,
    n.created_at,
    n.updated_at,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'report_type') AS report_type,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'content_html') AS content_html,
    -- 模板信息
    (SELECT n2.id FROM edges e JOIN nodes n2 ON n2.id = e.to_node_id 
     WHERE e.from_node_id = n.id AND e.edge_type = 'INSTANCE_OF' LIMIT 1) AS template_id,
    (SELECT n2.name FROM edges e JOIN nodes n2 ON n2.id = e.to_node_id 
     WHERE e.from_node_id = n.id AND e.edge_type = 'INSTANCE_OF' LIMIT 1) AS template_name,
    -- 项目信息
    (SELECT n2.id FROM edges e JOIN nodes n2 ON n2.id = e.to_node_id 
     WHERE e.from_node_id = n.id AND e.edge_type = 'BELONGS_TO' AND n2.node_type = 'PROJECT' LIMIT 1) AS project_id,
    (SELECT n2.name FROM edges e JOIN nodes n2 ON n2.id = e.to_node_id 
     WHERE e.from_node_id = n.id AND e.edge_type = 'BELONGS_TO' AND n2.node_type = 'PROJECT' LIMIT 1) AS project_name,
    -- 复制来源
    (SELECT n2.id FROM edges e JOIN nodes n2 ON n2.id = e.to_node_id 
     WHERE e.from_node_id = n.id AND e.edge_type = 'COPIED_FROM' LIMIT 1) AS source_report_id,
    -- 统计
    (SELECT COUNT(*) FROM edges e WHERE e.from_node_id = n.id AND e.edge_type = 'HAS_ATTACHMENT') AS attachment_count,
    -- 创建人
    n.created_by,
    (SELECT n2.name FROM nodes n2 WHERE n2.id = n.created_by) AS created_by_name
FROM nodes n
WHERE n.node_type = 'REPORT';

6.4 v_template_elements - 模板动态要素视图

CREATE OR REPLACE VIEW v_template_elements AS
SELECT 
    n.id,
    n.name AS element_name,
    n.node_key AS element_key,
    n.created_at,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'element_type') AS element_type,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'namespace') AS namespace,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'field_name') AS field_name,
    (SELECT prop_json FROM node_properties WHERE node_id = n.id AND prop_key = 'table_columns') AS table_columns,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'required')::boolean AS required,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'default_value') AS default_value,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'description') AS description,
    -- 所属模板
    (SELECT e.from_node_id FROM edges e WHERE e.to_node_id = n.id AND e.edge_type = 'HAS_ELEMENT' LIMIT 1) AS template_id,
    (SELECT e.sort_order FROM edges e WHERE e.to_node_id = n.id AND e.edge_type = 'HAS_ELEMENT' LIMIT 1) AS sort_order
FROM nodes n
WHERE n.node_type = 'ELEMENT';

6.5 v_report_element_values - 报告要素值视图

CREATE OR REPLACE VIEW v_report_element_values AS
SELECT 
    n.id AS value_id,
    n.node_key AS element_key,
    n.created_at,
    n.updated_at,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'value_text') AS value_text,
    (SELECT prop_json FROM node_properties WHERE node_id = n.id AND prop_key = 'value_json') AS value_json,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'is_filled')::boolean AS is_filled,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'fill_source') AS fill_source,
    -- 所属报告
    (SELECT e.from_node_id FROM edges e WHERE e.to_node_id = n.id AND e.edge_type = 'HAS_VALUE' LIMIT 1) AS report_id
FROM nodes n
WHERE n.node_type = 'VALUE';

6.6 v_attachments - 附件视图

CREATE OR REPLACE VIEW v_attachments AS
SELECT 
    n.id,
    n.name AS display_name,
    n.node_key AS file_key,
    n.created_at,
    n.updated_at,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'file_name') AS file_name,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'file_path') AS file_path,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'file_type') AS file_type,
    (SELECT prop_number FROM node_properties WHERE node_id = n.id AND prop_key = 'file_size')::bigint AS file_size,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'parse_status') AS parse_status,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'parsed_text') AS parsed_text,
    (SELECT prop_date FROM node_properties WHERE node_id = n.id AND prop_key = 'parsed_at') AS parsed_at,
    -- 实体数量
    (SELECT COUNT(*) FROM edges e WHERE e.from_node_id = n.id AND e.edge_type = 'HAS_ENTITY') AS entity_count,
    -- 所属报告
    (SELECT e.from_node_id FROM edges e WHERE e.to_node_id = n.id AND e.edge_type = 'HAS_ATTACHMENT' LIMIT 1) AS report_id,
    (SELECT e.sort_order FROM edges e WHERE e.to_node_id = n.id AND e.edge_type = 'HAS_ATTACHMENT' LIMIT 1) AS sort_order
FROM nodes n
WHERE n.node_type = 'ATTACHMENT';

6.7 v_entities - 实体视图

CREATE OR REPLACE VIEW v_entities AS
SELECT 
    n.id,
    n.name AS entity_text,
    n.node_key AS entity_key,
    n.created_at,
    n.updated_at,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'entity_type') AS entity_type,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'business_label') AS business_label,
    (SELECT prop_number FROM node_properties WHERE node_id = n.id AND prop_key = 'confidence') AS confidence,
    (SELECT prop_number FROM node_properties WHERE node_id = n.id AND prop_key = 'occurrence_count')::int AS occurrence_count,
    -- 所属附件
    (SELECT e.from_node_id FROM edges e WHERE e.to_node_id = n.id AND e.edge_type = 'HAS_ENTITY' LIMIT 1) AS attachment_id
FROM nodes n
WHERE n.node_type = 'ENTITY';

6.8 v_rules - 规则视图

CREATE OR REPLACE VIEW v_rules AS
SELECT 
    n.id,
    n.name AS rule_name,
    n.node_key AS element_key,
    n.status,
    n.created_at,
    n.updated_at,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'description') AS description,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'rule_type') AS rule_type,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'action_type') AS action_type,
    (SELECT prop_json FROM node_properties WHERE node_id = n.id AND prop_key = 'action_config') AS action_config,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'dsl_content') AS dsl_content,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'last_output_text') AS last_output_text,
    (SELECT prop_json FROM node_properties WHERE node_id = n.id AND prop_key = 'last_output_json') AS last_output_json,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'last_run_status') AS last_run_status,
    (SELECT prop_date FROM node_properties WHERE node_id = n.id AND prop_key = 'last_run_time') AS last_run_time,
    (SELECT prop_value FROM node_properties WHERE node_id = n.id AND prop_key = 'last_run_error') AS last_run_error,
    -- 所属报告
    (SELECT e.from_node_id FROM edges e WHERE e.to_node_id = n.id AND e.edge_type = 'HAS_RULE' LIMIT 1) AS report_id
FROM nodes n
WHERE n.node_type = 'RULE';

6.9 v_rule_inputs - 规则输入视图

CREATE OR REPLACE VIEW v_rule_inputs AS
SELECT 
    e.id AS input_id,
    e.from_node_id AS rule_id,
    e.to_node_id AS source_node_id,
    e.sort_order,
    (SELECT prop_value FROM edge_properties WHERE edge_id = e.id AND prop_key = 'input_key') AS input_key,
    (SELECT prop_value FROM edge_properties WHERE edge_id = e.id AND prop_key = 'input_name') AS input_name,
    (SELECT prop_value FROM edge_properties WHERE edge_id = e.id AND prop_key = 'input_type') AS input_type,
    (SELECT prop_value FROM edge_properties WHERE edge_id = e.id AND prop_key = 'fixed_value') AS fixed_value,
    -- 来源节点信息
    n.node_type AS source_type,
    n.name AS source_name
FROM edges e
JOIN nodes n ON n.id = e.to_node_id
WHERE e.edge_type = 'INPUT_FROM';

6.10 v_report_full - 报告完整视图(聚合)

CREATE OR REPLACE VIEW v_report_full AS
SELECT 
    r.*,
    -- 动态要素填充统计
    (SELECT COUNT(*) FROM v_report_element_values v WHERE v.report_id = r.id AND v.is_filled = true) AS filled_count,
    (SELECT COUNT(*) FROM v_template_elements te WHERE te.template_id = r.template_id) AS total_elements,
    -- 规则统计
    (SELECT COUNT(*) FROM v_rules ru WHERE ru.report_id = r.id) AS rule_count,
    (SELECT COUNT(*) FROM v_rules ru WHERE ru.report_id = r.id AND ru.last_run_status = 'success') AS success_rule_count
FROM v_reports r;

7. 索引设计

7.1 nodes 表索引

-- 类型索引(最常用)
CREATE INDEX idx_nodes_type ON nodes(node_type);

-- 类型+状态组合索引
CREATE INDEX idx_nodes_type_status ON nodes(node_type, status);

-- 业务键索引
CREATE INDEX idx_nodes_key ON nodes(node_key);

-- 类型+业务键唯一索引
CREATE UNIQUE INDEX idx_nodes_type_key ON nodes(node_type, node_key) WHERE node_key IS NOT NULL;

-- 创建人索引
CREATE INDEX idx_nodes_created_by ON nodes(created_by);

-- 创建时间索引
CREATE INDEX idx_nodes_created_at ON nodes(created_at DESC);

7.2 edges 表索引

-- 关系类型索引
CREATE INDEX idx_edges_type ON edges(edge_type);

-- 起始节点索引
CREATE INDEX idx_edges_from ON edges(from_node_id);

-- 目标节点索引
CREATE INDEX idx_edges_to ON edges(to_node_id);

-- 类型+起始节点组合索引(查询某节点的特定关系)
CREATE INDEX idx_edges_type_from ON edges(edge_type, from_node_id);

-- 类型+目标节点组合索引(反向查询)
CREATE INDEX idx_edges_type_to ON edges(edge_type, to_node_id);

-- 防止重复关系
CREATE UNIQUE INDEX idx_edges_unique ON edges(edge_type, from_node_id, to_node_id);

7.3 node_properties 表索引

-- 节点ID索引
CREATE INDEX idx_node_props_node ON node_properties(node_id);

-- 节点+属性键组合索引
CREATE UNIQUE INDEX idx_node_props_unique ON node_properties(node_id, prop_key);

-- 属性键索引(用于跨节点查询特定属性)
CREATE INDEX idx_node_props_key ON node_properties(prop_key);

7.4 edge_properties 表索引

-- 关系ID索引
CREATE INDEX idx_edge_props_edge ON edge_properties(edge_id);

-- 关系+属性键组合索引
CREATE UNIQUE INDEX idx_edge_props_unique ON edge_properties(edge_id, prop_key);

8. 核心操作流程

8.1 上传文件并生成模板(样本+附件可同时上传)

操作:用户上传样本文件(可同时上传附件) → 系统解析 → 生成模板

步骤:
1. 创建 SOURCE_FILE 节点(样本文件)
2. 解析样本文件,提取要素定义
3. 创建 TEMPLATE 节点
4. 创建 PARSED_TO 关系(SOURCE_FILE → TEMPLATE)
5. 为每个要素定义创建 ELEMENT 节点
6. 创建 HAS_ELEMENT 关系(TEMPLATE → ELEMENT)
7. 【可选】同时上传附件:
   a. 创建 ATTACHMENT 节点
   b. 创建 HAS_ATTACHMENT 关系(关联到后续创建的 REPORT)
   c. 解析附件,提取实体
   d. 创建 ENTITY 节点
   e. 创建 HAS_ENTITY 关系(ATTACHMENT → ENTITY)

说明:附件可以在上传样本时同时上传,系统会先解析附件并提取实体,这样用户在确认要素和规则时,可以直接从附件实体中选择绑定。

SQL 示例

-- 1. 创建原始文件节点
INSERT INTO nodes (node_type, node_key, name, created_by)
VALUES ('SOURCE_FILE', 'SF-001', '成都院复审报告样本.docx', 1)
RETURNING id;  -- 假设返回 id = 100

-- 2. 添加原始文件属性
INSERT INTO node_properties (node_id, prop_key, prop_value) VALUES
(100, 'original_name', '成都院复审报告样本.docx'),
(100, 'file_path', '/uploads/2026/02/SF-001.docx'),
(100, 'file_type', 'docx'),
(100, 'parse_status', 'completed');

-- 3. 创建模板节点
INSERT INTO nodes (node_type, node_key, name, created_by)
VALUES ('TEMPLATE', 'TPL-001', '电力安全生产标准化复审报告模板', 1)
RETURNING id;  -- 假设返回 id = 101

-- 4. 创建 PARSED_TO 关系
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('PARSED_TO', 100, 101);

-- 5. 创建要素定义节点
INSERT INTO nodes (node_type, node_key, name)
VALUES ('ELEMENT', 'basicInfo.projectCode', '项目编号')
RETURNING id;  -- 假设返回 id = 102

-- 6. 添加要素定义属性
INSERT INTO node_properties (node_id, prop_key, prop_value) VALUES
(102, 'element_type', 'text'),
(102, 'namespace', 'basicInfo'),
(102, 'field_name', 'projectCode'),
(102, 'required', 'true');

-- 7. 创建 HAS_ELEMENT 关系
INSERT INTO edges (edge_type, from_node_id, to_node_id, sort_order)
VALUES ('HAS_ELEMENT', 101, 102, 1);

8.2 基于模板创建报告

操作:用户选择模板 → 创建报告 → 关联项目

步骤:
1. 创建 REPORT 节点
2. 创建 INSTANCE_OF 关系(REPORT → TEMPLATE)
3. 创建 BELONGS_TO 关系(REPORT → PROJECT)
4. 为每个要素定义创建空的 VALUE 节点
5. 创建 HAS_VALUE 关系(REPORT → VALUE)
6. 创建 FOR_ELEMENT 关系(VALUE → ELEMENT)

SQL 示例

-- 1. 创建报告节点
INSERT INTO nodes (node_type, node_key, name, status, created_by)
VALUES ('REPORT', 'RPT-001', '成都院2024年复审报告', 'draft', 1)
RETURNING id;  -- 假设返回 id = 200

-- 2. 创建 INSTANCE_OF 关系(报告 → 模板)
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('INSTANCE_OF', 200, 101);

-- 3. 创建 BELONGS_TO 关系(报告 → 项目)
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('BELONGS_TO', 200, 1);  -- 假设项目ID为1

-- 4. 为每个要素创建空的 VALUE 节点
INSERT INTO nodes (node_type, node_key, name)
VALUES ('VALUE', 'RPT-001:basicInfo.projectCode', '项目编号值')
RETURNING id;  -- 假设返回 id = 201

-- 5. 添加 VALUE 属性(初始为空)
INSERT INTO node_properties (node_id, prop_key, prop_value) VALUES
(201, 'is_filled', 'false');

-- 6. 创建 HAS_VALUE 关系(报告 → 值)
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('HAS_VALUE', 200, 201);

-- 7. 创建 FOR_ELEMENT 关系(值 → 要素定义)
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('FOR_ELEMENT', 201, 102);

8.3 复制报告到新项目

操作:用户选择已有报告 → 复制到新项目

复制内容:
✓ 模板引用(INSTANCE_OF)
✓ 规则配置(RULE 节点及其 INPUT_FROM 关系结构)
✗ 要素值(VALUE 节点清空,需重新填充)
✗ 附件(ATTACHMENT 节点不复制,需重新上传)
✗ 实体(ENTITY 节点不复制)

步骤:
1. 创建新的 REPORT 节点
2. 复制 INSTANCE_OF 关系(指向同一模板)
3. 创建 BELONGS_TO 关系(指向新项目)
4. 创建 COPIED_FROM 关系(新报告 → 源报告)
5. 为每个要素创建空的 VALUE 节点
6. 复制 RULE 节点(复制规则配置,但清空执行结果)
7. 复制 INPUT_FROM 关系结构(但引用需要重新绑定)

SQL 示例

-- 1. 创建新报告节点
INSERT INTO nodes (node_type, node_key, name, status, created_by)
VALUES ('REPORT', 'RPT-002', '华东院2024年复审报告', 'draft', 1)
RETURNING id;  -- 假设返回 id = 300

-- 2. 获取源报告的模板ID
SELECT to_node_id FROM edges 
WHERE from_node_id = 200 AND edge_type = 'INSTANCE_OF';  -- 返回 101

-- 3. 创建 INSTANCE_OF 关系(指向同一模板)
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('INSTANCE_OF', 300, 101);

-- 4. 创建 BELONGS_TO 关系(指向新项目)
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('BELONGS_TO', 300, 2);  -- 假设新项目ID为2

-- 5. 创建 COPIED_FROM 关系(溯源)
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('COPIED_FROM', 300, 200);

-- 6. 复制规则节点(清空执行结果)
INSERT INTO nodes (node_type, node_key, name, status)
SELECT 'RULE', 
       REPLACE(node_key, 'RPT-001', 'RPT-002'),
       name,
       'active'
FROM nodes 
WHERE node_type = 'RULE' 
  AND id IN (SELECT to_node_id FROM edges WHERE from_node_id = 200 AND edge_type = 'HAS_RULE');

-- 7. 复制规则属性(保留配置,清空结果)
INSERT INTO node_properties (node_id, prop_key, prop_value, prop_json)
SELECT new_rule.id, np.prop_key, 
       CASE WHEN np.prop_key IN ('last_output_text', 'last_run_status', 'last_run_error') THEN NULL 
            ELSE np.prop_value END,
       CASE WHEN np.prop_key = 'last_output_json' THEN NULL ELSE np.prop_json END
FROM node_properties np
JOIN nodes old_rule ON old_rule.id = np.node_id AND old_rule.node_type = 'RULE'
JOIN nodes new_rule ON new_rule.node_key = REPLACE(old_rule.node_key, 'RPT-001', 'RPT-002')
WHERE old_rule.id IN (SELECT to_node_id FROM edges WHERE from_node_id = 200 AND edge_type = 'HAS_RULE');

8.4 上传附件并解析实体

操作:用户上传附件 → 系统解析 → 提取实体

步骤:
1. 创建 ATTACHMENT 节点
2. 创建 HAS_ATTACHMENT 关系(REPORT → ATTACHMENT)
3. 解析附件内容
4. 提取实体(NER)
5. 为每个实体创建 ENTITY 节点(全局去重)
6. 创建 HAS_ENTITY 关系(ATTACHMENT → ENTITY)

SQL 示例

-- 1. 创建附件节点
INSERT INTO nodes (node_type, node_key, name)
VALUES ('ATTACHMENT', 'ATT-001', '01-复审通知')
RETURNING id;  -- 假设返回 id = 400

-- 2. 添加附件属性
INSERT INTO node_properties (node_id, prop_key, prop_value) VALUES
(400, 'file_name', '复审通知.docx'),
(400, 'file_path', '/uploads/2026/02/复审通知.docx'),
(400, 'file_type', 'docx'),
(400, 'parse_status', 'completed');

-- 3. 创建 HAS_ATTACHMENT 关系
INSERT INTO edges (edge_type, from_node_id, to_node_id, sort_order)
VALUES ('HAS_ATTACHMENT', 200, 400, 1);

-- 4. 创建实体节点(全局去重,使用 ON CONFLICT)
INSERT INTO nodes (node_type, node_key, name)
VALUES ('ENTITY', 'ORG:中国电建集团成都勘测设计研究院有限公司', '中国电建集团成都勘测设计研究院有限公司')
ON CONFLICT (node_type, node_key) DO UPDATE SET updated_at = NOW()
RETURNING id;  -- 假设返回 id = 500

-- 5. 添加实体属性
INSERT INTO node_properties (node_id, prop_key, prop_value) VALUES
(500, 'entity_type', 'ORG'),
(500, 'business_label', '评审对象')
ON CONFLICT (node_id, prop_key) DO UPDATE SET prop_value = EXCLUDED.prop_value;

-- 6. 创建 HAS_ENTITY 关系
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('HAS_ENTITY', 400, 500)
ON CONFLICT DO NOTHING;

8.5 用户从附件实体添加规则

操作:用户在页面上选择附件中的实体 → 绑定到动态要素 → 自动创建规则

场景:用户查看附件解析出的实体列表,选择某个实体直接绑定到要素

步骤:
1. 用户选择实体(如"中国电建集团成都勘测设计研究院有限公司")
2. 用户选择要绑定的动态要素(如"评审对象")
3. 系统自动创建 RULE 节点(规则类型为 direct_entity)
4. 创建 HAS_RULE 关系(REPORT → RULE)
5. 创建 FOR_ELEMENT 关系(RULE → ELEMENT)
6. 创建 INPUT_FROM 关系(RULE → ENTITY)
7. 执行规则,直接使用实体值填充要素

SQL 示例

-- 假设:
-- 报告ID = 200
-- 要素定义ID = 102(评审对象)
-- 实体ID = 500(中国电建集团成都勘测设计研究院有限公司)

-- 1. 创建规则节点(直接引用实体类型)
INSERT INTO nodes (node_type, node_key, name, status)
VALUES ('RULE', 'RPT-001:project.reviewObject', '评审对象-直接引用实体', 'active')
RETURNING id;  -- 假设返回 id = 610

-- 2. 添加规则属性(规则类型为 direct_entity,表示直接使用实体值)
INSERT INTO node_properties (node_id, prop_key, prop_value) VALUES
(610, 'rule_type', 'direct_entity'),
(610, 'action_type', 'use_entity_value'),
(610, 'description', '直接使用附件实体值填充要素');

-- 3. 创建 HAS_RULE 关系(报告 → 规则)
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('HAS_RULE', 200, 610);

-- 4. 创建 FOR_ELEMENT 关系(规则 → 要素定义)
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('FOR_ELEMENT', 610, 102);

-- 5. 创建 INPUT_FROM 关系(规则 → 实体)
INSERT INTO edges (edge_type, from_node_id, to_node_id, sort_order)
VALUES ('INPUT_FROM', 610, 500, 1);

-- 6. 添加输入属性
INSERT INTO edge_properties (edge_id, prop_key, prop_value)
SELECT id, 'input_key', 'entity' FROM edges 
WHERE edge_type = 'INPUT_FROM' AND from_node_id = 610 AND to_node_id = 500;

INSERT INTO edge_properties (edge_id, prop_key, prop_value)
SELECT id, 'input_type', 'entity_ref' FROM edges 
WHERE edge_type = 'INPUT_FROM' AND from_node_id = 610 AND to_node_id = 500;

-- 7. 执行规则:直接使用实体的 name 作为要素值
-- 获取实体值
SELECT name FROM nodes WHERE id = 500;  -- 返回 '中国电建集团成都勘测设计研究院有限公司'

-- 8. 更新要素值节点
UPDATE node_properties 
SET prop_value = '中国电建集团成都勘测设计研究院有限公司', updated_at = NOW()
WHERE node_id = (SELECT id FROM nodes WHERE node_key = 'RPT-001:project.reviewObject' AND node_type = 'VALUE')
  AND prop_key = 'value_text';

8.6 配置复杂规则并执行

操作:用户配置复杂规则(正则提取/LLM生成等) → 绑定输入 → 执行规则 → 填充要素值

步骤:
1. 创建 RULE 节点
2. 创建 HAS_RULE 关系(REPORT → RULE)
3. 创建 FOR_ELEMENT 关系(RULE → ELEMENT)
4. 配置规则输入(创建 INPUT_FROM 关系,可引用附件/实体/其他要素值)
5. 执行规则,获取结果
6. 更新 VALUE 节点的值

SQL 示例

-- 1. 创建规则节点
INSERT INTO nodes (node_type, node_key, name, status)
VALUES ('RULE', 'RPT-001:basicInfo.projectCode', '项目编号提取规则', 'active')
RETURNING id;  -- 假设返回 id = 600

-- 2. 添加规则属性
INSERT INTO node_properties (node_id, prop_key, prop_value, prop_json) VALUES
(600, 'rule_type', 'extraction', NULL),
(600, 'action_type', 'extract_pattern', NULL),
(600, 'action_config', NULL, '{"pattern": "项目编号[::]\\s*(\\S+)", "group": 1}'),
(600, 'dsl_content', 'EXTRACT pattern="项目编号[::]\\s*(\\S+)" FROM input1', NULL);

-- 3. 创建 HAS_RULE 关系
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('HAS_RULE', 200, 600);

-- 4. 创建 FOR_ELEMENT 关系
INSERT INTO edges (edge_type, from_node_id, to_node_id)
VALUES ('FOR_ELEMENT', 600, 102);

-- 5. 配置规则输入(引用附件)
INSERT INTO edges (edge_type, from_node_id, to_node_id, sort_order)
VALUES ('INPUT_FROM', 600, 400, 1);

-- 6. 添加输入属性
INSERT INTO edge_properties (edge_id, prop_key, prop_value)
SELECT id, 'input_key', 'input1' FROM edges 
WHERE edge_type = 'INPUT_FROM' AND from_node_id = 600 AND to_node_id = 400;

-- 7. 执行规则后,更新 VALUE 节点
UPDATE node_properties 
SET prop_value = 'BZ-0092-2024', updated_at = NOW()
WHERE node_id = 201 AND prop_key = 'value_text';

UPDATE node_properties 
SET prop_value = 'true', updated_at = NOW()
WHERE node_id = 201 AND prop_key = 'is_filled';

INSERT INTO node_properties (node_id, prop_key, prop_value)
VALUES (201, 'fill_source', 'rule')
ON CONFLICT (node_id, prop_key) DO UPDATE SET prop_value = EXCLUDED.prop_value;

-- 8. 更新规则执行状态
UPDATE node_properties 
SET prop_value = 'BZ-0092-2024', updated_at = NOW()
WHERE node_id = 600 AND prop_key = 'last_output_text';

INSERT INTO node_properties (node_id, prop_key, prop_value)
VALUES (600, 'last_run_status', 'success')
ON CONFLICT (node_id, prop_key) DO UPDATE SET prop_value = EXCLUDED.prop_value;

附录

A. 与传统设计对比

维度 传统设计(安源) 图结构设计(灵越)
表数量 140+ 张,持续增长 4 张核心表,固定不变
新增报告类型 需要新建表 只需新增数据
实体复用 每张表独立存储 全局唯一,引用ID
AI 操作 需要针对每张表编码 统一的图结构,易于理解
查询灵活性 需要修改表结构 通过视图组合

B. 变更记录

日期 版本 变更内容 作者
2026-02-11 1.0 初始版本,基于会议讨论的图数据库思想设计 Claude Opus 4.5
2026-02-11 1.1 增加三层数据模型(原始文件→模板→报告)、业务流程、核心操作流程 Claude Opus 4.5
2026-02-11 1.2 补充附件与样本同时上传、用户从附件添加规则的流程 Claude Opus 4.5
2026-02-11 1.3 补充本文(样本文件)也可以提取实体并添加规则 Claude Opus 4.5