mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-04-25 08:26:21 +02:00
426 lines
14 KiB
Markdown
426 lines
14 KiB
Markdown
|
|
---
|
|||
|
|
layout: default
|
|||
|
|
title: "Graph Contexts 技术规范"
|
|||
|
|
parent: "Chinese (Beta)"
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Graph Contexts 技术规范
|
|||
|
|
|
|||
|
|
> **Beta Translation:** This document was translated via Machine Learning and as such may not be 100% accurate. All non-English languages are currently classified as Beta.
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
本规范描述了 TrustGraph 核心图结构体的变更,以符合 RDF 1.2 标准并支持完整的 RDF 数据集语义。 这对 2.x 版本系列是一个破坏性变更。
|
|||
|
|
|
|||
|
|
### 版本控制
|
|||
|
|
|
|||
|
|
- **2.0**: 早期采用版本。核心功能可用,可能尚未完全达到生产级别。
|
|||
|
|
- **2.1 / 2.2**: 生产版本。稳定性和完整性已验证。
|
|||
|
|
|
|||
|
|
关于成熟度的灵活性是故意的 - 早期采用者可以访问新的功能,而所有功能尚未经过生产环境的验证。
|
|||
|
|
|
|||
|
|
## 目标
|
|||
|
|
|
|||
|
|
本次工作的首要目标是启用关于事实/声明的元数据:
|
|||
|
|
|
|||
|
|
- **时间信息**: 将事实与时间元数据关联
|
|||
|
|
- 确定一个事实何时被认为是正确的。
|
|||
|
|
- 确定一个事实何时开始成立。
|
|||
|
|
- 确定一个事实何时被发现是错误的。
|
|||
|
|
|
|||
|
|
- **来源/溯源**: 跟踪哪些来源支持一个事实
|
|||
|
|
- “这个事实由来源 X 支持”。
|
|||
|
|
- 将事实链接回其原始文档。
|
|||
|
|
|
|||
|
|
- **真实性/信任度**: 记录对真实性的断言
|
|||
|
|
- “Person P 声明这是真的”。
|
|||
|
|
- “Person Q 声称这是假的”。
|
|||
|
|
- 启用信任评分和冲突检测。
|
|||
|
|
|
|||
|
|
**假设**: 重构(RDF-star / 引用三元组)是实现这些目标的关键机制,因为所有这些都要求对声明进行声明。
|
|||
|
|
|
|||
|
|
## 背景
|
|||
|
|
|
|||
|
|
为了表达“事实(Alice 知道 Bob)于 2024-01-15 被发现”或“来源 X 支持(Y 导致 Z)的声明”,您需要引用一个边作为可以进行声明的对象。 标准的三元组不支持这种情况。
|
|||
|
|
|
|||
|
|
### 当前限制
|
|||
|
|
|
|||
|
|
`trustgraph-base/trustgraph/schema/core/primitives.py` 中的当前 `Value` 类可以表示:
|
|||
|
|
- URI 节点 (`is_uri=True`)
|
|||
|
|
- 原始值 (`is_uri=False`)
|
|||
|
|
|
|||
|
|
`type` 字段存在,但未用于表示 XSD 数据类型。
|
|||
|
|
|
|||
|
|
## 技术设计
|
|||
|
|
|
|||
|
|
### 需要支持的 RDF 功能
|
|||
|
|
|
|||
|
|
#### 核心功能(与重构目标相关)
|
|||
|
|
|
|||
|
|
这些功能与时间、溯源和真实性目标直接相关:
|
|||
|
|
|
|||
|
|
1. **RDF 1.2 引用三元组 (RDF-star)**
|
|||
|
|
- 指向其他边的边。
|
|||
|
|
- 三元组可以作为另一个三元组的主语或宾语。
|
|||
|
|
- 启用关于声明的声明(重构)。
|
|||
|
|
- 注释单个事实的核心机制。
|
|||
|
|
|
|||
|
|
2. **RDF 数据集 / 命名图**
|
|||
|
|
- 支持数据集中的多个命名图。
|
|||
|
|
- 每个图由 IRI 标识。
|
|||
|
|
- 从三元组 (s, p, o) 转换为四元组 (s, p, o, g)。
|
|||
|
|
- 包含一个默认图以及零个或多个命名图。
|
|||
|
|
- 图 IRI 可以是语句的主语,例如:
|
|||
|
|
```
|
|||
|
|
<graph-source-A> <discoveredOn> "2024-01-15"
|
|||
|
|
<graph-source-A> <hasVeracity> "high"
|
|||
|
|
```
|
|||
|
|
- 注意:命名图是一个与重构分离的功能。 它们除了语句注释之外还有其他用途(分区、访问控制、数据集组织),并且应该被视为一种不同的能力。
|
|||
|
|
|
|||
|
|
3. **匿名节点** (有限支持)
|
|||
|
|
- 没有全局 URI 的匿名节点。
|
|||
|
|
- 用于兼容性,以便加载外部 RDF 数据。
|
|||
|
|
- **有限状态**: 对加载后身份的稳定性没有保证。
|
|||
|
|
- 通过通配符查询找到它们(通过连接匹配,而不是通过 ID)。
|
|||
|
|
- 不是首选功能 - 不要依赖于精确的匿名节点处理。
|
|||
|
|
|
|||
|
|
#### 机会性修复 (2.0 破坏性变更)
|
|||
|
|
|
|||
|
|
这些功能与重构目标没有直接关系,但包含在破坏性变更中是有价值的改进:
|
|||
|
|
|
|||
|
|
4. **原始数据类型**
|
|||
|
|
- 正确使用 `type` 字段表示 XSD 数据类型。
|
|||
|
|
- 示例:xsd:string, xsd:integer, xsd:dateTime 等。
|
|||
|
|
- 修复当前限制:无法正确表示日期或整数。
|
|||
|
|
|
|||
|
|
5. **语言标签**
|
|||
|
|
- 支持字符串原始值上的语言属性 (@en, @fr 等)。
|
|||
|
|
- 注意:一个原始值要么有一个语言标签,要么有一个数据类型,两者不能同时存在(除了 rdf:langString)。
|
|||
|
|
- 对于 AI/多语言用例非常重要。
|
|||
|
|
|
|||
|
|
### 数据模型
|
|||
|
|
|
|||
|
|
#### Term (重命名自 Value)
|
|||
|
|
|
|||
|
|
`Value` 类将被重命名为 `Term`,以更好地反映 RDF 术语。
|
|||
|
|
此重命名有两个目的:
|
|||
|
|
1. 与 RDF 概念对齐命名(“Term”可以是 IRI、原始值、匿名节点或引用三元组,而不仅仅是“值”)。
|
|||
|
|
2. 在破坏性变更接口强制代码审查 - 任何仍然引用 `Value` 的代码都会立即显示为已损坏,并且需要更新。
|
|||
|
|
|
|||
|
|
一个 Term 可以表示:
|
|||
|
|
|
|||
|
|
- **IRI/URI** - 命名节点/资源。
|
|||
|
|
- **匿名节点** - 具有本地作用域的匿名节点。
|
|||
|
|
- **原始值** - 具有以下之一的数据值:
|
|||
|
|
- 数据类型 (XSD 类型),或
|
|||
|
|
- 语言标签。
|
|||
|
|
- **引用三元组** - 用作项的三元组 (RDF 1.2)。
|
|||
|
|
|
|||
|
|
##### 选定的方法:具有类型区分器的单个类
|
|||
|
|
|
|||
|
|
序列化要求驱动结构 - 无论 Python 表示形式如何,都需要类型区分器。 具有类型字段的单个类是最佳选择,并且与当前的 `Value` 模式一致。
|
|||
|
|
|
|||
|
|
单字符类型代码提供紧凑的序列化:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
from dataclasses import dataclass
|
|||
|
|
|
|||
|
|
# Term 类型常量
|
|||
|
|
IRI = "i" # IRI/URI 节点
|
|||
|
|
BLANK = "b" # 匿名节点
|
|||
|
|
LITERAL = "l" # 原始值
|
|||
|
|
TRIPLE = "t" # 引用三元组 (RDF-star)
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class Term:
|
|||
|
|
type: str = "" # 之一: IRI, BLANK, LITERAL, TRIPLE
|
|||
|
|
|
|||
|
|
# 对于 IRI 项 (type == IRI)
|
|||
|
|
iri: str = ""
|
|||
|
|
|
|||
|
|
# 对于匿名节点 (type == BLANK)
|
|||
|
|
id: str = ""
|
|||
|
|
|
|||
|
|
# 对于原始值 (type == LITERAL)
|
|||
|
|
value: str = ""
|
|||
|
|
datatype: str = "" # XSD 数据类型 URI (与语言互斥)
|
|||
|
|
language: str = "" # 语言标签 (与数据类型互斥)
|
|||
|
|
|
|||
|
|
# 对于引用三元组 (type == TRIPLE)
|
|||
|
|
triple: "Triple | None" = None
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
用法示例:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
# IRI 项
|
|||
|
|
node = Term(type=IRI, iri="http://example.org/Alice")
|
|||
|
|
|
|||
|
|
# 带数据类型的原始值
|
|||
|
|
age = Term(type=LITERAL, value="42", datatype="xsd:integer")
|
|||
|
|
|
|||
|
|
# 带语言标签的原始值
|
|||
|
|
label = Term(type=LITERAL, value="Hello", language="en")
|
|||
|
|
|
|||
|
|
# 匿名节点
|
|||
|
|
anon = Term(type=BLANK, id="_:b1")
|
|||
|
|
|
|||
|
|
# 引用三元组 (关于声明的声明)
|
|||
|
|
inner = Triple(
|
|||
|
|
s=Term(type=IRI, iri="http://example.org/Alice"),
|
|||
|
|
p=Term(type=IRI, iri="http://example.org/knows"),
|
|||
|
|
o=Term(type=IRI, iri="http://example.org/Bob"),
|
|||
|
|
)
|
|||
|
|
reified = Term(type=TRIPLE, triple=inner)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
##### 考虑的替代方案
|
|||
|
|
|
|||
|
|
**选项 B:专用类的联合** (`Term = IRI | BlankNode | Literal | QuotedTriple`)
|
|||
|
|
- 拒绝:仍然需要类型区分器进行序列化,增加了复杂性。
|
|||
|
|
|
|||
|
|
**选项 C:具有子类的基本类**
|
|||
|
|
- 拒绝:与序列化问题相同,此外还有 dataclass 继承的复杂性。
|
|||
|
|
|
|||
|
|
#### Triple / Quad
|
|||
|
|
|
|||
|
|
`Triple` 类获得一个可选的图字段,以成为四元组:
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
@dataclass
|
|||
|
|
class Triple:
|
|||
|
|
s: Term | None = None # 主语
|
|||
|
|
p: Term | None = None # 谓词
|
|||
|
|
o: Term | None = None # 宾语
|
|||
|
|
g: str | None = None # 图名 (IRI),None = 默认图
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
设计决策:
|
|||
|
|
- **字段名称**: `g` 用于与 `s`、`p`、`o` 一致。
|
|||
|
|
- **可选**: `None` 表示默认图(无命名)。
|
|||
|
|
- **类型**: 纯字符串 (IRI),而不是 Term
|
|||
|
|
- 图名始终是 IRI。
|
|||
|
|
- 匿名节点作为图名被排除(过于混乱)。
|
|||
|
|
- 不需要完整的 Term 机制。
|
|||
|
|
|
|||
|
|
注意:类名保持为 `Triple`,即使它现在实际上是一个四元组。
|
|||
|
|
这避免了变更,并且术语“三元组”仍然是常见的术语。 图上下文是关于三元组存储位置的元数据。
|
|||
|
|
|
|||
|
|
### 候选查询模式
|
|||
|
|
|
|||
|
|
当前查询引擎接受 S、P、O 项的组合。 使用引用三元组时,一个三元组本身可以成为这些位置上的有效项。 以下是支持原始目标的候选查询模式。
|
|||
|
|
|
|||
|
|
#### 图参数语义
|
|||
|
|
|
|||
|
|
遵循 SPARQL 的约定以实现向后兼容:
|
|||
|
|
|
|||
|
|
- **`g` 被省略 / None**: 仅查询默认图。
|
|||
|
|
- **`g` = 特定 IRI**: 仅查询该命名图。
|
|||
|
|
- **`g` = 通配符 / `*`**: 查询所有图 (相当于 SPARQL `GRAPH ?g { ... }`)
|
|||
|
|
|
|||
|
|
这保持简单查询的简单性,并使命名图查询成为可选。
|
|||
|
|
|
|||
|
|
完全支持跨图查询 (g=通配符)。 Cassandra 模式包含专门的表,其中 g 是一个聚类列,而不是分区键,从而实现高效的跨所有图的查询。
|
|||
|
|
|
|||
|
|
#### 时间查询
|
|||
|
|
|
|||
|
|
**查找在特定日期之后发现的所有事实:**
|
|||
|
|
```
|
|||
|
|
S: ? # 任何引用三元组
|
|||
|
|
P: <discoveredOn>
|
|||
|
|
O: > "2024-01-15"^^xsd:date # 日期比较
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**查找何时认为特定事实成立:**
|
|||
|
|
```
|
|||
|
|
S: << <Alice> <knows> <Bob> >> # 引用三元组作为主语
|
|||
|
|
P: <believedTrueFrom>
|
|||
|
|
O: ? # 返回日期
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**查找被发现为错误的 facts:**
|
|||
|
|
```
|
|||
|
|
S: ? # 任何引用三元组
|
|||
|
|
P: <discoveredFalseOn>
|
|||
|
|
O: ? # 具有任何值 (存在)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 溯源查询
|
|||
|
|
|
|||
|
|
**查找由特定来源支持的所有事实:**
|
|||
|
|
```
|
|||
|
|
S: ? # 任何引用三元组
|
|||
|
|
P: <supportedBy>
|
|||
|
|
O: <source:document-123>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**查找哪些来源支持特定事实:**
|
|||
|
|
```
|
|||
|
|
S: << <DrugA> <treats> <DiseaseB> >> # 引用三元组作为主语
|
|||
|
|
P: <supportedBy>
|
|||
|
|
O: ? # 返回来源 IRI
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 真实性查询
|
|||
|
|
|
|||
|
|
**查找 Person 声明为真的断言:**
|
|||
|
|
```
|
|||
|
|
S: ? # 任何引用三元组
|
|||
|
|
P: <assertedTrueBy>
|
|||
|
|
O: <person:Alice>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**查找冲突的断言 (相同的 facts,不同的真实性):**
|
|||
|
|
```
|
|||
|
|
# 第一个查询:声明为真的事实
|
|||
|
|
S: ?
|
|||
|
|
P: <assertedTrueBy>
|
|||
|
|
O: ?
|
|||
|
|
|
|||
|
|
# 第二个查询:声明为假的 fact
|
|||
|
|
S: ?
|
|||
|
|
P: <assertedFalseBy>
|
|||
|
|
O: ?
|
|||
|
|
|
|||
|
|
# 应用程序逻辑:查找主语的交集
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**查找信任评分低于阈值的 facts:**
|
|||
|
|
```
|
|||
|
|
S: ? # 任何引用三元组
|
|||
|
|
P: <trustScore>
|
|||
|
|
O: < 0.5 # 数值比较
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 架构
|
|||
|
|
|
|||
|
|
需要对多个组件进行重大更改:
|
|||
|
|
|
|||
|
|
#### 此仓库 (trustgraph)
|
|||
|
|
|
|||
|
|
- **模式原始数据类型** (`trustgraph-base/trustgraph/schema/core/primitives.py`)
|
|||
|
|
- `Value` → `Term` 重命名。
|
|||
|
|
- 具有类型区分器的新的 `Term` 结构。
|
|||
|
|
- `Triple` 获得 `g` 字段以进行图上下文。
|
|||
|
|
|
|||
|
|
- **消息翻译器** (`trustgraph-base/trustgraph/messaging/translators/`)
|
|||
|
|
- 更新以适应新的 `Term` 和 `Triple` 结构。
|
|||
|
|
- 用于新字段的序列化/反序列化。
|
|||
|
|
|
|||
|
|
- **网关组件**
|
|||
|
|
- 处理新的 `Term` 和四元组结构。
|
|||
|
|
|
|||
|
|
- **知识核心**
|
|||
|
|
- 支持四元组和重构的核心更改。
|
|||
|
|
|
|||
|
|
- **知识管理器**
|
|||
|
|
- 模式更改会在此处传播。
|
|||
|
|
|
|||
|
|
- **存储层**
|
|||
|
|
- Cassandra: 重新设计模式(参见“实施详细信息”)。
|
|||
|
|
- 其他后端:推迟到后续阶段。
|
|||
|
|
|
|||
|
|
- **命令行工具**
|
|||
|
|
- 更新以适应新的数据结构。
|
|||
|
|
|
|||
|
|
- **REST API 文档**
|
|||
|
|
- 更新 OpenAPI 规范。
|
|||
|
|
|
|||
|
|
#### 外部仓库
|
|||
|
|
|
|||
|
|
- **Python API** (此仓库)
|
|||
|
|
- 更新客户端库以匹配新的结构。
|
|||
|
|
|
|||
|
|
- **TypeScript API** (单独仓库)
|
|||
|
|
- 平行于 Python API 的更改。
|
|||
|
|
- 分离的发布协调。
|
|||
|
|
|
|||
|
|
- **Workbench** (单独仓库)
|
|||
|
|
- 状态管理方面的重大更改。
|
|||
|
|
- 用于图上下文功能的 UI 更新。
|
|||
|
|
|
|||
|
|
### API
|
|||
|
|
|
|||
|
|
#### REST API
|
|||
|
|
|
|||
|
|
- 在 OpenAPI 规范中记录。
|
|||
|
|
- 需要更新以适应新的 `Term` 和 `Triple` 结构。
|
|||
|
|
- 可能需要新的端点来处理图上下文操作。
|
|||
|
|
|
|||
|
|
#### Python API (此仓库)
|
|||
|
|
|
|||
|
|
- 客户端库更改以匹配新的原始数据类型。
|
|||
|
|
- `Term` (以前是 `Value`) 和 `Triple` 的破坏性更改。
|
|||
|
|
|
|||
|
|
#### TypeScript API (单独仓库)
|
|||
|
|
|
|||
|
|
- 与 Python API 平行的更改。
|
|||
|
|
- 分离的发布协调。
|
|||
|
|
|
|||
|
|
#### Workbench (单独仓库)
|
|||
|
|
|
|||
|
|
- 状态管理方面的重大更改。
|
|||
|
|
- 用于图上下文功能的 UI 更新。
|
|||
|
|
|
|||
|
|
### 实施细节
|
|||
|
|
|
|||
|
|
#### 分阶段的存储实施
|
|||
|
|
|
|||
|
|
存在多个图存储后端(Cassandra、Neo4j 等)。
|
|||
|
|
实施将分阶段进行:
|
|||
|
|
|
|||
|
|
1. **第一阶段:Cassandra**
|
|||
|
|
- 在完全控制的后端上验证设计,然后再承诺在所有存储系统中的实现。
|
|||
|
|
|
|||
|
|
2. **第二阶段+:其他后端**
|
|||
|
|
- 在后续阶段实施 Neo4j 和其他存储系统。
|
|||
|
|
|
|||
|
|
此方法通过在所有系统上承诺实现之前,在完全受控的后端上验证设计,从而降低风险。
|
|||
|
|
|
|||
|
|
#### `Value` → `Term` 重命名
|
|||
|
|
|
|||
|
|
`Value` 类将被重命名为 `Term`。 这会影响代码库中的约 78 个文件。
|
|||
|
|
重命名充当强制函数:任何仍然使用 `Value` 的代码都将立即显示为需要审查/更新以获得 2.0 兼容性。
|
|||
|
|
|
|||
|
|
## 安全注意事项
|
|||
|
|
|
|||
|
|
命名图不是安全功能。 用户和集合仍然是安全边界。 命名图纯粹用于数据组织和重构支持。
|
|||
|
|
|
|||
|
|
## 性能注意事项
|
|||
|
|
|
|||
|
|
- 引用三元组会增加嵌套深度,这可能会影响查询性能。
|
|||
|
|
- 需要命名图索引策略以实现高效的范围查询。
|
|||
|
|
- Cassandra 模式设计需要适应四元组存储。
|
|||
|
|
|
|||
|
|
### 向量存储边界
|
|||
|
|
|
|||
|
|
向量存储始终只引用 IRI:
|
|||
|
|
- 永远不要边(引用三元组)。
|
|||
|
|
- 永远不要原始值。
|
|||
|
|
- 永远不要匿名节点。
|
|||
|
|
|
|||
|
|
这使向量存储保持简单 - 它处理命名实体语义相似性。 图结构处理关系、重构和元数据。 引用三元组和命名图不会使向量操作复杂化。
|
|||
|
|
|
|||
|
|
## 测试策略
|
|||
|
|
|
|||
|
|
使用现有的测试策略。 由于这是一个破坏性版本,因此需要重点关注端到端测试套件,以验证新的结构是否在所有组件中都正确工作。
|
|||
|
|
|
|||
|
|
## 迁移计划
|
|||
|
|
|
|||
|
|
- 2.0 是一个破坏性版本;不需要向后兼容性。
|
|||
|
|
- 现有数据可能需要迁移到新的模式(基于最终设计的确定)。
|
|||
|
|
- 考虑迁移工具,用于转换现有三元组。
|
|||
|
|
|
|||
|
|
## 开放问题
|
|||
|
|
|
|||
|
|
- **匿名节点**: 确认有限支持。 可能需要决定采用 Skolem 化策略(在加载时生成 IRI,或保留匿名节点 ID)。
|
|||
|
|
- **查询语法**: 引用三元组在查询中的具体语法是什么? 需要定义查询 API。
|
|||
|
|
- **谓词词汇表**: 已解决。 允许任何有效的 RDF 谓词,包括自定义的用户定义的谓词。 尽量减少对任何事情的锁定(例如,在某些地方使用 `rdfs:label`)。 策略:除非绝对必要,否则避免锁定任何内容。
|
|||
|
|
- **向量存储影响**: 已解决。 向量存储始终仅指向 IRI - 永远不要边、原始值或匿名节点。 引用三元组和重构不会影响向量存储。
|
|||
|
|
|
|||
|
|
## 参考文献
|
|||
|
|
|
|||
|
|
- [RDF 1.2 概念](https://www.w3.org/TR/rdf12-concepts/)
|
|||
|
|
- [RDF-star 和 SPARQL-star](https://w3c.github.io/rdf-star/)
|
|||
|
|
- [RDF 数据集](https://www.w3.org/TR/rdf11-concepts/#section-dataset)
|