# 构建图谱

> 本协议支持所有符合RDF规范的图数据库。

将上一章构建出来的RDF数据导入图数据库，即可得到一个简单的社交图。

<figure><img src="https://3668324987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdqevFF76s9Kq7JWAPlD3%2Fuploads%2Fgit-blob-d5ef5305e862945ffd0460281012c6a1c504be94%2Ffollow.png?alt=media" alt=""><figcaption><p>图 7-3 一个简单的社交图</p></figcaption></figure>

## 使用Neptune

> [Amazon Neptune](https://docs.aws.amazon.com/zh_cn/neptune/latest/userguide/intro.html) 是一项快速、可扩展的图形数据库服务。Neptune 可高效存储和导航高度互连的数据。它的查询处理引擎针对领先的图形查询语言 Apache TinkerPop™ Gremlin 和 W3C 的 RDF SPARQL 进行了优化。Neptune 通过这些图形框架开放和标准的 API 实现了高性能。

借助[Amazon Neptune](https://docs.aws.amazon.com/zh_cn/neptune/latest/userguide/intro.html)我们可以把用户在区块链上的行为数据，构建出一个社交图谱。

具体步骤：

1. 在[aws控制台](https://ap-northeast-1.console.aws.amazon.com/neptune/home)启动一个Neptune实例
2. 将上一章构建的sparql拼接成Neptune插入语句：

```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> {
:Soul_0x0109c8ee3151bde7b6b5d9f37e9d2c4bc16930fe a :Soul;
    p:name "Alice" .
:Soul_0x6247123ec0fe0d25feb811e3c4d4a760c1f2e63e a :Soul;
    p:name "Bob" .
:Soul_0x0109c8ee3151bde7b6b5d9f37e9d2c4bc16930fe p:following :Soul_0x6247123ec0fe0d25feb811e3c4d4a760c1f2e63e .
}}
```

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

```shell
curl -X POST --data-binary '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> {
:Soul_0x0109c8ee3151bde7b6b5d9f37e9d2c4bc16930fe a :Soul;
    p:name "Alice" .
:Soul_0x6247123ec0fe0d25feb811e3c4d4a760c1f2e63e a :Soul;
    p:name "Bob" .
:Soul_0x0109c8ee3151bde7b6b5d9f37e9d2c4bc16930fe p:following :Soul_0x6247123ec0fe0d25feb811e3c4d4a760c1f2e63e .  }}' https://your-neptune-endpoint:port/sparql
```

至此，我们已经将`Alice follow Bob`的数据索引至图数据库了，通过调用Neptune服务接口查询数据：

```shell
curl -X POST --data-binary 'query=select * where {
?s a :Soul;
  p:name "Alice".
?s p:following ?f .} limit 10' https://your-neptune-endpoint:port/sparql
```

## 使用Jena

为了方便演示，我们使用[docker](https://www.docker.com)来启动一个Jena服务：

```shell
docker run -p 3030:3030 -e ADMIN_PASSWORD=pw123 stain/jena-fuseki
```

启动成功后访问 <http://localhost:3030/，账户：admin/pw123。>

1. 首先创建一个数据集

<figure><img src="https://3668324987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdqevFF76s9Kq7JWAPlD3%2Fuploads%2Fgit-blob-f34b0a811c0d96724dce01071c597ab229d1f8fe%2Fjena-1.png?alt=media" alt=""><figcaption><p>图 7-4 添加一个数据集</p></figcaption></figure>

<figure><img src="https://github.com/relationlabs/relation-docs/blob/gitbook/protocol/zh/indexer/...gitbook/assets/jena-2.png" alt=""><figcaption><p>图 7-5 创建demo数据集</p></figcaption></figure>

2. 然后将上一步的数据导入图数据库

```sparql
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#>

:Soul_0x0109c8ee3151bde7b6b5d9f37e9d2c4bc16930fe a :Soul;
    p:name "Alice" .

:Soul_0x6247123ec0fe0d25feb811e3c4d4a760c1f2e63e a :Soul;
    p:name "Bob" .

:Soul_0x0109c8ee3151bde7b6b5d9f37e9d2c4bc16930fe p:following :Soul_0x6247123ec0fe0d25feb811e3c4d4a760c1f2e63e .
```

<figure><img src="https://3668324987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdqevFF76s9Kq7JWAPlD3%2Fuploads%2Fgit-blob-ce8d0ee4b671f69bd0622877afca3d1f9d6afead%2Fjena-3.png?alt=media" alt=""><figcaption><p>图 7-6 上传RDF数据</p></figcaption></figure>

<figure><img src="https://3668324987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdqevFF76s9Kq7JWAPlD3%2Fuploads%2Fgit-blob-1065a94c116c037d411a7e055e184996dc523ed8%2Fjena-4.png?alt=media" alt=""><figcaption><p>图 7-7 选择文件并上传</p></figcaption></figure>

3. 最后切换至Query标签页，查询一下Alice关注了哪些人：

```sparql
PREFIX : <http://relationlabs.ai/entity/>
PREFIX p: <http://relationlabs.ai/property/>

SELECT * WHERE {
  ?me a :Soul;
	p:name "Alice";
    p:following ?following .
  ?following p:name ?name .
}
LIMIT 10
```

<figure><img src="https://3668324987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdqevFF76s9Kq7JWAPlD3%2Fuploads%2Fgit-blob-0ab3237c1463cec391496e3b4a4c2d832497a099%2Fjena-5.png?alt=media" alt=""><figcaption><p>图 7-8 使用SPARQL进行查询</p></figcaption></figure>

<figure><img src="https://3668324987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdqevFF76s9Kq7JWAPlD3%2Fuploads%2Fgit-blob-4c87ebf1ac4721a4eeec29c077508901db296015%2Fjena-6.png?alt=media" alt=""><figcaption><p>图 7-9 查询结果</p></figcaption></figure>

即可查询到：Alice的地址`0x0109c8ee3151bde7b6b5d9f37e9d2c4bc16930fe` follow了Bob的地址`0x6247123ec0fe0d25feb811e3c4d4a760c1f2e63e`。

## 使用Neo4j

为了方便演示，我们使用[docker](https://www.docker.com)来启动一个Neo4j服务：

```shell
docker run \
    -p 7474:7474 -p 7687:7687 \
    --name neo4j-neosemantics \
    neo4j:5.5.0
```

1. 安装插件以支持RDF

```shell
docker exec -it neo4j-neosemantics bash
cd plugins/
wget https://github.com/neo4j-labs/neosemantics/releases/download/5.5.0.0/neosemantics-5.5.0.0.jar
```

2. 配置插件

编辑`conf/neo4j.conf`， 追加配置`dbms.unmanaged_extension_classes=n10s.endpoint=/rdf`。

配置完成后重启Neo4j

```shell
docker restart neo4j-neosemantics
```

Open Neo4j Browser: <http://localhost:7474/browser/> 初始账号：neo4j/neo4j

3. 配置Graph

在Neo4j browser输入框分别执行以下命令：

{% tabs %}
{% tab title="cypher-shell" %}

```cypher
CALL n10s.graphconfig.init();

CREATE CONSTRAINT n10s_unique_uri FOR (r:Resource) REQUIRE r.uri IS UNIQUE;

CALL n10s.graphconfig.init( {  handleMultival: "ARRAY" })

CALL n10s.nsprefixes.add("e", "http://relationlabs.ai/entity/");
CALL n10s.nsprefixes.add("p", "http://relationlabs.ai/property/");
```

{% endtab %}
{% endtabs %}

4. 导入数据

在Neo4j browser中执行以导入数据：

{% tabs %}
{% tab title="cypher-shell" %}

```cypher
CALL n10s.rdf.import.inline("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#>

:Soul_0x0109c8ee3151bde7b6b5d9f37e9d2c4bc16930fe a :Soul;
    p:name \"Alice\" .

:Soul_0x6247123ec0fe0d25feb811e3c4d4a760c1f2e63e a :Soul;
    p:name \"Bob\" .

:Soul_0x0109c8ee3151bde7b6b5d9f37e9d2c4bc16930fe p:following :Soul_0x6247123ec0fe0d25feb811e3c4d4a760c1f2e63e .","Turtle");
```

{% endtab %}
{% endtabs %}

5. 查询

在Neo4j browser中查询：

{% tabs %}
{% tab title="cypher-shell" %}

```cypher
MATCH (ss:Resource {p__name: ["Alice"]})-[:p__following]->(oo) RETURN ss, oo
```

{% endtab %}
{% endtabs %}

<figure><img src="https://3668324987-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FdqevFF76s9Kq7JWAPlD3%2Fuploads%2Fgit-blob-af6c5c8489b40e97e02751aaf80beb10fd205de4%2Findexer-neo4j.png?alt=media" alt=""><figcaption><p>图 7-10 使用Neo4j</p></figcaption></figure>
