Amazon Neptune を構築してみた

# はじめに

AWS では、「Purpose-built databases」と表現される、利用するサービスのワークロードに合わせて最適なデータベースを選択する考え方があります。実現したいシステムをデータ構造に落とし込み、最適なパフォーマンスでお客様にサービスを提供するために、様々な用途に合わせたデータベースが選べます。

その中で今回はグラフデータベースである Amazon Neptune を取り上げていきます。

グラフデータベースが利用できるわかりやすい例として、次のものがあります。

![image-20220305163819569.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/f1b07758-f21c-4540-06f8-aa6d71668acf.png)

URL : https://pages.awscloud.com/rs/112-TZM-766/images/2_20211111_Neptune_shoukai.pdf



ソーシャルネットワークを表現しており、「ユーザー」「記事」「いいね！」「コメント」といった登場人物がいます。A さんの友達がコメントしている記事を いいね！している人など、複雑な多対多の関係性となっています。こういった複雑な関係性でなおかつ大量にデータがあるとき、一般的な RDBMS だとパフォーマンスの問題がある可能性があります。そこで、多対多の関係性の表現に強い Amazon Neptune を利用することで、パフォーマンスをよくデータ提供ができます。



今回の記事では、Neptune を構築してみて、どういった使い方が出来るものなのか確認していきましょう。AWS Document の次の URL を参考に進めていきます。

Getting Started : https://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/neptune-setup.html



# Neptune を作成

Neptune のページを開き、Create Database を押します

![image-20220305162014295.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3052f507-d3be-e53c-8c1b-eb2b56705d71.png)



各種パラメータを指定します

- Neptune のバージョンを指定
- Cluster 名を指定

![image-20220305162510080.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/2ff19e61-9ea1-67b3-f500-5d310aa0dabf.png)



各種パラメータを指定します

- 本番環境向け
- Instance Size
- 異なる AZ に Read Replica を作成する、Multi-AZ 構成

![image-20220305162725729.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/ff5a9949-9cd2-4b99-8fbb-c96d0c310f18.png)



各種パラメータを指定します

- VPC, Subnet Group, Security Group を指定
- Neptune の Port を指定

![image-20220305163223993.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/2b7ddb33-59a9-769a-fc92-b8f099910af6.png)



他の各種設定はデフォルトのままで進めます。RDS の設定画面に似ていますね。

![image-20220305163405488.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/da9ea60a-8edf-9df2-39be-10228ee092af.png)



Create Database を選択します

![image-20220305163518074.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/af17b0bc-af68-ae7c-7627-cc0512eaf06d.png)



2 つの AZ にまたがって、2つの Neptune インスタンスが Creating となりました

![image-20220305163447176.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/d72c2a6d-1c9c-393d-f5c5-85b828b4ead5.png)



一定時間後、Available と変わりました。Writer インスタンス1個と、Reader インスタンス 1 個が作成出来ました。

![image-20220305164929290.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/3e7b2395-98cf-f947-dd66-902d1c2322cc.png)



クラスタの詳細を開くと、Writer Endpoint, Reader Endpoint が確認できます。

![image-20220305165056185.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/5a390a24-8b15-78b9-2e24-85fcb055e47c.png)



# curl で SPARQL

Neptune クラスタは VPC 内に作成していますので、VPC 内に存在する EC2 インスタンスからアクセスを行います。

EC2 インスタンスで以下の curl コマンドを実行し、データを INSERT します。

RDF では、主語-述語-目的語を表現するためのトリプルと呼ばれる概念があり、これをINSERT します。 `<https://test.com/s> <https://test.com/p> <https://test.com/o>` が、主語-述語-目的語の部分です。

```
curl -X POST \
--data-binary 'update=INSERT DATA { <https://test.com/s> <https://test.com/p> <https://test.com/o> . }' \
https://neptune-test.cluster-chuxmuzmrpgx.ap-northeast-1.neptune.amazonaws.com:8182/sparql
```



実行例

- JSON でレスポンスが返ってきている
- 処理に掛かった時間も教えてくれる

```
> curl -X POST \
      --data-binary 'update=INSERT DATA { <https://test.com/s> <https://test.com/p> <https://test.com/o> . }' \
      https://neptune-test.cluster-chuxmuzmrpgx.ap-northeast-1.neptune.amazonaws.com:8182/sparql
[
{
    "type" : "UpdateEvent",
    "totalElapsedMillis" : 144,
    "elapsedMillis" : 6,
    "connFlush" : 0,
    "batchResolve" : 0,
    "whereClause" : 0,
    "deleteClause" : 0,
    "insertClause" : 0
},
{
    "type" : "Commit",
    "totalElapsedMillis" : 206
}
]⏎
```



データの INSERT が無事に終わったので、次にデータの取得を行っていきます。

- グラフ内のトリプル(主語-述語-目的語)

```
curl -X POST \
--data-binary 'query=select ?s ?p ?o where {?s ?p ?o} limit 10' \
https://neptune-test.cluster-chuxmuzmrpgx.ap-northeast-1.neptune.amazonaws.com:8182/sparql
```



実行例

```
> curl -X POST \
      --data-binary 'query=select ?s ?p ?o where {?s ?p ?o} limit 10' \
      https://neptune-test.cluster-chuxmuzmrpgx.ap-northeast-1.neptune.amazonaws.com:8182/sparql
{
  "head" : {
    "vars" : [ "s", "p", "o" ]
  },
  "results" : {
    "bindings" : [ {
      "s" : {
        "type" : "uri",
        "value" : "https://test.com/s"
      },
      "p" : {
        "type" : "uri",
        "value" : "https://test.com/p"
      },
      "o" : {
        "type" : "uri",
        "value" : "https://test.com/o"
      }
    } ]
  }
}
```



# Jupyter Notebook を作成する

curl を使った SPARQL アクセスをしましたが、毎回 curl でコマンドを打っていくのは大変です。そこで、Neptune で提供されている Jupyter Notebook を便利に利用できます。この Notebook の中には、Neptune Workbench と呼ばれる、クエリーと可視化が出来るツールが含まれており、開発作業に便利に活用できます。

Neptune のメニューから、Create Notebook を選びます

![image-20220305194744742.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/1f2c37e0-7119-9dbd-b413-596715e60ceb.png)



パラメータを入力します

- 連携したい Neptune クラスタ
- Notebook のインスタンスタイプ
- など

![image-20220305195018350.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/e7971ebc-33c4-0344-f86d-43eee77ad956.png)



以下のパラメータをいれて、Create を押します。

- Notebook Instance の Subnet や Security Group を選択

![image-20220305195046040.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/90710cb3-3f87-c707-18f1-62aaf8d52f72.png)



Notebook Instance が作成され、pending となりました

![image-20220305195058353.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/b374561e-0fcb-2a8d-bc17-755d2b858c21.png)



一定時間後、Ready になったあとに、Open notebook を押します。

![image-20220305200925590.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/73f6e5ad-9f5b-a7dd-4165-f7a7a8ac3f57.png)



Jupyter Notebook が開きました

![image-20220305200951484.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/96fad239-5ab7-b9f8-f5a8-4851a2a89d5b.png)





Neptune の Notebook には、多くのサンプルがあります

![image-20220305201045728.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/489de900-ff08-2ef4-fe83-d4ff99d276bd.png)



# Neptune Workbench で SPARQL クエリー

Notebook 上で、新規の Notebook を作成しましょう。New から Python 3 を選択します。

![image-20220305203717910.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/c7e707d8-e1ba-c307-9eb8-d555974492b4.png)



新たな Notebook が作成されました。

![image-20220305203817241.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/ea28d53e-8b89-e1bd-ce74-b976625f0ca4.png)



新たな Notebook 上で、SPARQL を簡単に実行できるようになっています。`%%sparql` を頭に付けることで、それ以降は SPARQL のクエリーを記述出来、簡単に Jupyter Notebook 上でクエリー実行できます。

今回は、curl で既に入れているデータに対して、取得を行ってみましょう。次の文字列を入れて、Run で実行します。

```
%%sparql

SELECT ?s ?p ?o WHERE {?s ?p ?o} LIMIT 10
```

![image-20220305204110844.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/60ce372b-2de3-ce40-dd36-a9da227be3e6.png)



実行されました。SPARQL の実行結果が Table で見えています。curl の時と比べて記述量が SPARQL 部分となっており、シンプルにできていることがわかります。Graph も押してみましょう。

![image-20220305204213584.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/5dbd6f89-130e-d1de-f0f3-4f1b3db7951f.png)



以下のように、クエリーに紐づくデータを可視化できています。今回は、意味のないデータであまり感動がありませんが、実際のワークロードでは便利に関係性を可視化で把握できて便利そうですね。

![image-20220305204256191.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1002774/eb85b1fe-d6f9-3700-3094-cc5d5b952575.png)



# まとめ

今回の記事では、次の2点を整理しました

- Neptune クラスタの構築方法
- SPARQL を利用したアクセス方法は、curl を使ったアクセス、および、Jupyter Notebook で Neptune Workbench を使ったアクセス



# メモ : データの作成と削除のクエリー

Insert

```
%%sparql

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



Delete

```
%%sparql

DELETE DATA { <https://test.com/s> <https://test.com/p> <https://test.com/o> . }
```





# 参考URL

https://docs.aws.amazon.com/ja_jp/neptune/latest/userguide/neptune-setup.html