# 使用The Graph 索引链上RDF数据

### 概述

在部署Semantic SBT合约后，项目方可以通过对接`The Graph 服务`，来获取链上SBT对应的RDF数据。

在获取到RDF数据后，项目方可以自行选择对应的图数据库来存储从链上的RDF数据。

本文档以AWS的Neptune为例，演示如何将链上RDF数据保存至图数据中。

具体步骤：

1. 通过The Graph获取到数据实体中的RDF数据内容，即链上数据的`turtle数据对象`
2. 通过调用合约的`schemaURI`方法查询RDF对应的数据schema。
3. 将schema和turtle数据对象按SPARQL UPDATE语法格式拼接成对应的图数据库插入语句。
4. 调用Neptune的服务接口

### GraphQL API服务介绍

数据访问方式：

* 通过The Graph 官方提供的webUI(playground)的方式查询
* 通过HTTP请求方式查询
* 通过JS Client的方式查询

#### 数据实体

* id: The transaction id .
* txnHash: The transaction hash in blockchain.
* blockNumber: The block number.
* contract: The contract address.
* owner: The token owner of SBT.
* tokenId: The token id of SBT.
* turtle: The RDF content.

#### Web UI的方式查询

GraphQL API项目地址：

<https://thegraph.com/hosted-service/subgraph/relationlabs/semantic-sbt>

可以登录后可以通过The Graph提供的playground进行查询

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

#### HTTP REST 请求

查询最近两条（对应参数 `first:2`）token对应的数据实体

{% code overflow="wrap" %}

```shell
curl --location --request POST 'https://api.thegraph.com/subgraphs/name/relationlabs/semantic-sbt' \
--header 'Content-Type: application/json' \
--data-raw '{"query":"{\n  turtles(first: 2) {\n    id\n    owner\n    tokenId\n    turtle\n  }\n}"}'
```

{% endcode %}

查询结果

{% code overflow="wrap" %}

```shell
{"data":{"turtles":[{"id":"33456276423","owner":"0x16ff7821a8d293cd2ea07b650fc69ea9206d0615","tokenId":"1","turtle":":Activity1 p:name \"Activity_2049_1\" . :Activity1 p:level 1 . "},{"id":"33456276425","owner":"0x16ff7821a8d293cd2ea07b650fc69ea9206d0615","tokenId":"2","turtle":":Activity2 p:name \"Activity_2049_2\" . :Activity2 p:level 2 . "}]}}
```

{% endcode %}

### 通过JS Client的方式查询

安装 @apollo/client 和 graphql组件

```shell
npm install @apollo/client graphql
```

初始化client

{% code overflow="wrap" %}

```js
import { ApolloClient, InMemoryCache, gql } from '@apollo/client'

const APIURL = 'https://api.thegraph.com/subgraphs/name/relationlabs/semantic-sbt'

const tokensQuery = `
  query($first: Int, $contract: String) {
    turtles(
      first: $first, contract: $contract
    ) {
      id
      tokenId
      owner
      turtle
    }
  }

const client = new ApolloClient({
  uri: APIURL,
  cache: new InMemoryCache(),
})

client
  .query({
    query: gql(tokensQuery),
    variables: {
      first: 2,
      contract: '0xb8eDcD887DF79278E227dAb986cb2a91C2347E02',
    },
  })
  .then((data) => console.log('Subgraph data: ', data))
  .catch((err) => {
    console.log('Error fetching data: ', err)
  })
```

{% endcode %}

### 获取图数据库对应的Schema

通过调用合约的`schemaURI`方法查询schema。

该schema用于构建图数据库时，存储数据时使用。

### RDF数据导入图数据库

1. 在[aws控制台](https://ap-northeast-1.console.aws.amazon.com/neptune/home)启动一个Neptune实例
2. 将turtle数据与对应schema拼接成SPARQL update语句

{% code overflow="wrap" %}

```
update=INSERT DATA 
{ <https://test.com/s> <https://test.com/p> <https://test.com/o> . }
```

{% endcode %}

3\. 调用Neptune服务接口保存RDF数据

{% code overflow="wrap" %}

```shell
curl -X POST --data-binary 'update=INSERT DATA { <https://test.com/s> <https://test.com/p> <https://test.com/o> . }' https://your-neptune-endpoint:port/sparql
```

{% endcode %}

4\. 调用Neptune服务接口查询保存的数据

{% code overflow="wrap" %}

```shell
curl -X POST --data-binary 'query=select ?s ?p ?o where {?s ?p ?o} limit 10' https://your-neptune-endpoint:port/sparql
```

{% endcode %}

### 代码示例

下边通过一段python代码，来示例如何查询链上RDF数据，并保存至Neptune图数据库中的完整过程。

{% code overflow="wrap" %}

```python
import json
import requests

// 通过The graph的HTTP接口，获取链上对应token的RDF数据，并解析对应的turtle数据对象
def graphql_query():
    turtles = []
    graphql_endpoint = 'https://api.thegraph.com/subgraphs/name/relationlabs/semantic-sbt'
    data = {
        'query': '{turtles(where: {contract: "0xb8eDcD887DF79278E227dAb986cb2a91C2347E02", blockNumber_gt: '
                 '"35661923", blockNumber_lt: "35671923"}) {id owner tokenId turtle}} '
    }
    res = requests.post(graphql_endpoint, headers={'Content-Type': 'application/json'}, data=json.dumps(data))
    print(len(json.loads(res.text)['data']['turtles']))
    for item in json.loads(res.text)['data']['turtles']:
        turtles.append(item['turtle'])
    return turtles

// 将turtle数据对象和对应Schema拼装为sparql格式语句，通过Neptune服务接口，保存至图数据库中
def load_rdf(turtles):
    neptune_endpoint = 'https://your-neptune-endpoint:port/sparql'
    for turtle in turtles:
        sparql = 'update=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#> ' \
                 'INSERT DATA {GRAPH <http://relationlabs.ai/relationship> { ' + turtle + ' }}'
        res = requests.post(neptune_endpoint,
                            headers={'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'},
                            data=sparql)
        print(res.text)


if __name__ == '__main__':
    load_rdf(graphql_query())
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://relationlabs.gitbook.io/semantic-sbt/semanticsbt-zh/untitled/shi-yong-the-graph-suo-yin-lian-shang-rdf-shu-ju.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
