> For the complete documentation index, see [llms.txt](https://relationlabs.gitbook.io/semantic-sbt/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://relationlabs.gitbook.io/semantic-sbt/semanticsbt-zh/zheng-ti-jie-gou-she-ji.md).

# 整体结构设计

## 整体架构

Relation Labs 基于SBT的理念，设计并实现了一套链上语义存储网络。通过该网络，各项目方和WEB3 开发者可以快速便捷地铸造语义SBT、建立自己的品牌，共同创建去中心化的社交图谱。该网络主要由三部分组成：

* 调用层
* 合约层
* 链外服务层

<figure><img src="/files/focz6XfbxgM6wIrIvAQI" alt=""><figcaption></figcaption></figure>

项目方或WEB3开发者在使用该语义网络时，首先需要将数据的schema保存在IPFS、Arweave 之类的链外去中心化存储服务器中，供后续数据组装和分析时使用。然后调用Semantic 合约进行数据的链上存储以及mint SBT等操作。同时结合着合约规范中的event事件，Semantic Scan会将SBT数据以RDF格式保存至包含Relation Graph的Semantic Scan中，并提供相应API接口，供项目方和开发者使用。同时也可以通过SPARQL进行相关数据的各种组合、关联等高级业务查询。

### 调用层

RDF作为资源描述框架，其本质是一个数据模型，是对具体事物的描述。但是RDF的表达能力有限，无法区分类和对象，也无法定义和描述类的关系或者属性。因此调用方在存储RDF数据前，需要先把数据对应的schema确定好，schema是RDF的属性描述，类比于数据库中的表结构。通过schema，开发者可以将保存至链上的数据形具有业务意义的数据。所以开发者在调用合约之前，需要先在链外定义好RDF Schema，并将其保存至IPFS、Arweave 之类的链外去中心化存储服务中。

下边是以“员工”为对象的RDF Schema的例子

```
PREFIX : <http://relationlabs.ai/entity/>
PREFIX p: <http://relationlabs.ai/property/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

### 这里定义了“员工”这个类
:Staff a rdfs:Class;
      rdfs:label "entity";
      rdfs:comment "A staff" .

### staff 有三个属性分别是name，age，career，对应类型分别是string，integer，string
p:name rdf:Property;
      rdfs:label "the name of staff";
      rdfs:range xsd:string .

p:age rdf:Property;
      rdfs:label "the age of staff";
      rdfs:range xsd:integer .
        
p:career rdf:Property;
      rdfs:label "the career of staff";
      rdfs:range xsd:string .
```

### 合约层

#### 合约逻辑设计

Semantic SBT合约在ERC721和ERC5192基础上，增加了RDF数据结构以及对应的生成方法。合约实现的逻辑设计方面主要分为三部分：

* Data Entity：定义了Class（主语实体）、Subject（主语）、Predicate（谓语）、Turtle（完整三元组） 等数据对象规范。通过数据实体规范了RDF数据组成单元。
* Semantic Entity：基于语义规范，对数据对象进行实例化和关系化组合，形成具体的RDF数据模型。
* Contract Method：在Semantic合约中，在数据规范和数据组装模型的前提下，定义了相应的方法，来完成SBT的创建和使用。

<figure><img src="/files/8JUR2ckSGBZiPa6EBRrk" alt=""><figcaption></figcaption></figure>

在这个三部分中，语义实体的实例化和组装起到关键性的作用，即关系到了数据的保存方式，有直接影响了SBT的生成过程。

#### 语义实体的生成逻辑

<figure><img src="/files/ZrYa4XfkTPZTe0iSSqfZ" alt=""><figcaption></figcaption></figure>

语义的组装过程主要包括以下几个步骤

* 初始化合约：在`合约初始化`阶段
  * 定义token的基本属性，比如token的name, symbol, baseURI
  * 定义主语对应的实例，即Class
  * 定义谓语，即Predicate
  * 定义SBT对应的schemaURI，用于保存RDF数据对应的schema
* 新增Subject：在`合约初始化`完成后，可以基于已经确定的Class，可以新建对应的主语。
* 新增Object：在`Mint`前，可以提前将需要新增的Object和已确定的Predicate关联生成相应的PredicateAndObject对象。
* 生成Turtle：在`Mint`过程中，将传入的Subject和PredicateAndObject组装为Turtle数据，生成对应Token，并分配给对应Address。
* 生成RDF数据：在`Mint` 结束前，通过事件通知方法，将Turtle数据转换为RDF格式的数据通知到合约监听方。

可以看出，在SBT的Mint过程中，Turtle的组装、创建和分发是SBT非常关键的部分。

#### **Turtle组成结构**

<figure><img src="/files/GJnNoM1OAmDpapa1eALS" alt=""><figcaption></figcaption></figure>

1. 初始化合约时，会将主语对象和谓词提前制定好。在合约部署后的初始化阶段，会定义Class 和Predicate。初始化时，合约会基于 Class Name生成对应的Class的index。同样的，会基于Predicate Name 以及Predicate Type，生成对应的Predicate Index。谓词类型包括：Integer、String、Address、Subject和BlankNode。Subject可以理解为自定义谓词。
2. 创建主语，即Subject。Subject由Value和ClassId组成，在创建Subject时，通过addSubject方法，传入Subject Value 和Class Name，首先根据Class Name检查是否为初始化生成的Class，然后基于Subject Value生成对应的Subject Index，最后根据Class Index和Subject Value生成Subject。
3. 绑定谓词和宾语，即PredicateId和Object，生成PredicateAndObject。在mint Semantic Token 过程中，通过传入Predicate Index 和Object，生成对应Predicate类型的PredicateAndObject。
4. 将subject和predicateAndObject组装成Turtle，在mint Semantic Token 过程中，通过将Subject 和 PredicateAndObject关联，形成Turtle数据，并与对应的Token id相关联，并将Token指定给对应用户，该用户可以是合约调用者，也可以是指定SBT拥有者。
5. 将subject和predicateAndObject规范为RDF格式存储。通过合约事件监听，可以获取到组装好的RDF格式的数据，并可以将其直接进行链外数据保存。

### 链外服务层

链外服务层主要是通过合约监听服务将数据保存至图数据库中，进而可以通过图数据库进行业务功能扩展。具体的图数据库、合约监听服务，项目方可以根据自身技术架构自行选择和实现。

我们将在`使用The Graph 索引脸上RDF数据` 章节提供相应的实现Demo。

\`\`
