Graph Server コンテナ作成（23.4）

![graph-podman-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/7fd5f42c-08ba-26de-26d1-175d9192fa5a.png)

（以下の手順は、Graph Server 23.4.0 および Oracle Database 23.3.0 でテストしています。）

以前の記事「[SQL 2023 のグラフ構文を試す](https://qiita.com/ryotayamanaka/items/1dbbe3269e5101f3cd33)」では Oracle Database 23c をコンテナ上に起動し、これをグラフ・データベースとして使う方法をご説明しました。今回はここに Graph Server のコンテナを追加する方法をご説明します。Graph Server はグラフをメモリ上に効率的に展開することで、グラフを辿る処理やグラフアルゴリズムを高速化することができます。

次のアーキテクチャ図で、既に Oracle Database 23c のコンテナは構築できている前提で、これから Graph Server のコンテナを追加します。

![Picture1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/4eb92260-4b77-0b7d-c712-8f3f0d5d4365.png)

## Docker/Podman の準備

Oracle Graph Server は RedHat Linux 7/8 および Oracle Linux 7/8 で動作がサポートされています。

- [14.2.1.1 Prerequisites for Installing Oracle Graph Server](https://docs.oracle.com/en/database/oracle/property-graph/23.4/spgdg/using-rpm-installation.html#GUID-D617B745-AC9F-431E-A861-B45374392162)

そこで、この記事ではコンテナのホストも RedHat 系 Linux であることを想定して、Podman で立ち上げた Oracle Linux 8　のコンテナ上に Graph Server を構築します。

podman と一緒に podman-docker をインストールしておくと `docker` コマンドを `podman` コマンドのエイリアスとして使うことができるので、今回はこのパッケージを用いて、以下では `docker` コマンドで表記することにします。

```
sudo yum update
sudo yum install -y podman podman-docker
```

この記事は Graph Server の動作を手軽に試す場合を想定していますので、本番利用で各コンテナ環境がサポートされるかどうかについては、Oracle にお問い合わせください。

## Oracle Database の準備

ここでは Database 23c を使います。Database 23c のコンテナを起動する手順は次の記事に書かれています。Docker と Podman はコマンドを同様に使えるので適宜読み替えてください。

- [SQL 2023 のグラフ構文を試す](https://qiita.com/ryotayamanaka/items/1dbbe3269e5101f3cd33)

また、Graph Server を使用するためには追加の権限が必要なため、使用するデータベースユーザー（graph_user）に対して graph_developer ロールを付与しておきます。

```
docker exec -it database-23c sqlplus sys/password123@freepdb1 as sysdba
```

```
GRANT graph_developer TO graphuser;
GRANT pgx_session_add_published_graph TO graphuser;
```

## Oracle Graph と JDK のダウンロード

Graph Server が含まれる RPM パッケージと Graph Client が含まれる ZIP ファイルを [こちらのサイト](https://www.oracle.com/database/technologies/spatialandgraph/property-graph-features/graph-server-and-client/graph-server-and-client-downloads.html) からダウンロードします。いずれかのパッケージを選択すると、Oracle アカウントでのログインが要求されて、Oracle Software Delivery Cloud というところに飛ばされます。

![Screenshot 2023-11-07 at 12.25.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/99b0573f-6ae6-0993-c6e6-5e52a26c97e3.png)

今回必要になる「Oracle Graph Server」にチェックを入れてダウンロードします。

![Screenshot 2023-11-07 at 12.27.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/075863ed-3a5b-6505-ff96-10fd8de01963.png)

Oracle Download Manager なるものが現れてダウンロードを開始します。

![Screenshot 2023-11-07 at 12.28.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/535c4fd0-59c0-f8d5-d2bf-78ab7dcb566c.png)

加えて、JDK 11（Linux - x64 RPM Package）を[こちらのサイト](https://www.oracle.com/java/technologies/downloads/#java11)からダウンロードしておきます。こちらも個人用途や開発用途であればライセンス費用がかからないので、安心してお使いいただけます。

## Graph Server イメージのビルド

ここでダウンロードしたこれらの RPM パッケージと次に作成する Dockerfile（または Containerfile）を同じディレクトリに配置します。

- oracle-graph-23.4.0.x86_64.rpm
- jdk-11.0.21_linux-x64_bin.rpm

```
vi Dockerfile
```

```Dockerfile:Dockerfile
FROM oraclelinux:8

ARG VERSION_JDK
ARG VERSION_OPG
ARG JDBC_URL

COPY ./jdk-${VERSION_JDK}_linux-x64_bin.rpm /tmp
COPY ./oracle-graph-${VERSION_OPG}.x86_64.rpm /tmp

RUN yum install -y unzip numactl gcc libgfortran python3.8 \
 && yum clean all \
 && rm -rf /var/cache/yum/* \
 && rpm -ivh /tmp/jdk-${VERSION_JDK}_linux-x64_bin.rpm \
 && rpm -ivh /tmp/oracle-graph-${VERSION_OPG}.x86_64.rpm \
 && rm -f /usr/bin/python3 /usr/bin/pip3 \
 && ln /usr/bin/python3.8 /usr/bin/python3 \
 && ln /usr/bin/pip3.8 /usr/bin/pip3 \
 && pip3 install oracle-graph-client==23.4.0

ENV JAVA_HOME=/usr/lib/jvm/jdk-11-oracle-x64
ENV PATH=$PATH:/opt/oracle/graph/bin
ENV SSL_CERT_FILE=/etc/oracle/graph/ca_certificate.pem
ENV PGX_SERVER_KEYSTORE_PASSWORD=changeit

RUN keytool -importkeystore \
    -srckeystore /etc/oracle/graph/server_keystore.jks \
    -destkeystore $JAVA_HOME/lib/security/cacerts \
    -deststorepass changeit \
    -srcstorepass changeit \
    -noprompt

RUN sed -i "s|<REPLACE-WITH-DATABASE-URL-TO-USE-FOR-AUTHENTICATION>|${JDBC_URL}|" /etc/oracle/graph/pgx.conf

EXPOSE 7007

WORKDIR /opt/oracle/graph/bin

CMD ["sh", "/opt/oracle/graph/pgx/bin/start-server"]
```

イメージをビルドします。JDK のバージョンはダウンロードしたものに置き換えてください。ここでコンテナのホストを Podman では `host.containers.internal`（Docker では `host.docker.internal`）で参照しています。

```
docker build . \
-f Dockerfile \
--tag graph-server:23.4.0 \
--build-arg VERSION_OPG=23.4.0 \
--build-arg VERSION_JDK=11.0.21 \
--build-arg JDBC_URL=jdbc:oracle:thin:@host.containers.internal:1521/freepdb1
```

## Graph Server コンテナの起動

イメージが完成したらコンテナを起動します。

```
docker run \
--name graph-server \
--publish 7007:7007 \
--env JAVA_TOOL_OPTIONS="-Xms1G -Xmx2G" \
--detach \
graph-server:23.4.0
```

Python シェルを起動します。

```
docker exec -it graph-server python3
```

データベースユーザー graphuser で Graph Server にログインできることを確認します。

```python
from opg4py import graph_server
from pypgx import setloglevel
setloglevel("ROOT", "WARN")
base_url = "https://localhost:7007"
username = "graphuser"
password = "password123"
instance = graph_server.get_instance(base_url, username, password)
session = instance.create_session("test")
```

既にデータベース上に作成してあるグラフ（BANK_GRAPH）を Graph Server に読み込みます。

```python
graph = session.read_graph_by_name('BANK_GRAPH', 'pg_sql')
print(graph)
```
```
PgxGraph(name: BANK_GRAPH, v: 360, e: 6230, directed: True, memory(Mb): 0)
```

Graph Server のメモリ上のグラフに対してクエリを実行します。

```python
session.query_pgql("""
SELECT * FROM GRAPH_TABLE (bank_graph
  MATCH (c IS customer)-[e IS owns]->(a IS account)
  WHERE c.cst_id = 10
  COLUMNS (c.cst_id, c.first_name, a.acc_id)
)
""").print()
```
```
+------------------------------+
| cst_id | first_name | acc_id |
+------------------------------+
| 10.0   | Laura      | 10.0   |
| 10.0   | Laura      | 90.0   |
+------------------------------+
```

このグラフに異なるセッション（ここでは次項の可視化アプリケーション）からアクセスできるようにするため、グラフを公開（publish）しておきます。

```python
graph.publish()
```

## クエリ実行結果の可視化

ウェブ・ブラウザから Graph Visualization にログインします。

- https://localhost:7007/ui/

自己署名証明書が使われているため、セキュリティ警告が表示されますが、以下のように進みます。

- Chrome: Advanced > Proceed to <ip-address> (unsafe)
- Firefox: Advanced > Accept the Risk and continue

データベース・ユーザーでログインします。

![Screenshot 2023-11-13 at 15.01.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/0a252950-b983-4847-4770-4b50931f890f.png)

ログインできたら「Graph Server」タブが選択された状態で先程と同じクエリを実行してみます。

```sql
SELECT * FROM GRAPH_TABLE (bank_graph
  MATCH (c IS customer)-[e IS owns]->(a IS account)
  WHERE c.cst_id = 10
  COLUMNS (c.cst_id, c.first_name, a.acc_id)
)
```

結果がグラフ（ただしノードだけ）として表示されます。デザインの設定ファイル [settings.json](https://raw.githubusercontent.com/ryotayamanaka/oracle-graph/main/bank-transaction/settings.json)（右クリックで保存）をアップロードすると色やアイコンが設定されます。

![687e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/c43b2c3d-c353-1125-9d2e-5c1ba839ba31.png)


「Table mode」に切り替えるとクエリ結果が表で表示されます。

![687706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/e11b4f39-da1b-3688-ae40-a1480eaecc73.png)

エッジのプロパティを返すようにするとエッジも可視化することができます。

```sql
SELECT * FROM GRAPH_TABLE (bank_graph
  MATCH (c IS customer)-[e IS owns]->(a IS account)
  WHERE c.cst_id = 10
  COLUMNS (c.cst_id, e.cst_id AS e, a.acc_id)
)
```

![Screenshot 2023-11-07 at 18.57.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/cb5fb3ef-6ce2-f8c0-8955-4d283147df3c.png)

以上、Graph Server を作成することができました。この環境を使用して、グラフ・データベースの様々なユースケースを議論していければと思います。

## 補足

後々 JDBC URL を変更する必要がある場合には、コンソールからコンテナに接続し、pgx.conf 内の JDBC URL を編集します。その後、ホストに戻り、Graph Server コンテナを再起動します。

```
$ docker exec -it graph-server /bin/bash
# vi /etc/oracle/graph/pgx.conf

  "jdbc_url": "jdbc:oracle:thin:@host.docker.internal:1521/xepdb1",

# exit
$ docker restart graph-server
$ docker logs -f graph-server
```

Graph Server で実行可能なクエリは SQL ではなく PGQL です。PGQL は SQL:2023 の GRAPH_TABLE を使うことができる一方で、以下のような従来の記法も使うことができます。

```sql
SELECT *
FROM MATCH (c:customer)-[e:owns]->(a:account) ON bank_graph
WHERE c.cst_id = 10
```

![Screenshot 2023-11-09 at 17.58.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/556e85b0-06f2-3348-3259-b2fd0d84a5c0.png)

また、タブを「Database (SQL Property Graph)」に切り替えることによりデータベース上のグラフにクエリを実行することができます。この場合も VERTEX_ID / EDGE_ID を返すことでグラフを可視化することができます。

```sql
SELECT * FROM GRAPH_TABLE (bank_graph
  MATCH (c IS customer)-[e IS owns]->(a IS account)
  WHERE c.cst_id = 10
  COLUMNS (VERTEX_ID(c) AS id_c, EDGE_ID(e) AS id_e, VERTEX_ID(a) AS id_a)
)
```

![Screenshot 2023-11-07 at 15.53.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/fa2df27c-64ca-a652-73d7-4590f5c86c48.png)