Appearance
muotai-spg 数据库设计与技术文档
文档说明
项目名称: muotai-spg 知识图谱持久层 版本: v1.0 创建日期: 2025-12-15 数据库: MySQL 8.0+, Neo4j 5.x ORM框架: MyBatis-Plus 3.5.x
目录
一、数据库架构概览
1.1 架构设计理念
muotai-spg采用双数据库架构:
- MySQL: 存储Schema元数据、项目配置、版本管理
- Neo4j: 存储实际的知识图谱数据(节点和关系)
┌─────────────────────────────────────────────────────┐
│ Application Layer │
│ (Spring Boot + MyBatis-Plus) │
└─────────────────────────────────────────────────────┘
│
┌────────────────┴────────────────┐
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ MySQL │ │ Neo4j │
│ (Schema Meta) │ │ (Graph Data) │
├──────────────────┤ ├──────────────────┤
│ • Project Info │ │ • Nodes │
│ • Entity Types │ │ • Relationships │
│ • Properties │ │ • Properties │
│ • Constraints │ │ • Indexes │
│ • Versions │ │ │
└──────────────────┘ └──────────────────┘1.2 数据库职责划分
| 数据类型 | MySQL | Neo4j | 说明 |
|---|---|---|---|
| Schema定义 | ✅ | ❌ | 实体类型、属性定义、约束 |
| 元数据管理 | ✅ | ❌ | 项目、业务域、用户权限 |
| 版本管理 | ✅ | ❌ | Schema版本、发布历史 |
| 图谱实例数据 | ❌ | ✅ | 实际的实体节点和关系边 |
| 图查询 | ❌ | ✅ | 多跳查询、路径查询 |
| 全文搜索 | ✅ | ✅ | MySQL: 元数据搜索, Neo4j: 内容搜索 |
1.3 表分类
A. 项目与租户管理(2张表)
kg_biz_domain- 业务域表kg_project_info- 项目信息表
B. 本体Schema管理(4张表)
kg_ontology_entity- 实体类型表kg_ontology_entity_parent- 继承关系表kg_ontology_entity_property_range- 属性范围表(SPO三元组)kg_ontology_property_constraint- 属性约束表
C. 项目关联与版本(2张表)
kg_project_entity- 项目-实体关联表kg_ontology_release- Schema发布版本表
二、详细表设计
2.1 kg_biz_domain (业务域表)
表名: kg_biz_domain用途: 多租户管理,一个业务域可包含多个项目,实现数据隔离
字段说明
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT(20) | PK, AUTO_INCREMENT | 主键ID |
| name | VARCHAR(100) | NOT NULL | 业务域名称 |
| description | VARCHAR(1024) | NULL | 业务域描述 |
| global_config | TEXT | NULL | 全局配置(JSON格式) |
| status | CHAR(1) | NOT NULL, DEFAULT '1' | 状态: 1-有效, 9-删除 |
| gmt_create | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| gmt_modified | TIMESTAMP | NOT NULL, AUTO UPDATE | 修改时间 |
索引设计
sql
PRIMARY KEY (id)
KEY idx_status (status)字段详解
global_config (JSON格式示例):
json
{
"max_projects": 100,
"storage_quota": "100GB",
"features": ["multi_version", "graph_query"],
"notification": {
"email": "admin@example.com",
"webhook": "https://api.example.com/webhook"
}
}业务规则
- 默认业务域: 系统初始化时自动创建
default业务域 - 软删除: 删除业务域时设置
status='9',不物理删除 - 级联影响: 删除业务域时,需先处理其下所有项目
示例数据
sql
INSERT INTO kg_biz_domain (name, description, status)
VALUES ('default', '默认业务域', '1');
INSERT INTO kg_biz_domain (name, description, global_config, status)
VALUES (
'medical',
'医疗行业业务域',
'{"max_projects": 50, "industry": "healthcare"}',
'1'
);2.2 kg_project_info (项目信息表)
表名: kg_project_info用途: 知识图谱项目管理,每个项目对应一个独立的知识图谱
字段说明
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT(20) | PK, AUTO_INCREMENT | 主键ID |
| name | VARCHAR(255) | NOT NULL, UNIQUE | 项目名称(唯一) |
| description | VARCHAR(1024) | NULL | 项目描述 |
| namespace | VARCHAR(64) | NOT NULL, DEFAULT '' | 命名空间 |
| biz_domain_id | BIGINT(20) | NULL, FK | 业务域ID |
| config | TEXT | NULL | 项目配置(JSON格式) |
| visibility | VARCHAR(64) | DEFAULT 'PRIVATE' | 可见性: PRIVATE/PUBLIC |
| status | CHAR(1) | NOT NULL, DEFAULT '1' | 状态: 1-有效, 9-删除 |
| gmt_create | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| gmt_modified | TIMESTAMP | NOT NULL, AUTO UPDATE | 修改时间 |
| creator | VARCHAR(64) | NULL | 创建人 |
| modifier | VARCHAR(64) | NULL | 修改人 |
索引设计
sql
PRIMARY KEY (id)
UNIQUE KEY uk_name (name)
KEY idx_biz_domain_id (biz_domain_id)
KEY idx_namespace (namespace)字段详解
namespace命名规范:
- 格式: 小写字母、数字、下划线
- 示例:
medical,finance,e_commerce - 用途: Schema唯一命名空间,避免类型冲突
config (JSON格式示例):
json
{
"graph_db": {
"type": "neo4j",
"database": "medical_kg",
"connection": {
"uri": "bolt://localhost:7687",
"username": "neo4j"
}
},
"storage": {
"max_entities": 1000000,
"max_relations": 5000000
},
"features": {
"version_control": true,
"full_text_search": true,
"reasoning": false
},
"permissions": {
"public_read": false,
"allow_export": true
}
}visibility可选值:
PRIVATE: 私有项目,仅项目成员可见PUBLIC: 公开项目,所有人可读
业务规则
- 唯一性: 项目名称全局唯一
- 命名空间: 同一命名空间下的类型名称必须唯一
- 软删除: 删除项目时设置
status='9' - 权限控制: 通过
visibility和权限表控制访问
示例数据
sql
INSERT INTO kg_project_info (name, description, namespace, biz_domain_id, visibility, creator)
VALUES (
'Medical Knowledge Graph',
'医疗领域知识图谱',
'medical',
1,
'PRIVATE',
'admin'
);2.3 kg_ontology_entity (本体实体类型表)
表名: kg_ontology_entity用途: 存储本体中所有实体类型定义,支持多版本管理
字段说明
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT(20) | PK, AUTO_INCREMENT | 主键ID(版本相关) |
| original_id | BIGINT(20) | NOT NULL, DEFAULT 0 | 原始ID(版本无关) |
| name | VARCHAR(255) | NOT NULL, UNIQUE | 实体类型名称(英文) |
| name_zh | VARCHAR(255) | NOT NULL | 实体类型中文名称 |
| entity_category | VARCHAR(20) | NOT NULL | 实体类别 |
| layer | VARCHAR(20) | NULL | 层级: CORE/EXTENSION |
| description | VARCHAR(1024) | NULL | 英文描述 |
| description_zh | VARCHAR(1024) | NULL | 中文描述 |
| with_index | VARCHAR(20) | NOT NULL, DEFAULT 'TRUE' | 是否建索引: TRUE/FALSE |
| scope | VARCHAR(20) | NULL | 作用域: PUBLIC/PRIVATE |
| version | INT(11) | NOT NULL, DEFAULT 0 | 版本号 |
| version_status | VARCHAR(50) | NOT NULL, DEFAULT 'ONLINE' | 版本状态 |
| transformer_id | BIGINT(20) | NULL | 转换器ID |
| operator_config | TEXT | NULL | 操作配置(JSON) |
| config | MEDIUMTEXT | NULL | 扩展配置(JSON) |
| unique_name | VARCHAR(255) | NULL | 唯一名称(namespace.name) |
| status | CHAR(1) | NOT NULL, DEFAULT '1' | 状态: 1-有效, 9-删除 |
| gmt_create | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| gmt_modified | TIMESTAMP | NOT NULL, AUTO UPDATE | 修改时间 |
索引设计
sql
PRIMARY KEY (id)
UNIQUE KEY uk_name (name)
UNIQUE KEY uk_original_id_version (original_id, version)
KEY idx_version_status (version_status)
KEY idx_original_id_version_status (original_id, version_status)
KEY idx_category_status (entity_category, status)字段详解
entity_category (实体类别):
| 值 | 说明 | 示例 |
|---|---|---|
| BASIC | 基本类型 | Text, Integer, Float, Date |
| STANDARD | 标准类型 | Email, Phone, URL |
| ADVANCED | 高级类型(自定义) | Person, Company, Product |
| CONCEPT_TYPE | 概念类型 | HighValueCustomer, VIPMember |
| EVENT_TYPE | 事件类型 | Transaction, Login, Purchase |
version_status (版本状态):
| 值 | 说明 | 使用场景 |
|---|---|---|
| ONLINE | 线上版本 | 生产环境正在使用 |
| LATEST | 最新版本 | 开发中的最新版本 |
| EFFICIENT | 生效版本 | 已生效但未上线 |
| HISTORY | 历史版本 | 已下线的旧版本 |
| DISCARDED | 废弃版本 | 已废弃不再使用 |
版本管理机制:
Entity "Person" 的版本演进:
┌────────┬─────────────┬─────────┬────────────────┐
│ id │ original_id │ version │ version_status │
├────────┼─────────────┼─────────┼────────────────┤
│ 1001 │ 1000 │ 1 │ HISTORY │ ← 历史版本
│ 1002 │ 1000 │ 2 │ HISTORY │ ← 历史版本
│ 1003 │ 1000 │ 3 │ ONLINE │ ← 当前线上版本
│ 1004 │ 1000 │ 4 │ LATEST │ ← 最新开发版本
└────────┴─────────────┴─────────┴────────────────┘config (JSON格式示例):
json
{
"icon": "person",
"color": "#3498db",
"display": {
"label_property": "name",
"title_property": "title",
"description_property": "description"
},
"validation": {
"required_properties": ["name", "id"],
"unique_properties": ["id", "email"]
},
"storage": {
"index_type": "BTREE",
"partition": "by_year"
},
"business": {
"audit_log": true,
"data_masking": ["email", "phone"]
}
}业务规则
- 版本唯一性: (original_id, version) 组合唯一
- 名称唯一性: name 在当前版本中唯一
- 版本递增: 新版本号 = MAX(version) + 1
- 状态转换:
LATEST → EFFICIENT → ONLINE ↓ HISTORY/DISCARDED
示例数据
sql
-- 基本类型
INSERT INTO kg_ontology_entity
(original_id, name, name_zh, entity_category, layer, version_status, status)
VALUES
(1, 'Thing', '事物', 'BASIC', 'CORE', 'ONLINE', '1'),
(2, 'Text', '文本', 'BASIC', 'CORE', 'ONLINE', '1'),
(3, 'Integer', '整数', 'BASIC', 'CORE', 'ONLINE', '1');
-- 自定义类型
INSERT INTO kg_ontology_entity
(original_id, name, name_zh, entity_category, layer, description, unique_name, version_status, status)
VALUES
(1000, 'Person', '人物', 'ADVANCED', 'EXTENSION', '人物实体类型', 'medical.Person', 'ONLINE', '1'),
(1001, 'Disease', '疾病', 'ADVANCED', 'EXTENSION', '疾病实体类型', 'medical.Disease', 'ONLINE', '1');2.4 kg_ontology_entity_parent (实体继承关系表)
表名: kg_ontology_entity_parent用途: 存储实体类型之间的继承关系,支持单继承和多继承
字段说明
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT(20) | PK, AUTO_INCREMENT | 主键ID |
| entity_id | BIGINT(20) | NOT NULL, FK | 子类型ID |
| parent_id | BIGINT(20) | NOT NULL, FK | 父类型ID(根节点为-1) |
| path | VARCHAR(4096) | NULL | 继承路径 |
| deep_inherit | CHAR(1) | DEFAULT 'N' | 是否深度继承: Y/N |
| status | CHAR(1) | NOT NULL, DEFAULT '1' | 状态: 1-有效, 9-删除 |
| gmt_create | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| gmt_modified | TIMESTAMP | NOT NULL, AUTO UPDATE | 修改时间 |
索引设计
sql
PRIMARY KEY (id)
UNIQUE KEY uk_entity_parent (entity_id, parent_id)
KEY idx_parent_id (parent_id)
KEY idx_entity_id (entity_id)字段详解
继承路径 (path): 存储从根节点到当前节点的完整路径,格式: /parent1_id/parent2_id/entity_id
示例:
Thing (id=1)
└── Person (id=1000)
└── Doctor (id=1010)
Doctor的path: /1/1000/1010深度继承 (deep_inherit):
Y: 深度继承,继承所有祖先的属性N: 浅继承,只继承直接父类的属性
继承关系图示
Thing (根类型)
│
┌───────────┼───────────┐
│ │ │
Person Product Location
│ │ │
┌─────┼─────┐ │ ┌────┼────┐
│ │ │ │ │ │ │
Doctor Student Customer City Province Country业务规则
- 根节点:
parent_id = -1表示根节点 - 无循环: 不允许循环继承(A→B→A)
- 路径唯一: 同一子类型到同一父类型只能有一条路径
- 属性继承: 子类型自动继承父类型的所有属性
示例数据
sql
-- Person 继承自 Thing
INSERT INTO kg_ontology_entity_parent (entity_id, parent_id, path, deep_inherit)
VALUES (1000, 1, '/1/1000', 'Y');
-- Doctor 继承自 Person
INSERT INTO kg_ontology_entity_parent (entity_id, parent_id, path, deep_inherit)
VALUES (1010, 1000, '/1/1000/1010', 'Y');
-- 多继承示例: Student 同时继承 Person 和 Learner
INSERT INTO kg_ontology_entity_parent (entity_id, parent_id, path, deep_inherit)
VALUES
(1020, 1000, '/1/1000/1020', 'Y'), -- 继承Person
(1020, 2000, '/2000/1020', 'Y'); -- 继承Learner2.5 kg_ontology_entity_property_range (属性范围表 - SPO三元组)
表名: kg_ontology_entity_property_range用途: 存储实体类型的属性定义,采用RDF三元组模型(Subject-Predicate-Object)
字段说明
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT(20) | PK, AUTO_INCREMENT | 主键ID |
| original_id | BIGINT(20) | NOT NULL, DEFAULT 0 | 原始ID(版本无关) |
| domain_id | BIGINT(20) | NOT NULL, FK | 主体实体ID(Subject) |
| property_name | VARCHAR(255) | NOT NULL | 属性名称(Predicate) |
| property_name_zh | VARCHAR(255) | NOT NULL | 属性中文名称 |
| range_id | BIGINT(20) | NOT NULL, FK | 目标实体ID(Object) |
| property_category | VARCHAR(20) | NOT NULL | 属性类别 |
| constraint_id | BIGINT(20) | NULL, FK | 约束ID |
| property_desc | VARCHAR(1024) | NULL | 属性描述 |
| property_desc_zh | VARCHAR(1024) | NULL | 属性中文描述 |
| direction | VARCHAR(10) | NULL | 方向: BOTH(双向) |
| index_type | VARCHAR(1024) | NULL | 索引类型 |
| version | INT(11) | NOT NULL, DEFAULT 0 | 版本号 |
| version_status | VARCHAR(50) | DEFAULT 'ONLINE' | 版本状态 |
| unique_name | VARCHAR(255) | NULL | 唯一名称 |
| config | TEXT | NULL | 扩展配置(JSON) |
| status | CHAR(1) | NOT NULL, DEFAULT '1' | 状态: 1-有效, 9-删除 |
| gmt_create | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| gmt_modified | TIMESTAMP | NOT NULL, AUTO UPDATE | 修改时间 |
索引设计
sql
PRIMARY KEY (id)
UNIQUE KEY uk_spo_version (domain_id, property_name, range_id, version)
KEY idx_original_id (original_id)
KEY idx_version_status (version_status)
KEY idx_property_name (property_name)
KEY idx_domain_id (domain_id)字段详解
SPO三元组模型:
Subject(主体) --Predicate(谓词)--> Object(客体)
↓ ↓ ↓
domain_id property_name range_id
示例:
Person --name--> Text
Person --age--> Integer
Person --worksFor--> Company
Drug --treats--> Diseaseproperty_category (属性类别):
| 值 | 说明 | 示例 |
|---|---|---|
| PROPERTY | 数据属性 | name: Text, age: Integer |
| RELATION | 对象属性(关系) | worksFor: Company, friendOf: Person |
direction (方向):
NULL或FORWARD: 单向关系 A → BBOTH: 双向关系 A ↔ B
index_type (索引类型):
json
{
"type": "BTREE", // BTREE, HASH, FULLTEXT
"unique": false,
"fields": ["name"],
"analyzer": "standard" // 全文索引分词器
}三元组示例
Person (实体类型)
├── name: Text [数据属性]
├── age: Integer [数据属性]
├── email: Text [数据属性]
├── worksFor: Company [对象属性/关系]
└── friendOf: Person [对象属性/关系,双向]
SPO三元组表示:
┌───────────┬───────────────┬──────────┬──────────────────┐
│ domain_id │ property_name │ range_id │ property_category│
├───────────┼───────────────┼──────────┼──────────────────┤
│ Person │ name │ Text │ PROPERTY │
│ Person │ age │ Integer │ PROPERTY │
│ Person │ worksFor │ Company │ RELATION │
│ Person │ friendOf │ Person │ RELATION │
└───────────┴───────────────┴──────────┴──────────────────┘业务规则
- 唯一性: (domain_id, property_name, range_id, version) 组合唯一
- 类型检查: range_id 必须指向有效的实体类型
- 版本同步: 属性版本号应与所属实体版本号同步
- 约束关联: constraint_id 指向属性约束表
示例数据
sql
-- Person的属性定义
INSERT INTO kg_ontology_entity_property_range
(original_id, domain_id, property_name, property_name_zh, range_id, property_category, version_status)
VALUES
-- 数据属性
(5001, 1000, 'name', '姓名', 2, 'PROPERTY', 'ONLINE'), -- Person.name: Text
(5002, 1000, 'age', '年龄', 3, 'PROPERTY', 'ONLINE'), -- Person.age: Integer
(5003, 1000, 'email', '邮箱', 2, 'PROPERTY', 'ONLINE'), -- Person.email: Text
-- 对象属性(关系)
(5004, 1000, 'worksFor', '工作于', 1001, 'RELATION', 'ONLINE'), -- Person.worksFor: Company
(5005, 1000, 'friendOf', '朋友', 1000, 'RELATION', 'ONLINE'); -- Person.friendOf: Person
-- Disease的属性定义
INSERT INTO kg_ontology_entity_property_range
(original_id, domain_id, property_name, property_name_zh, range_id, property_category, version_status)
VALUES
(6001, 1001, 'name', '疾病名称', 2, 'PROPERTY', 'ONLINE'),
(6002, 1001, 'icd_code', 'ICD编码', 2, 'PROPERTY', 'ONLINE'),
(6003, 1001, 'symptom', '症状', 2, 'PROPERTY', 'ONLINE');2.6 kg_ontology_property_constraint (属性约束表)
表名: kg_ontology_property_constraint用途: 定义属性的约束规则,如必填、唯一、取值范围等
字段说明
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT(20) | PK, AUTO_INCREMENT | 主键ID |
| name | VARCHAR(255) | NOT NULL | 约束名称 |
| name_zh | VARCHAR(255) | NULL | 约束中文名称 |
| is_required | CHAR(1) | NOT NULL, DEFAULT 'N' | 是否必填: Y/N |
| is_unique | CHAR(1) | DEFAULT 'N' | 是否唯一: Y/N |
| max_value | VARCHAR(255) | NULL | 最大值(数值类型) |
| min_value | VARCHAR(255) | NULL | 最小值(数值类型) |
| value_pattern | VARCHAR(1024) | NULL | 正则表达式(文本类型) |
| is_enum | CHAR(1) | DEFAULT 'N' | 是否枚举: Y/N |
| enum_value | TEXT | NULL | 枚举值(JSON数组) |
| is_multi_value | CHAR(1) | DEFAULT 'N' | 是否多值: Y/N |
| description | VARCHAR(1024) | NULL | 描述 |
| description_zh | VARCHAR(1024) | NULL | 中文描述 |
| config | TEXT | NULL | 扩展配置(JSON) |
| status | CHAR(1) | NOT NULL, DEFAULT '1' | 状态: 1-有效, 9-删除 |
| gmt_create | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| gmt_modified | TIMESTAMP | NOT NULL, AUTO UPDATE | 修改时间 |
索引设计
sql
PRIMARY KEY (id)
KEY idx_name (name)约束类型说明
1. 必填约束 (is_required)
json
{
"is_required": "Y",
"error_message": "该字段不能为空"
}2. 唯一性约束 (is_unique)
json
{
"is_unique": "Y",
"scope": "global", // global(全局唯一) 或 project(项目内唯一)
"error_message": "该值已存在"
}3. 数值范围约束
json
{
"min_value": "0",
"max_value": "120",
"inclusive": true, // 包含边界值
"error_message": "年龄必须在0-120之间"
}4. 正则表达式约束 (value_pattern)
javascript
// Email格式
"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
// 手机号格式(中国)
"^1[3-9]\\d{9}$"
// ICD编码格式
"^[A-Z]\\d{2}(\\.\\d{1,2})?$"5. 枚举值约束 (enum_value)
json
{
"is_enum": "Y",
"enum_value": [
{"value": "MALE", "label": "男性"},
{"value": "FEMALE", "label": "女性"},
{"value": "OTHER", "label": "其他"}
]
}6. 多值约束 (is_multi_value)
json
{
"is_multi_value": "Y",
"min_count": 1,
"max_count": 10,
"separator": ";"
}示例数据
sql
-- 必填+唯一约束
INSERT INTO kg_ontology_property_constraint
(name, name_zh, is_required, is_unique, description)
VALUES
('person_id_constraint', '人物ID约束', 'Y', 'Y', '人物ID必填且唯一');
-- 数值范围约束
INSERT INTO kg_ontology_property_constraint
(name, name_zh, is_required, min_value, max_value, description)
VALUES
('age_constraint', '年龄约束', 'N', '0', '120', '年龄范围0-120岁');
-- 正则表达式约束
INSERT INTO kg_ontology_property_constraint
(name, name_zh, value_pattern, description)
VALUES
('email_constraint', '邮箱约束',
'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$',
'Email格式验证');
-- 枚举约束
INSERT INTO kg_ontology_property_constraint
(name, name_zh, is_enum, enum_value, description)
VALUES
('gender_constraint', '性别约束', 'Y',
'[{"value":"MALE","label":"男"},{"value":"FEMALE","label":"女"}]',
'性别枚举值');
-- 多值约束
INSERT INTO kg_ontology_property_constraint
(name, name_zh, is_multi_value, config, description)
VALUES
('tags_constraint', '标签约束', 'Y',
'{"min_count":1,"max_count":10,"separator":","}',
'标签多值约束');2.7 kg_project_entity (项目-实体关联表)
表名: kg_project_entity用途: 关联项目和实体类型,支持实体类型在多个项目间共享或引用
字段说明
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT(20) | PK, AUTO_INCREMENT | 主键ID |
| project_id | BIGINT(20) | NOT NULL, FK | 项目ID |
| entity_id | BIGINT(20) | NOT NULL, FK | 实体ID |
| version | INT(11) | NOT NULL, DEFAULT 0 | 版本号 |
| version_status | VARCHAR(50) | NOT NULL, DEFAULT 'ONLINE' | 版本状态 |
| referenced | CHAR(1) | NOT NULL, DEFAULT 'N' | 是否引用: Y/N |
| status | CHAR(1) | NOT NULL, DEFAULT '1' | 状态: 1-有效, 9-删除 |
| gmt_create | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| gmt_modified | TIMESTAMP | NOT NULL, AUTO UPDATE | 修改时间 |
索引设计
sql
PRIMARY KEY (id)
UNIQUE KEY uk_project_entity_version (project_id, entity_id, version)
KEY idx_version_status (version_status)
KEY idx_project_id_version_status (project_id, version_status)字段详解
referenced (引用标志):
N: 自有实体,在本项目中定义Y: 引用实体,引用自其他项目或公共库
使用场景
场景1: 项目独立定义实体
医疗项目A:
└── Disease (自有实体, referenced='N')
└── 在项目A中定义和维护场景2: 项目引用公共实体
公共类型库:
└── Person (公共实体)
电商项目:
└── Person (引用, referenced='Y')
└── 引用自公共类型库
金融项目:
└── Person (引用, referenced='Y')
└── 引用自公共类型库场景3: 项目间共享实体
项目A:
└── Company (自有实体, referenced='N')
项目B:
└── Company (引用, referenced='Y')
└── 引用自项目A业务规则
- 唯一性: (project_id, entity_id, version) 组合唯一
- 引用规则: referenced='Y' 时,不允许修改实体定义
- 版本同步: 引用实体时,可选择引用的版本
- 删除保护: 被引用的实体不能删除
示例数据
sql
-- 项目1 自有实体
INSERT INTO kg_project_entity (project_id, entity_id, version, version_status, referenced)
VALUES
(1, 1000, 1, 'ONLINE', 'N'), -- Person
(1, 1001, 1, 'ONLINE', 'N'); -- Disease
-- 项目2 引用项目1的实体
INSERT INTO kg_project_entity (project_id, entity_id, version, version_status, referenced)
VALUES
(2, 1000, 1, 'ONLINE', 'Y'); -- 引用Person2.8 kg_ontology_release (Schema发布版本表)
表名: kg_ontology_release用途: 管理Schema的版本发布,保存每个版本的完整快照
字段说明
| 字段名 | 类型 | 约束 | 说明 |
|---|---|---|---|
| id | BIGINT(20) | PK, AUTO_INCREMENT | 主键ID |
| project_id | BIGINT(20) | NOT NULL, FK | 项目ID |
| version | INT(11) | NOT NULL | 版本号 |
| schema_view | MEDIUMTEXT | NULL | Schema快照(JSON格式) |
| status | VARCHAR(50) | NOT NULL, DEFAULT 'DRAFT' | 状态 |
| description | VARCHAR(1024) | NULL | 版本描述 |
| user_id | VARCHAR(64) | NULL | 发布用户ID |
| publish_time | TIMESTAMP | NULL | 发布时间 |
| gmt_create | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | 创建时间 |
| gmt_modified | TIMESTAMP | NOT NULL, AUTO UPDATE | 修改时间 |
索引设计
sql
PRIMARY KEY (id)
UNIQUE KEY uk_project_version (project_id, version)
KEY idx_status (status)
KEY idx_project_id_status (project_id, status)字段详解
status (版本状态):
| 值 | 说明 | 操作 |
|---|---|---|
| DRAFT | 草稿 | 可编辑、删除 |
| ONLINE | 线上 | 只读,生产环境使用 |
| HISTORY | 历史 | 只读,已下线 |
| DISCARDED | 废弃 | 已废弃不再使用 |
状态转换流程:
DRAFT → ONLINE → HISTORY
↓
DISCARDEDschema_view (Schema快照) JSON格式:
json
{
"version": 1,
"namespace": "medical",
"timestamp": "2025-12-15T10:00:00Z",
"entities": [
{
"id": 1000,
"name": "Person",
"nameZh": "人物",
"category": "ADVANCED",
"properties": [
{
"name": "name",
"nameZh": "姓名",
"type": "Text",
"required": true,
"unique": false
},
{
"name": "age",
"nameZh": "年龄",
"type": "Integer",
"min": 0,
"max": 120
}
],
"parents": ["Thing"],
"indexes": ["name"]
},
{
"id": 1001,
"name": "Disease",
"nameZh": "疾病",
"category": "ADVANCED",
"properties": [
{
"name": "name",
"nameZh": "疾病名称",
"type": "Text",
"required": true
},
{
"name": "icd_code",
"nameZh": "ICD编码",
"type": "Text",
"pattern": "^[A-Z]\\d{2}(\\.\\d{1,2})?$"
}
]
}
],
"relations": [
{
"name": "treats",
"nameZh": "治疗",
"subjectType": "Drug",
"objectType": "Disease",
"properties": [
{
"name": "effectiveness",
"nameZh": "有效性",
"type": "Float",
"min": 0.0,
"max": 1.0
}
]
}
],
"constraints": [
{
"id": 1,
"name": "person_id_unique",
"type": "unique",
"entity": "Person",
"property": "id"
}
]
}版本管理流程
1. 创建草稿版本
sql
INSERT INTO kg_ontology_release (project_id, version, status, description, user_id)
VALUES (1, 1, 'DRAFT', '初始版本', 'admin');2. 发布版本
sql
-- 更新当前版本为线上
UPDATE kg_ontology_release
SET status = 'ONLINE',
publish_time = NOW()
WHERE project_id = 1 AND version = 1;
-- 将旧版本设为历史
UPDATE kg_ontology_release
SET status = 'HISTORY'
WHERE project_id = 1 AND version < 1 AND status = 'ONLINE';3. 回滚版本
sql
-- 下线当前版本
UPDATE kg_ontology_release
SET status = 'HISTORY'
WHERE project_id = 1 AND version = 2 AND status = 'ONLINE';
-- 重新激活旧版本
UPDATE kg_ontology_release
SET status = 'ONLINE',
publish_time = NOW()
WHERE project_id = 1 AND version = 1 AND status = 'HISTORY';业务规则
- 版本递增: 新版本号 = MAX(version) + 1
- 唯一线上版本: 同一项目同时只能有一个ONLINE版本
- 快照完整性: schema_view 必须包含完整的Schema定义
- 不可篡改: ONLINE和HISTORY状态的版本不可修改
示例数据
sql
INSERT INTO kg_ontology_release
(project_id, version, schema_view, status, description, user_id, publish_time)
VALUES
(1, 1,
'{"version":1,"namespace":"medical","entities":[...],"relations":[...]}',
'HISTORY',
'初始版本',
'admin',
'2025-01-01 10:00:00'),
(1, 2,
'{"version":2,"namespace":"medical","entities":[...],"relations":[...]}',
'ONLINE',
'增加疾病类型',
'admin',
'2025-12-15 10:00:00');三、数据模型关系
3.1 ER关系图
┌─────────────────┐
│ kg_biz_domain │ 业务域
└────────┬────────┘
│ 1
│
│ N
┌────────┴────────┐
│kg_project_info │ 项目
└────────┬────────┘
│ 1
├────────────────────────────┐
│ N │ 1
┌────────┴────────┐ ┌────────┴──────────┐
│kg_project_entity│ │kg_ontology_release│
│ (项目实体关联) │ │ (版本发布) │
└────────┬────────┘ └───────────────────┘
│ N
│
│ 1
┌────────┴───────────┐
│kg_ontology_entity │ 实体类型
└────────┬───────────┘
│ 1
├───────────────────────┐
│ N │ N
┌────────┴────────────────┐ ┌──┴─────────────────────┐
│kg_ontology_entity_parent│ │kg_ontology_property │
│ (继承关系) │ │ _range (SPO三元组) │
└─────────────────────────┘ └──┬─────────────────────┘
│ N
│
│ 1
┌──────────┴──────────────────┐
│kg_ontology_property │
│ _constraint (属性约束) │
└─────────────────────────────┘3.2 核心关系说明
关系1: 业务域 → 项目 (1:N)
sql
SELECT d.name as domain_name, p.name as project_name
FROM kg_biz_domain d
LEFT JOIN kg_project_info p ON d.id = p.biz_domain_id
WHERE d.status = '1' AND p.status = '1';关系2: 项目 → 实体 (N:M, 通过kg_project_entity)
sql
SELECT p.name as project_name, e.name as entity_name
FROM kg_project_info p
INNER JOIN kg_project_entity pe ON p.id = pe.project_id
INNER JOIN kg_ontology_entity e ON pe.entity_id = e.id
WHERE p.status = '1' AND e.status = '1' AND pe.status = '1';关系3: 实体 → 属性 (1:N)
sql
SELECT e.name as entity_name,
pr.property_name,
r.name as range_type
FROM kg_ontology_entity e
INNER JOIN kg_ontology_entity_property_range pr ON e.id = pr.domain_id
INNER JOIN kg_ontology_entity r ON pr.range_id = r.id
WHERE e.status = '1' AND pr.status = '1';关系4: 实体 → 父类 (N:M)
sql
SELECT child.name as child_entity,
parent.name as parent_entity,
ep.path
FROM kg_ontology_entity child
INNER JOIN kg_ontology_entity_parent ep ON child.id = ep.entity_id
INNER JOIN kg_ontology_entity parent ON ep.parent_id = parent.id
WHERE ep.status = '1';3.3 完整的Schema查询
查询项目的完整Schema(包含所有实体、属性、继承关系):
sql
SELECT
p.name as project_name,
e.name as entity_name,
e.name_zh as entity_name_zh,
pr.property_name,
pr.property_name_zh,
r.name as property_type,
c.is_required,
c.is_unique,
parent.name as parent_entity
FROM kg_project_info p
INNER JOIN kg_project_entity pe ON p.id = pe.project_id
INNER JOIN kg_ontology_entity e ON pe.entity_id = e.id
LEFT JOIN kg_ontology_entity_property_range pr ON e.id = pr.domain_id AND pr.status = '1'
LEFT JOIN kg_ontology_entity r ON pr.range_id = r.id
LEFT JOIN kg_ontology_property_constraint c ON pr.constraint_id = c.id
LEFT JOIN kg_ontology_entity_parent ep ON e.id = ep.entity_id AND ep.status = '1'
LEFT JOIN kg_ontology_entity parent ON ep.parent_id = parent.id
WHERE p.id = 1
AND p.status = '1'
AND pe.status = '1'
AND e.status = '1'
AND pe.version_status = 'ONLINE'
ORDER BY e.name, pr.property_name;四、代码示例
4.1 Entity类示例
KgProjectInfo.java (完整代码)
java
package com.aroundix.spg.api.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* 知识图谱项目信息表
*
* @author Aroundix SPG Team
* @since 2025-12-15
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("kg_project_info")
@Schema(description = "知识图谱项目信息")
public class KgProjectInfo extends Model<KgProjectInfo> implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
@Schema(description = "主键ID")
private Long id;
@Schema(description = "项目名称")
private String name;
@Schema(description = "项目描述")
private String description;
@Schema(description = "命名空间")
private String namespace;
@Schema(description = "业务域ID")
private Long bizDomainId;
@Schema(description = "项目配置(JSON格式)")
private String config;
@Schema(description = "可见性(PRIVATE/PUBLIC)")
private String visibility;
@Schema(description = "状态(1-有效,9-删除)")
private String status;
@TableField(fill = FieldFill.INSERT)
@Schema(description = "创建时间")
private LocalDateTime gmtCreate;
@TableField(fill = FieldFill.UPDATE)
@Schema(description = "修改时间")
private LocalDateTime gmtModified;
@TableField(fill = FieldFill.INSERT)
@Schema(description = "创建人")
private String creator;
@TableField(fill = FieldFill.UPDATE)
@Schema(description = "修改人")
private String modifier;
}4.2 Mapper接口示例
KgOntologyEntityMapper.java (完整代码)
java
package com.aroundix.spg.mapper;
import com.aroundix.spg.api.entity.KgOntologyEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 本体实体类型表 Mapper接口
*
* @author Aroundix SPG Team
* @since 2025-12-15
*/
@Mapper
public interface KgOntologyEntityMapper extends BaseMapper<KgOntologyEntity> {
/**
* 根据实体名称查询实体
*
* @param name 实体名称
* @return 实体信息
*/
KgOntologyEntity selectByName(@Param("name") String name);
/**
* 根据唯一名称查询实体
*
* @param uniqueName 唯一名称(namespace.name)
* @return 实体信息
*/
KgOntologyEntity selectByUniqueName(@Param("uniqueName") String uniqueName);
/**
* 根据原始ID和版本状态查询实体
*
* @param originalId 原始ID
* @param versionStatus 版本状态
* @return 实体信息
*/
KgOntologyEntity selectByOriginalIdAndStatus(
@Param("originalId") Long originalId,
@Param("versionStatus") String versionStatus
);
/**
* 根据实体类别查询实体列表
*
* @param entityCategory 实体类别
* @return 实体列表
*/
List<KgOntologyEntity> selectByCategory(@Param("entityCategory") String entityCategory);
/**
* 根据版本状态查询实体列表
*
* @param versionStatus 版本状态
* @return 实体列表
*/
List<KgOntologyEntity> selectByVersionStatus(@Param("versionStatus") String versionStatus);
/**
* 批量插入实体
*
* @param entities 实体列表
* @return 插入数量
*/
int batchInsert(@Param("entities") List<KgOntologyEntity> entities);
}4.3 MyBatis XML示例
KgOntologyEntityMapper.xml (完整代码)
xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.aroundix.spg.mapper.KgOntologyEntityMapper">
<!-- 通用查询映射结果 -->
<resultMap id="baseResultMap" type="com.aroundix.spg.api.entity.KgOntologyEntity">
<id column="id" property="id"/>
<result column="original_id" property="originalId"/>
<result column="name" property="name"/>
<result column="name_zh" property="nameZh"/>
<result column="entity_category" property="entityCategory"/>
<result column="layer" property="layer"/>
<result column="description" property="description"/>
<result column="description_zh" property="descriptionZh"/>
<result column="with_index" property="withIndex"/>
<result column="scope" property="scope"/>
<result column="version" property="version"/>
<result column="version_status" property="versionStatus"/>
<result column="transformer_id" property="transformerId"/>
<result column="operator_config" property="operatorConfig"/>
<result column="config" property="config"/>
<result column="unique_name" property="uniqueName"/>
<result column="status" property="status"/>
<result column="gmt_create" property="gmtCreate"/>
<result column="gmt_modified" property="gmtModified"/>
</resultMap>
<!-- 根据实体名称查询实体 -->
<select id="selectByName" resultMap="baseResultMap">
SELECT * FROM kg_ontology_entity
WHERE name = #{name} AND status = '1'
LIMIT 1
</select>
<!-- 根据唯一名称查询实体 -->
<select id="selectByUniqueName" resultMap="baseResultMap">
SELECT * FROM kg_ontology_entity
WHERE unique_name = #{uniqueName} AND status = '1'
LIMIT 1
</select>
<!-- 根据原始ID和版本状态查询实体 -->
<select id="selectByOriginalIdAndStatus" resultMap="baseResultMap">
SELECT * FROM kg_ontology_entity
WHERE original_id = #{originalId}
AND version_status = #{versionStatus}
AND status = '1'
LIMIT 1
</select>
<!-- 根据实体类别查询实体列表 -->
<select id="selectByCategory" resultMap="baseResultMap">
SELECT * FROM kg_ontology_entity
WHERE entity_category = #{entityCategory} AND status = '1'
ORDER BY gmt_create DESC
</select>
<!-- 根据版本状态查询实体列表 -->
<select id="selectByVersionStatus" resultMap="baseResultMap">
SELECT * FROM kg_ontology_entity
WHERE version_status = #{versionStatus} AND status = '1'
ORDER BY gmt_create DESC
</select>
<!-- 批量插入实体 -->
<insert id="batchInsert">
INSERT INTO kg_ontology_entity (
original_id, name, name_zh, entity_category, layer,
description, description_zh, with_index, scope, version,
version_status, transformer_id, operator_config, config,
unique_name, status, gmt_create, gmt_modified
) VALUES
<foreach collection="entities" item="item" separator=",">
(
#{item.originalId}, #{item.name}, #{item.nameZh},
#{item.entityCategory}, #{item.layer}, #{item.description},
#{item.descriptionZh}, #{item.withIndex}, #{item.scope},
#{item.version}, #{item.versionStatus}, #{item.transformerId},
#{item.operatorConfig}, #{item.config}, #{item.uniqueName},
#{item.status}, NOW(), NOW()
)
</foreach>
</insert>
</mapper>4.4 Service层示例
ProjectService接口
java
package com.aroundix.spg.service;
import com.aroundix.spg.api.entity.KgProjectInfo;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* 项目管理服务
*/
public interface ProjectService extends IService<KgProjectInfo> {
/**
* 创建项目
*/
Long createProject(String name, String namespace, Long bizDomainId, String creator);
/**
* 根据名称查询项目
*/
KgProjectInfo getByName(String name);
/**
* 删除项目(软删除)
*/
boolean deleteProject(Long projectId);
}ProjectServiceImpl实现
java
package com.aroundix.spg.service.impl;
import com.aroundix.spg.api.entity.KgProjectInfo;
import com.aroundix.spg.mapper.KgProjectInfoMapper;
import com.aroundix.spg.service.ProjectService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* 项目管理服务实现
*/
@Service
public class ProjectServiceImpl
extends ServiceImpl<KgProjectInfoMapper, KgProjectInfo>
implements ProjectService {
@Override
@Transactional(rollbackFor = Exception.class)
public Long createProject(String name, String namespace, Long bizDomainId, String creator) {
KgProjectInfo project = new KgProjectInfo();
project.setName(name);
project.setNamespace(namespace);
project.setBizDomainId(bizDomainId);
project.setCreator(creator);
project.setStatus("1");
this.save(project);
return project.getId();
}
@Override
public KgProjectInfo getByName(String name) {
return this.baseMapper.selectByName(name);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deleteProject(Long projectId) {
KgProjectInfo project = this.getById(projectId);
if (project != null) {
project.setStatus("9");
return this.updateById(project);
}
return false;
}
}4.5 Controller层示例
java
package com.aroundix.spg.controller;
import com.aroundix.spg.api.entity.KgProjectInfo;
import com.aroundix.spg.service.ProjectService;
import com.pig4cloud.pigx.common.core.util.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
/**
* 项目管理控制器
*/
@RestController
@RequestMapping("/project")
@RequiredArgsConstructor
@Tag(name = "项目管理", description = "知识图谱项目管理接口")
public class ProjectController {
private final ProjectService projectService;
@PostMapping
@Operation(summary = "创建项目")
public R<Long> createProject(@RequestBody CreateProjectRequest request) {
Long projectId = projectService.createProject(
request.getName(),
request.getNamespace(),
request.getBizDomainId(),
request.getCreator()
);
return R.ok(projectId);
}
@GetMapping("/{id}")
@Operation(summary = "查询项目详情")
public R<KgProjectInfo> getProject(@PathVariable Long id) {
KgProjectInfo project = projectService.getById(id);
return R.ok(project);
}
@GetMapping("/by-name/{name}")
@Operation(summary = "根据名称查询项目")
public R<KgProjectInfo> getProjectByName(@PathVariable String name) {
KgProjectInfo project = projectService.getByName(name);
return R.ok(project);
}
@DeleteMapping("/{id}")
@Operation(summary = "删除项目")
public R<Boolean> deleteProject(@PathVariable Long id) {
boolean result = projectService.deleteProject(id);
return R.ok(result);
}
}4.6 使用示例
示例1: 创建项目并添加实体
java
@Service
@RequiredArgsConstructor
public class SchemaManagementService {
private final ProjectService projectService;
private final EntityService entityService;
/**
* 创建医疗项目并初始化Schema
*/
@Transactional(rollbackFor = Exception.class)
public void createMedicalProject() {
// 1. 创建项目
Long projectId = projectService.createProject(
"Medical KG",
"medical",
1L,
"admin"
);
// 2. 创建Disease实体类型
KgOntologyEntity disease = new KgOntologyEntity();
disease.setOriginalId(1001L);
disease.setName("Disease");
disease.setNameZh("疾病");
disease.setEntityCategory("ADVANCED");
disease.setLayer("EXTENSION");
disease.setUniqueName("medical.Disease");
disease.setVersionStatus("ONLINE");
disease.setStatus("1");
entityService.save(disease);
// 3. 关联项目和实体
KgProjectEntity projectEntity = new KgProjectEntity();
projectEntity.setProjectId(projectId);
projectEntity.setEntityId(disease.getId());
projectEntity.setVersion(1);
projectEntity.setVersionStatus("ONLINE");
projectEntity.setReferenced("N");
projectEntity.setStatus("1");
projectEntityService.save(projectEntity);
// 4. 添加属性
addProperty(disease.getId(), "name", "疾病名称", 2L, "PROPERTY");
addProperty(disease.getId(), "icd_code", "ICD编码", 2L, "PROPERTY");
}
private void addProperty(Long domainId, String propertyName,
String propertyNameZh, Long rangeId,
String category) {
KgOntologyPropertyRange property = new KgOntologyPropertyRange();
property.setDomainId(domainId);
property.setPropertyName(propertyName);
property.setPropertyNameZh(propertyNameZh);
property.setRangeId(rangeId);
property.setPropertyCategory(category);
property.setVersionStatus("ONLINE");
property.setStatus("1");
propertyRangeService.save(property);
}
}示例2: 查询完整Schema
java
@Service
@RequiredArgsConstructor
public class SchemaQueryService {
private final EntityService entityService;
private final PropertyRangeService propertyRangeService;
/**
* 查询项目的完整Schema
*/
public ProjectSchema getProjectSchema(Long projectId) {
ProjectSchema schema = new ProjectSchema();
// 1. 查询项目的所有实体
List<KgOntologyEntity> entities = entityService.getByProjectId(projectId);
for (KgOntologyEntity entity : entities) {
EntitySchema entitySchema = new EntitySchema();
entitySchema.setName(entity.getName());
entitySchema.setNameZh(entity.getNameZh());
entitySchema.setCategory(entity.getEntityCategory());
// 2. 查询实体的所有属性
List<KgOntologyPropertyRange> properties =
propertyRangeService.getByDomainId(entity.getId());
for (KgOntologyPropertyRange property : properties) {
PropertySchema propSchema = new PropertySchema();
propSchema.setName(property.getPropertyName());
propSchema.setNameZh(property.getPropertyNameZh());
propSchema.setType(getTypeName(property.getRangeId()));
propSchema.setCategory(property.getPropertyCategory());
entitySchema.addProperty(propSchema);
}
schema.addEntity(entitySchema);
}
return schema;
}
}示例3: 发布新版本
java
@Service
@RequiredArgsConstructor
public class VersionManagementService {
private final OntologyReleaseService releaseService;
private final EntityService entityService;
/**
* 发布新版本
*/
@Transactional(rollbackFor = Exception.class)
public void publishNewVersion(Long projectId, String description, String userId) {
// 1. 获取最新版本号
Integer maxVersion = releaseService.getMaxVersion(projectId);
Integer newVersion = (maxVersion == null ? 1 : maxVersion + 1);
// 2. 生成Schema快照
String schemaView = generateSchemaSnapshot(projectId);
// 3. 创建发布记录
KgOntologyRelease release = new KgOntologyRelease();
release.setProjectId(projectId);
release.setVersion(newVersion);
release.setSchemaView(schemaView);
release.setStatus("ONLINE");
release.setDescription(description);
release.setUserId(userId);
release.setPublishTime(LocalDateTime.now());
releaseService.save(release);
// 4. 将旧版本设为历史
releaseService.markAsHistory(projectId, newVersion);
}
private String generateSchemaSnapshot(Long projectId) {
// 查询完整Schema并序列化为JSON
ProjectSchema schema = schemaQueryService.getProjectSchema(projectId);
return JSON.toJSONString(schema);
}
}五、使用场景
5.1 场景1: 医疗知识图谱
需求: 构建医疗领域知识图谱,包括疾病、药物、症状等实体
Schema设计:
json
{
"namespace": "medical",
"entities": [
{
"name": "Disease",
"nameZh": "疾病",
"properties": [
{"name": "name", "type": "Text", "required": true},
{"name": "icd_code", "type": "Text"},
{"name": "symptoms", "type": "Text", "multiValue": true}
]
},
{
"name": "Drug",
"nameZh": "药物",
"properties": [
{"name": "name", "type": "Text", "required": true},
{"name": "approval_date", "type": "Date"}
]
}
],
"relations": [
{
"name": "treats",
"nameZh": "治疗",
"subjectType": "Drug",
"objectType": "Disease",
"properties": [
{"name": "effectiveness", "type": "Float"}
]
}
]
}5.2 场景2: 企业组织架构图谱
需求: 管理企业的人员、部门、项目等关系
Schema设计:
json
{
"namespace": "enterprise",
"entities": [
{
"name": "Employee",
"nameZh": "员工",
"properties": [
{"name": "name", "type": "Text", "required": true},
{"name": "email", "type": "Text", "unique": true},
{"name": "phone", "type": "Text"}
]
},
{
"name": "Department",
"nameZh": "部门",
"properties": [
{"name": "name", "type": "Text", "required": true},
{"name": "code", "type": "Text", "unique": true}
]
}
],
"relations": [
{
"name": "worksIn",
"nameZh": "所属部门",
"subjectType": "Employee",
"objectType": "Department"
},
{
"name": "manages",
"nameZh": "管理",
"subjectType": "Employee",
"objectType": "Employee"
}
]
}5.3 场景3: 电商商品图谱
需求: 构建商品、品牌、类目等关系图谱
Schema设计:
json
{
"namespace": "ecommerce",
"entities": [
{
"name": "Product",
"nameZh": "商品",
"properties": [
{"name": "title", "type": "Text", "required": true},
{"name": "price", "type": "Float", "min": 0},
{"name": "stock", "type": "Integer", "min": 0}
]
},
{
"name": "Brand",
"nameZh": "品牌",
"properties": [
{"name": "name", "type": "Text", "required": true, "unique": true},
{"name": "country", "type": "Text"}
]
},
{
"name": "Category",
"nameZh": "类目",
"properties": [
{"name": "name", "type": "Text", "required": true}
]
}
],
"relations": [
{
"name": "belongsToBrand",
"nameZh": "所属品牌",
"subjectType": "Product",
"objectType": "Brand"
},
{
"name": "inCategory",
"nameZh": "所属类目",
"subjectType": "Product",
"objectType": "Category"
}
]
}六、性能优化
6.1 索引优化
已创建的核心索引:
sql
-- kg_ontology_entity
CREATE INDEX idx_version_status ON kg_ontology_entity(version_status);
CREATE INDEX idx_original_id_version_status ON kg_ontology_entity(original_id, version_status);
-- kg_ontology_entity_property_range
CREATE INDEX idx_domain_id ON kg_ontology_entity_property_range(domain_id);
CREATE INDEX idx_property_name ON kg_ontology_entity_property_range(property_name);
-- kg_project_entity
CREATE INDEX idx_project_id_version_status ON kg_project_entity(project_id, version_status);建议添加的索引(根据实际查询模式):
sql
-- 如果经常按类别查询实体
CREATE INDEX idx_category_status ON kg_ontology_entity(entity_category, status);
-- 如果经常查询实体的关系属性
CREATE INDEX idx_domain_category ON kg_ontology_entity_property_range(domain_id, property_category);6.2 查询优化
优化1: 使用覆盖索引
sql
-- 不好的查询
SELECT * FROM kg_ontology_entity WHERE version_status = 'ONLINE';
-- 好的查询(只查询需要的字段)
SELECT id, name, name_zh, entity_category
FROM kg_ontology_entity
WHERE version_status = 'ONLINE';优化2: 分页查询
sql
-- 使用LIMIT减少数据量
SELECT * FROM kg_ontology_entity
WHERE entity_category = 'ADVANCED'
ORDER BY gmt_create DESC
LIMIT 20 OFFSET 0;优化3: 批量操作
java
// 不好的做法: 循环插入
for (KgOntologyEntity entity : entities) {
entityMapper.insert(entity);
}
// 好的做法: 批量插入
entityMapper.batchInsert(entities);6.3 缓存策略
策略1: Schema缓存
java
@Cacheable(value = "schema", key = "#projectId + '_' + #version")
public ProjectSchema getSchema(Long projectId, Integer version) {
// 查询Schema
}
@CacheEvict(value = "schema", key = "#projectId + '_*'")
public void publishSchema(Long projectId) {
// 发布新版本,清除缓存
}策略2: 实体类型缓存
java
@Cacheable(value = "entity", key = "#name")
public KgOntologyEntity getEntityByName(String name) {
return entityMapper.selectByName(name);
}6.4 数据库连接池配置
application.yml:
yaml
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
initial-size: 10
min-idle: 10
max-active: 100
max-wait: 60000
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: SELECT 1
test-while-idle: true
test-on-borrow: false
test-on-return: false七、总结
7.1 核心特性
✅ 多版本管理: 支持Schema的多版本并存,方便回滚和灰度发布 ✅ SPO三元组: 采用RDF风格的三元组模型,灵活表达复杂关系 ✅ 继承体系: 支持实体类型的单继承和多继承 ✅ 约束系统: 完善的属性约束机制(必填、唯一、范围、正则、枚举) ✅ 项目隔离: 多项目支持,数据完全隔离 ✅ Schema快照: 每个版本保存完整快照,保证数据一致性
7.2 技术亮点
🔹 遵循muotai规范: 完全兼容现有微服务架构 🔹 双数据库架构: MySQL存元数据,Neo4j存图数据 🔹 完整的审计: 所有表都有创建时间、修改时间、创建人、修改人 🔹 软删除机制: 删除数据不物理删除,便于恢复 🔹 JSON扩展字段: 预留config字段,支持未来扩展
7.3 使用建议
- 初始化顺序: 业务域 → 项目 → 实体类型 → 属性 → 约束 → 发布版本
- 版本管理: 开发环境使用LATEST版本,生产环境使用ONLINE版本
- 性能优化: 合理使用索引,启用Redis缓存,使用批量操作
- 数据一致性: 关键操作使用事务,Schema发布前做完整性校验
- 监控告警: 监控数据库慢查询,及时优化SQL
文档版本: v1.0 最后更新: 2025-12-15 维护团队: Aroundix SPG Team 联系方式: spg-support@aroundix.com