Always Free 環境で SPARQL エンドポイントを構築！（WebLogic 編）

![cristian-escobar-abkEAOjnY0s-unsplash_mod.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/6ed903f3-5ba2-0323-8640-b057016f4bfa.jpeg)
この記事では Oracle Cloud の Always Free Cloud Services を利用して SPARQL エンドポイントを構築する方法を紹介します。こちらは期間の制限なく無料で使用できるサービスで、1 アカウントあたり 2 つのデータベース・インスタンスと 2 つの VM が含まれています。

LOD（Linked Open Data）の公開のためには、そのデータを含む SPARQL エンドポイントが常にアクセス可能になっていることが望ましいのですが、SPARQL エンドポイントとそのバックエンドの RDF ストアをウェブ上で運用するには通常なんらかのコストがかかってしまいます。しかし、Oracle Cloud を使えば無料でこれを運用（＊）することができます！

＊ ただし、その用途は**個人利用やテスト目的**に限られることにご注意ください。Always Free Cloud Services は [SLA とサポートの対象外](https://www.oracle.com/jp/cloud/free/faq.html)であり、エンドポイント管理サーバーが使用している WebLogic には [OTN ライセンス](https://faq.oracle.co.jp/app/answers/detail/a_id/4929/kw/otn)が適用されますので、商用本番利用においては有償のサービスをご検討ください。

ここではエンドポイント管理サーバーを構築して SPARQL クエリを実行するまでの、最も簡略化した手順を記載します。その他に考慮すべき点についてはこの記事の末尾に参考として記載します。

### 準備

まず、以下を用意しておきます。パスワードは同じものを使用することも可能です。

- Oracle Cloud のアカウント
- SSH key pair (private と public key)
- 3 つのパスワード
  - `<password_1>`: DB ログイン用（`ADMIN` user）
  - `<password_2>`: RDF Server ログイン用（`admin` user）
  - `<password_3>`: DB 接続 Wallet 用

### データベースの作成

次のように画面を進み、データベースを作成します。このデータベースは Autonomous Database と呼ばれるフル・マネージド・サービスです。

```
Oracle Cloud console
  > Oracle Database
    > Autonomous Database
      > Create Autonomous Database
```

- Configure the database
  - Database name: `<db_name>` （ここでは `ADB1` とします）
  - Workload type: `トランザクション処理`
  - Deployment type: `共有インフラストラクチャ`
  - Database version: `19c` or `21c` 
  - Password: `<password_1>`

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/3f06a64f-48dd-5ef9-8ce5-59aae5b6f159.png)

## ネットワークの作成

次のように画面を進み、SPARQL エンドポイント用のネットワークを作成します。Oracle Cloud のネットワークは詳細に設定が可能ですが、ウィザードを使うことで基本的な構成を簡単に作成できるため、今回はそれを使用します。

```
Oracle Cloud console
  > Networking
    > Virtual Cloud Networks
      > Start VCN Wizard
        > Create VCN with Internet Connectivity
          > Start VCN Wizard
```

- Configuration
  - VCN NAME:（ここでは `VCN1` とします）
  - その他の項目: 変更の必要なし

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/1f1c081a-d1a7-a41c-6f51-b1b51102191c.png)

VCN1 に作成されたパブリック・サブネットに対して次のルールを新しく追加して、7002 ポートと 8001 ポートを外部からアクセス可能にします。

```
Oracle Cloud console
  > Networking
    > Virtual Cloud Networks
      > VCN1
        > Public Subnet-VCN1
          > Default Security List for VCN1
            > Add Ingress Rules
```

- Add Ingress Rules
  - Source CIDR: `0.0.0.0/0`
  - Destination port range: `7002,8001`
  - Description: `For SPARQL Endpoint`

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/3a8deeb8-7af0-c30f-7845-80b71e636cae.png)

## エンドポイント管理サーバーの作成

エンドポイント管理サーバー（RDF Graph Server and Query UI）は、マーケットプレイス・イメージとして配布されているので、次のように画面を進み、このイメージからインスタンスを作成します。

```
Oracle Cloud console
  > Marketplace
    > All Applications
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/91df045b-8927-36ae-7a1e-b5a5a05f49d4.png)

- Image
  - Name: `Oracle RDF Graph Server and Query UI`
  - Version: `22.2.0`

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/131a1783-55e3-c594-4dc1-dbcb57539bce.png)

- Configure Variables
  - Resource name prefix: 任意の名前
  - OCI compartment: お使いのコンパートメント
  - Server available domain: 任意のドメイン
  - Server shape: `VM.Standard.E2.1.Micro`（Always Free で使用可）
- Add SSH keys
  - SSH public key: 公開鍵 (e.g. `ssh-rsa AAAAB3NzaC...`)
- Instance Network
  - Virtual cloud network compartment: お使いのコンパートメント
  - Existing virtual cloud network: 上で作成された VCN
  - Subnet compartment: お使いのコンパートメント
  - Existing subnet: 上で作成された VCN の public subnet
- WebLogic Advanced Configuration
    - WebLogic Admin User Name: `admin`
    - WebLogic Admin Password: `<password_2>`

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/796b7c40-1726-c16e-bc15-f95c6663015b.png)

インスタンスの作成には数分かかります。

作成完了後、ログ出力に新しいインスタンスの IP アドレスが表示されるので、これを控えておいてください。IP アドレスは後からコンピュート・インスタンスのページで確認することもできます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/39a8be98-0819-2d16-6e9e-5b493288ad4e.png)

## エンドポイント管理サーバーへのログイン

作成されたエンドポイント管理サーバーにアクセスします。

- URL: `https://<ip_address>:8001/orardf`

自己署名証明書が使われているため、セキュリティ警告が表示されます。

- Chrome: "thisisunsafe" とタイプします
- Firefox: Advanced > Accept the Risk and continue

デフォルトのパスワードでログインします。

- User: `admin`
- Password: `<password_2>`

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/779d99ba-1594-7e74-f15b-cadd7eb3294d.png)

ログインできましたが、この時点ではエンドポイント管理サーバーは Autonomous Database に接続されていないため、クエリ対象となるデータソースはありません。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/0ac50325-e0c8-5af3-9991-ed4ed5f8edfd.png)

## Wallet のダウンロード

この SPARQL エンドポイントから Autonomous Database にアクセスするためには Oracle Wallet を用いる必要があります。Oracle Wallet とは証明書、証明書要求、秘密鍵などの資格情報を格納するファイルをまとめた Zip ファイルです。

次のように画面を進んで、Wallet のダウンロードのページを開きます。

```
Oracle Cloud console
  > Oracle Database
    > Autonomous Database
      > Select the ADB created above
        > DB Connection
```

- Wallet Type: `Instance Wallet`
- Password: `<password_3>`

## Wallet への資格証明の追加

SPARQL エンドポイントがこの Wallet を用いて Autonomous Database にアクセスするために、この Wallet に資格証明を含める必要があります。ここでは、一度、Wallet をインスタンスにアップロードして、以下のコマンドを用いて Wallet にユーザー名とパスワードを追加します。

```
$ scp -i <key> ~/Downloads/Wallet_<db_name>.zip opc@<ip_address>:
$ ssh -i <key> opc@<ip_address>
$ mkdir wallet
$ cd wallet
$ unzip ../Wallet_<db_name>.zip
$ export JAVA_HOME=/usr/local/java/jdk1.8.0_221
$ /u01/app/oracle/middleware/wls12214/oracle_common/bin/mkstore
  -wrl /home/opc/wallet -createCredential <db_name>_high ADMIN <password_1>

Enter wallet password: <password_3>
```

`<...>` の部分を置き換えた場合の例：

```
$ scp -i .ssh/id_rsa ~/Downloads/Wallet_ADB1.zip opc@192.0.2.1:
$ ssh -i .ssh/id_rsa opc@192.0.2.1
$ mkdir wallet
$ cd wallet
$ unzip ../Wallet_ADB1.zip
$ export JAVA_HOME=/usr/local/java/jdk1.8.0_221
$ /u01/app/oracle/middleware/wls12214/oracle_common/bin/mkstore \
  -wrl /home/opc/wallet -createCredential adb1_high ADMIN <password_1>

Enter wallet password: <password_3>
```

変更後の Wallet をダウンロードします。

```
$ zip ../wallet_with_cred.zip *
$ exit
$ scp -i <key> opc@<ip_address>:~/wallet_with_cred.zip ~/Downloads/
```

`<...>` の部分を置き換えた場合の例：

```
$ zip ../wallet_with_cred.zip *
$ exit
$ scp -i .ssh/id_rsa opc@192.0.2.1:~/wallet_with_cred.zip ~/Downloads/
```

## データベースへの接続

エンドポイント管理サーバーの設定画面の Data sources タブからデータベースへの接続を作成して、Wallet をアップロードします。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/6f8ab504-308b-23bd-468d-5c7b238d914f.png)

- Zip file: `wallet_with_cred.zip` を選択
- Name: 任意のデータソース名 (e.g. `ADB1`)
- Wallet Service: 上で Wallet に追加したサービス (e.g. `adb1_high`)

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/1995dd81-2e50-4603-affc-fba152ccad6f.png)

データソースが作成されると「Data」タブでこれを選択することができます。ただし、このデータソースにはまだ RDF network がありません。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/38f01605-2461-b1dd-a20d-d3dca1fa2aaa.png)

## RDF データのアップロード

ここでは、W3C のサイト（[https://www.w3.org/TR/turtle/](https://www.w3.org/TR/turtle/)）に掲載されている次のサンプル・データをロードしてみます。

`example1.ttl`

```
@base <http://example.org/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
@prefix rel: <http://www.perceive.net/schemas/relationship/> .

<#green-goblin>
    rel:enemyOf <#spiderman> ;
    a foaf:Person ;    # in the context of the Marvel universe
    foaf:name "Green Goblin" .

<#spiderman>
    rel:enemyOf <#green-goblin> ;
    a foaf:Person ;
    foaf:name "Spiderman", "Человек-паук"@ru .
```

Data タブで先に登録したデータ・ソース (e.g. `ADB1`) を選択して、ここに RDF Network を作成します。ここで、Oracle Database における RDF Network とは、表や索引のセットからなる論理的な RDF ストアのことで、データベース上には RDF Network を複数作成することができます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/b9648645-809f-a870-92b5-9efcefa2b5a1.png)

- Network owner: `ADMIN`
- Network name: 任意の RDF Network 名 (e.g. `NETWORK1`)
- Tablespace: `DATA`

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/fd371804-731e-5594-ed62-28d46904a435.png)

Data タブで先に作成した RDF Network (e.g. `ADMIN.NETWORK1`) を指定し、Import タブの Upload data アイコンをクリックして、ファイルをステージング表にアップロードします。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/786cdf5d-0ca5-f229-38a0-3fec0039607a.png)

- Upload: `example1.ttl`
- Staging table: 任意の表名 (e.g. `EXAMPLE1_TABLE`)
- Overwrite: false (既存の表を使いたい場合には上書きしても OK)

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/e284f118-2934-f91f-eae3-f53f32ded862.png)

最後に、Import タブの Bulk load data アイコンをクリックして、ステージング表のデータを Model にロードします。ここで、Oracle Graph における Model とは、RDF Network 内のトリプルの集合の管理単位のことで、SPARQL クエリの対象として Model を指定したり、Model を束ねた Virtual Model を定義するといったことが可能です。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/73f8e6eb-fd66-e8ca-69b3-ae0ad033045f.png)

- RDF Data
  - Model: 任意のモデル名 (e.g. `EXAMPLE1_MODEL`)
  - Staging table owner: `ADMIN`
  - Staging table: 上で作成したステージング表 (e.g. `EXAMPLE1_TABLE`)
- Options
  - 全ての項目: 変更不要
- Event Trace
  - 全ての項目: 変更不要

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/4f6bf254-010a-a944-c626-922cf23c1dc5.png)

## SPARQL クエリの実行

まずは、エンドポイント管理サーバーのクエリ UI 上で SPARQL クエリを実行してみます。

クエリ対象のモデル（ここでは `EXAMPLE1_MODEL`）を右クリックし「Open」からエディタを開きます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/57b0abb3-0689-6512-91ed-9b8ec8efcc9f.png)

Execute ボタンをクリックして、デフォルトで入力されている SPARQL クエリを実行してみると、結果として格納されているトリプルが表示されます。

![Screen Shot 2022-02-02 at 17.29.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/2b09d383-c38a-52c5-44cd-ea579d3abfa2.png)

こちらは、Spiderman という名前のヒーロー（変数 `?h`）の敵（`?e`）の名前（`?e_name`）を検索するクエリです。

```sparql
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX rel: <http://www.perceive.net/schemas/relationship/>

SELECT ?e_name
WHERE {
  ?h foaf:name "Spiderman" .
  ?e rel:enemyOf ?h .
  ?e foaf:name ?e_name .
} 
LIMIT 500
```

Green Goblin が返されました！

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/16ae4d16-059e-69c7-b73a-0e4bb6033ed9.png)

## エンドポイントの公開

この時点では、SPARQL エンドポイントはまだ公開されていません。エンドポイントの公開を可能するために、まず設定画面からこれを許可してデータ・ソース（ここでは `ADB1`）を選択します。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/9d49e43e-aae7-b724-1019-409d6863244a.png)

公開するモデルを右クリックして Publish を選択します。エンドポイント URL に使用するデータセットの名前（ここでは `example1`）を入力します。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/92bd3c4e-ead5-f791-e2d7-488ed2473a8b.png)

以下のようなエンドポイント URL が表示されるのでこれを保存しておきます。

```
https://<ip_address>:8001/orardf/api/v1/datasets/query/published/example1
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/3c8ae507-1a2e-5973-882b-e500ce971c2e.png)

## REST でエンドポイントにアクセス

GET もしくは POST を使ってエンドポイントに対して SPARQL クエリを発行してみます。まず、上でも用いた SPARQL クエリをファイルに保存しておきます。

`sparql.rq`

```sparql
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX rel: <http://www.perceive.net/schemas/relationship/>

SELECT ?e_name
WHERE {
  ?h foaf:name "Spiderman" .
  ?e rel:enemyOf ?h .
  ?e foaf:name ?e_name .
} 
LIMIT 500
```

このファイルを指定して POST リクエストを実行します。ここでは自己署名証明書を使っているため `--insecure` オプションを指定してこれを許可しています。

```
$ curl https://<ip_address>:8001/orardf/api/v1/datasets/query/published/example1 \
  --data-binary @sparql.rq --insecure -X POST
```

結果はデフォルトでは [W3C 標準](https://www.w3.org/TR/sparql11-results-json/) の JSON 形式で返されます。

```json
{
  "head": {
    "vars": [
      "E_NAME"
    ],
    "links": []
  },
  "results": {
    "bindings": [
      {
        "E_NAME": {
          "type": "literal",
          "value": "Green Goblin"
        }
      }
    ]
  }
}
```


## 参考： エンドポイントのパスワード変更

WebLogic Server コンソールにアクセスします。まだ証明書を設定していないので（自己署名証明書を使っているため）ウェブ・ブラウザの警告が出ます。Chrome では「thisisunsafe」の入力、Firefox では警告を承諾して次に進みます。

- `https://<ip_address>:7002/console`

デフォルトのパスワードでログインします。

- Username: `admin`
- Password: `<password_2>`

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/557ac3d3-79c7-9d73-18fb-dd55fab27e6a.png)

`Security Realms` > `myrealm` > `Users and Groups` と進み、`admin` を選択します。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/56c81b25-4769-a063-b240-285fd10d668a.png)

`Passwords` タブからパスワードを変更します。

## 参考： データ・ロード時にグラフ名を指定

RDF データをロードする際に、それらのトリプルのグラフ名を一括して設定し、クアッドとしてロードしたい場合があります。その場合には、トリプルをステージング表にアップロードした後に、その表にグラフ名を追加したビューを作成して、これを RDF モデルにロードします。

まず、[Create RDF Network](#Create-RDF-Network) で説明しているとおりに、データをステージング表にアップロードします。

- Upload: `example1.ttl`
- Staging table: 任意の表名 (e.g. `EXAMPLE1_TABLE`)
- Overwrite: false (既存の表を使いたい場合には上書きしても OK)

SQL を実行するため Database Actions を開きます。

```
Oracle Cloud console
  > Oracle Database
    > Autonomous Database
      > 作成した ADB を選択
        > Tools
          > Open Database Actions
```

次の SQL クエリを実行してビューを作成します。この際、指定したいグラフ名で `<http://example.org/graph1>` を置き換えてください。

```
create view SAMPLE_VIEW as
select
  RDF$STC_SUB
, RDF$STC_PRED
, RDF$STC_OBJ
, '<http://example.org/graph1>' as RDF$STC_GRAPH
from SAMPLE_TABLE
```

SPARQL エンドポイントに戻り、Import タブの Bulk load data アイコンをクリックして、作成したビューから新しいモデルへとデータをロードします。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410176/43e1803d-5cd9-b348-e227-3f9137b60c79.png)

- RDF Data
  - Model: 任意のモデル名 (e.g. `EXAMPLE1_MODEL`)
  - Staging table owner: `ADMIN`
  - Staging table: 上で作成したステージング表 (e.g. `EXAMPLE1_VIEW`)
- Options
  - 全ての項目: 変更不要
- Event Trace
  - 全ての項目: 変更不要


次の SPARQL クエリでグラフ名が結果に含まれることを確認できます。

```
SELECT *
WHERE { GRAPH ?g { ?s ?p ?o }} 
LIMIT 500
```

※ 冒頭画像 Photo by [Cristian Escobar](https://unsplash.com/@cristian1?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/spark?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)