OracleのRDFグラフ機能を使ってみる

## 1. 本記事について
RDFはLOD（Linked Open Data）などの取り組みを実現するデータフォーマットとして
注目が高まっています。
本記事ではOracleのRDFグラフ機能について環境セットアップからデータロード、
クエリ実行までの手順を記載します。（使ってみたい方向け）

そもそもRDFとは何なのか？といった内容は含みません。
※ ググれば色々出てきます。Oracleによる説明だと古いですが以下のものがあります。
[RDF 超入門](https://www.slideshare.net/oracle4engineer/rdf-semantic-graph-intro "RDF 超入門")

## 2. 構築する環境について
本手順では以下の環境をOracle Cloud上へ構築します。
クラウド環境を無償で使えるAlways Freeもありますので適宜活用ください。

図に記載のRDF ServerはOracle Database内のRDFグラフに対する管理および
クエリ実行のためのインターフェースを提供するWebアプリケーションです。
warファイルで提供されており、Tomcat 9系もしくはWeblogic Serverでデプロイが可能です。
※Oracle Databaseは12cまでは同じ手順で問題ないはず...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/99d9814c-85d5-26e8-c4b9-24a85c7f8361.png)

今回は金額的なハードルの低さからTomcat上に構築します。
ちなみにWeblogicの場合はmarketplaceからRDF Server構築済のVMをデプロイできます。
[Oracle RDF Graph Server and Query UI](https://cloudmarketplace.oracle.com/marketplace/ja_JP/listing/80709794 "Oracle RDF Graph Server and Query UI")

## 3. 構築手順
本手順ではRDFのセットアップ部分にフォーカスするため、クラウド上への
ネットワークリソースの作成やComputeインスタンスの作成部分は割愛します。
冒頭の図のようにComputeインスタンスとOracle Databaseが疎通できるよう
構成されていれば問題ありません。

### DBユーザー作成
・DBサーバーへログインします。
・RDF環境をセットアップするDBへSYSで接続します。

```shell
$ sqlplus sys/<パスワード>@<DBホスト名>:1521/<DBサービス名> as sysdba
```
・RDF用DBユーザーの作成と必要な権限を付与します。

```SQL
create user RDFUSER identified by <パスワード>;

grant connect, resource, unlimited tablespace to RDFUSER;
grant create any view to RDFUSER;
grant create any trigger to RDFUSER;
grant execute any procedure to RDFUSER;
grant administer database trigger to RDFUSER;
```

### JDKインストール
・RDF Serverを構築するComputeインスタンスへログインします。
・以下からJDK 17のRPMパッケージをダウンロードし、サーバー上の任意のディレクトリへ配置しておきます。
※ 2021/9～ Oracle JDKが無償で利用可能になりました。
[JDK Download](https://www.oracle.com/java/technologies/downloads/ "JDK Download")

```shell
$ sudo su -
$ sudo rpm -ivh /hoge/jdk-17_linux-x64_bin.rpm
$ java -version
java version "17.0.1" 2021-10-19 LTS
Java(TM) SE Runtime Environment (build 17.0.1+12-LTS-39)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.1+12-LTS-39, mixed mode, sharing)
```

### Tomcat構築
・Tomcat用のOSユーザーを作成します。
・Tomcatをダウンロードして解凍します。

```shell
$ sudo useradd tomcat
$ sudo su - tomcat
$ wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.56/bin/apache-tomcat-9.0.56.zip
$ unzip apache-tomcat-9.0.56.zip
```
・Tomcatの設定ファイルにDBに接続するためのデータソース定義を追記します。

```shell
$ vi apache-tomcat-9.0.56/conf/server.xml
```

```xml
<GlobalNamingResources>
    <!-- 以下を追記 -->
    <Resource name="jdbc/rdf" auth="Container" global="jdbc/rdf"
              type="javax.sql.DataSource" driverClassName="oracle.jdbc.driver.OracleDriver"
              url="jdbc:oracle:thin:@<DBホスト名>:1521/<DBサービス名>"
              username="RDFUSER" password="<パスワード>" maxTotal="10" maxIdle="10"
              maxWaitMillis="-1"/>
</GlobalNamingResources>
```
・JNDIリソース定義を追記します。

```shell
$ vi apache-tomcat-9.0.56/conf/context.xml
```
```xml
<Context>
    <!-- 以下を追記 -->
    <ResourceLink name="jdbc/rdf"
                  global="jdbc/rdf"
                  auth="Container"
                  type="javax.sql.DataSource" />
</Context>
```

・RDF Serverの認証ログインに使用するユーザーを追記します。

```shell
$ vi apache-tomcat-9.0.56/conf/tomcat-users.xml
```

```xml
<tomcat-users xmlns="http://tomcat.apache.org/xml"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
              version="1.0">
    <!-- 以下を追記 -->
    <role rolename="rdf-admin-user"/>
    <role rolename="rdf-read-user"/>
    <role rolename="rdf-readwrite-user"/>
    <user password="<パスワード>" roles="manager-script,admin,rdf-admin-user" username="admin"/>
</tomcat-users>
```

### RDF Serverデプロイ
・以下からRDF Serverのwarファイルを含む"Oracle Property Graph and Oracle RDF Graph Webapps"を選択し、ダウンロードします。
[Oracle Graph Server and Client Downloads](https://cloudmarketplace.oracle.com/marketplace/ja_JP/listing/80709794 "Oracle Graph Server and Client Downloads")
・zipファイル内の"orardf-21.4.0.war"をTomcatのwebapps配下へ配置します。

```shell
$ sudo chown tomcat:tomcat /hoge/orardf-21.4.0.war
$ mv /hoge/orardf-21.4.0.war apache-tomcat-9.0.56/webapps/orardf.war
```
・Tomcatを起動します。

```shell
chmod 744 apache-tomcat-9.0.56/bin/*.sh
sh apache-tomcat-9.0.56/bin/startup.sh
```
・firewallのポートを開けておきます。

```shell
$ sudo firewall-cmd --add-port=8080/tcp --zone=public --permanent
$ sudo firewall-cmd --reload
$ sudo firewall-cmd --list-all
```
・RDF Serverのブラウザインターフェースへアクセスします。
http://<ホスト>:8080/orardf
・"tomcat-users.xml"に記載したadmin/<パスワード>でログインします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/beaef56e-788b-da0e-a567-955e8ddbb030.png)

### データソース作成
・"Data Source"タブから"Create"を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/e6134c03-5eea-37b2-d058-307f1835ed18.png)
・"Container"を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/dbb971e7-b45f-7060-db8e-70c9ac273d29.png)
・Nameに任意の名称を入れ、JNDI NameはタブからTomcatに定義したものを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/70969e2d-dec9-1124-6d1d-ac8934015b6f.png)

## 4. RDF関連オブジェクト作成
Oracle Databaseでは以下のような構造でRDFグラフデータが管理されます。
セマンティック・ネットワークはRDFグラフに関連する一連のテーブルやビューなどの
オブジェクトを保持する大枠のイメージです。
仮想モデルとモデルの関係はDatabaseにおけるテーブルとビューの関係に近いです。
仮想モデルの定義（どのモデルを含むか）はオンラインで変更ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/d63c90ae-7b71-afd5-4606-6a9a7053a1f7.png)

今回はRDF Serverから上記のオブジェクト群を作成していきます。
### セマンティック・ネットワークの作成
・"Data"タブから"RDF Network"の"+"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/bc4af202-8c89-d067-cb6f-8a85962e9732.png)
・"Network name"に任意の名称を入れ、セマンティック・ネットワークを作成する表領域を選択します。
・"OK"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/18d1ece4-2835-357f-f46d-3fcf5b0830c1.png)

### モデルの作成
・"RDF network"タブで作成したセマンティック・ネットワークを選択します。
・"Regular Models"を右クリックし、"Create"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/76aabff1-722d-70df-fde5-6aabcbcbd47c.png)
・任意のモデル名と表領域を入力します。
・"OK"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/d0a03a45-cd9f-a387-18b8-e755d7d2a002.png)

### 仮想モデルの作成
・"Virtual Models"をクリックし、"Create"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/4c7b5469-4955-7292-9425-9560e831f50c.png)
・任意の仮想モデル名を入力し、"Next"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/33844a4c-8ae0-91eb-b38c-c6cf58c3ab36.png)
・仮想モデルに含めるモデルとして、先ほど作成した"MODEL01"をチェックします。
・"Next"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/f342c1e9-f9c0-cd43-4534-dae7c2aec0af.png)
・こちらはRDFの推論と呼ばれる機能で使われるオブジェクトですが、今回は選択しません。
・"Next"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/d577830e-6be1-9aeb-7277-a16c0daeece8.png)
・"OK"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/94d54212-5ea8-5997-03c4-5d90eaf670cf.png)

1つのモデルと、それを含む仮想モデルが作成できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/5a510368-4532-f9bd-c172-fc6fcbe8f991.png)

上記のモデルの作成などは以前はDB側で以下のプロシージャ群を実行する必要があったため、
GUIベースで実行できるようになって敷居がかなり低くなりました。
[SEM_APIS.CREATE_SEM_NETWORK](https://docs.oracle.com/en/database/oracle/oracle-database/21/rdfrm/SEM_APIS-reference.html#GUID-7E0EAF3F-C5A5-4E02-8736-8280ABA35214 "SEM_APIS.CREATE_SEM_NETWORK")
[SEM_APIS.CREATE_VIRTUAL_MODEL](https://docs.oracle.com/en/database/oracle/oracle-database/21/rdfrm/SEM_APIS-reference.html#GUID-CAFA0FE5-3A96-4DBD-A9EC-F3E0466807DB "SEM_APIS.CREATE_VIRTUAL_MODEL")
[SEM_APIS.CREATE_SEM_MODEL](https://docs.oracle.com/en/database/oracle/oracle-database/21/rdfrm/SEM_APIS-reference.html#GUID-1DB639F4-9A60-47CE-B1FC-E4B805D86F2F "SEM_APIS.CREATE_SEM_MODEL")

## 5. RDFグラフデータのロード
### ロードするデータについて
RDF形式の様々なデータが公開されている以下のサイトから
日本の駅ビル一覧のデータ(Turtleファイル形式)をダウンロードします。
[日本の駅ビル](http://linkdata.org/work/rdf1s7634i "日本の駅ビル")
※ ファイル先頭あたりの<>に続くcreativecommonsのトリプルが入っていると
パースエラーになるため、該当部分だけ削除してロードください。

### ステージング表の作成
Turtle等のRDF形式のファイルをOracle Database内のモデルへアップロードする場合、
ステージング表と呼ばれるテーブルを経由する必要があります。
こちらはOracle Database側で実行する必要があります。
・ステージング表を作成します。

```sql
SQL> sho user
USER is "RDFUSER"

SQL> create table STG_TABLE01 (
     RDF$STC_sub varchar2(4000) not null,
     RDF$STC_pred varchar2(4000) not null,
     RDF$STC_obj varchar2(4000) not null
     RDF$STC_graph varchar2(4000));
```

### ファイルのアップロード
RDF Serverの管理画面へ戻り、Turtleファイルのアップロードを行います。
・"Import"タブから"Upload data"を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/6908e17d-403c-c5c7-d577-f97e6d1c1e69.png)

・↑矢印のあたりをクリックするとWindows Explorerが起動するため、ダウンロードしたTurtleファイルをアップロードします。
・"Next"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/726f18ff-8449-68df-7753-68c274989042.png)
・"Staging table"で先ほど作成したステージング表を選択します。
・"Next"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/ad8cf37b-e5a4-b7e4-8cc7-6fe69bfa35bc.png)
・"OK"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/5f95de3b-943e-2581-646c-1f89429ce102.png)

### モデルへロード
ステージング表からモデルへデータをロードします。
・"Import"タブ中央の"Bulk load data"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/b983f423-181b-dc5b-7ccd-e3d674bec521.png)

・ロード先のモデル名とロード元のステージング表を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/aeaa8404-cc77-0b2a-3dee-3d8db51c9b77.png)
・"Degree of parallelism"でロード処理の並列度を指定します。環境に合わせて設定ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/415a9997-e3f4-0a7d-af3d-876787db205c.png)
・標準ログ出力メッセージの編集画面です。そのままで"Next"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/ac532e3f-5207-7e56-4a2a-ccb94ced97ea.png)
・"OK"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/cec2eb46-8b27-2f11-db3c-9817d510bf66.png)

"Successfully Completed"と表示されていればロード完了です。

## 6. SPARQLクエリ実行
ここからロードしたデータに対してクエリを実行します。
RDFグラフへの問い合わせはSPARQLと呼ばれるSQLに似たクエリ言語を使用します。
[SPARQL 1.1 Query Language](https://www.w3.org/TR/sparql11-query/ "SPARQL 1.1 Query Language")

・仮想モデル"VMODEL01"をダブルクリックします。
・SPARQLエディタのタブが表示されますので、任意のグラフパターンを500件取得するデフォルトのSPARQLのまま"Execute"を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/81d0f5d6-a882-0322-61e5-63d3a99dfc89.png)

・結果セットが主語(S)-述語(P)-目的語(O)のトリプルの形で表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/df2da246-c8bd-029c-fc06-fd189e83d781.png)

・"Show Graph"を押すと結果をグラフの形で可視化することもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217525/f043f0c2-3dd1-f641-8343-f142909bf971.png)

## 7. 参考
[RDF Graph Server and Query UI](https://docs.oracle.com/en/database/oracle/oracle-database/21/rdfrm/rdf-graph-server-and-query-ui.html "RDF Graph Server and Query UI")