AWSサーバレスでSPARQLエンドポイントを構築(Java+Apache Jena編)

AWSサーバレスでSPARQLエンドポイントの構築を試してみた第2弾です。
第1弾はこちらです。

AWSサーバレスでSPARQLエンドポイントを構築(Node.js+quadstore編)
https://qiita.com/uedayou/items/bdf7a802e27fe330044e

前回は利用したライブラリの関係で検索速度に難があり限定した用途であれば使える、という感じでした。
今回はRDFストアとしては実績がある[Apache Jena](https://jena.apache.org/)を使ってみました。

## 環境

- [AWS Lambda](https://aws.amazon.com/jp/lambda/)
- [Amazon API Gateway](https://aws.amazon.com/jp/api-gateway/)

前回と同じくAWS Lambda+API Gatewayという構成です。
Apache Jena は

- [jena-core](https://jena.apache.org/documentation/rdf/index.html)
- [jena-arq](https://jena.apache.org/documentation/query/index.html)
- [jena-tdb](https://jena.apache.org/documentation/tdb/index.html)

を使用しています。
TDBで使う方法以外にRDFファイルを直接使用することもできますが、以下の結果も踏まえてTDBに変換して使用することをお勧めします。

ソースコードは以下で公開しています。
<https://github.com/uedayou/jena-sparql-server-aws-serverless>

## クエリ検索時間計測

検索にかかる時間は

- TDBを使用する方法
- RDFファイルを直接利用する方法

の2つについて計測しています。TDBは一旦ZIP圧縮したものをデプロイしています。

### SPARQLクエリ

クエリは[前回](https://qiita.com/uedayou/items/bdf7a802e27fe330044e)と同じです。
データセットも[前回](https://qiita.com/uedayou/items/bdf7a802e27fe330044e)と同じく[「図書館及び関連組織のための国際標準識別子（ISIL）」試行版LOD](https://www.ndl.go.jp/jp/dlib/standards/opendataset/index.html)を使いました。
分割されたTurtleファイルを1つずつ追加して作成したデータセット毎(RDFファイルは全ファイルを統合したもののみ)に計測しています。

#### (1) トリプルを100件取得

```
select * where {?s ?p ?o} limit 100
```

#### (2) 全トリプル数を取得

```
select (count(*) as ?count) where {?s ?p ?o}
```

#### (3) `filter`を使って文字列の絞り込み

```
prefix schema: <http://schema.org/>
prefix org:   <http://www.w3.org/ns/org#>
prefix dbpedia: <http://dbpedia.org/ontology/>

select * where {
  ?uri dbpedia:originalName ?name;
  org:hasSite/org:siteAddress/schema:addressRegion ?pref.
  filter( regex(?pref, "東京") )
}
limit 10
```

### TDBの結果

TDBを使えばかなり高速に検索ができました。
ただ、AWS Lambdaはコンテナが生成される場合にその初期化とZIP圧縮されたTDBを解凍する時間が追加かかるため(一度生成されてしまえばしばらくはそのコンテナが再利用される)、その時(例えば初回起動時やしばらく実行がなくコンテナが破棄された状態の場合)にはそれらの処理の時間がかかり、今回使用したファイルでは約4秒ほどかかりました。
以下はコンテナがすでに生成されているときの時間です。コンテナ未生成時は以下の時間に＋4秒かかることになります。
[前回](https://qiita.com/uedayou/items/bdf7a802e27fe330044e)は10秒以上かかるクエリもあり単純なクエリでも場合によってはタイムアウトで検索結果が得られないことが起こり得ました。
TDBコンテナ生成が必要な時でも5秒以内には結果が取得でき、よっぽど複雑なクエリでなければタイムアウトはしないと思います。

トリプル数 | (1) | (2) | (3) 
--- | --- | --- | ---
21,788 | 242ms | 494ms | 159ms
42,585 | 254ms | 531ms | 102ms
63,448 | 148ms | 502ms | 67ms
84,587 | 166ms | 504ms | 100ms
104,826 | 154ms | 572ms | 85ms
124,718 | 176ms | 367ms | 112ms
144,669 | 153ms | 583ms | 80ms
160,491 | 141ms | 579ms | 104ms


### RDFファイルの結果

RDFファイルを直接利用する場合は、TDBよりも時間がかかりました。
以下はTDBと同じくコンテナ生成時の時間ですが、TDBよりも初期化に時間がかかりました(約7秒)。
TDBはZIPの解凍処理も入るのに、RDFファイルを使うほうが初期化の時間がかかるのは調べてみないとよくわかりませんが、それを差し引いてもTDBを使うほうが良いと思いました。

トリプル数 | (1) | (2) | (3) 
--- | --- | --- | ---
160,491 | 1587ms | 1664ms | 1215ms

## まとめ

- (個人的には)実用に耐えうる検索速度が出せるSPARQLエンドポイントがサーバレス環境で構築できた
- AWS Lambdaのコールドスタート問題？によりコンテナ生成時に数秒時間がかかる
- RDFファイルを直接利用するのではなくTDBに変換したほうがよい

Apache Jenaを使うAWSサーバレス版SPARQLエンドポイントは個人的には満足できるパフォーマンスだと思いますので、今後いろいろ使いたいと思います。

早速、鉄道オープンデータ提供サイト[鉄道駅LOD](http://uedayou.net/jrslod/)の[SPARQLエンドポイント](https://qiita.com/uedayou/items/3ba823c5d3bede12af9c)をApache Jena版に変更しました。

実際に試してみたい人は、以下の記事を参照してください。

鉄道駅LODのSPARQLエンドポイントを実験的に公開しました
https://qiita.com/uedayou/items/3ba823c5d3bede12af9c