Apache Jena Ontology APIについて

# Apache Jenaによるオントロジの利用
[Apache Jena](http://jena.apache.org/)は、[RDF4J](http://rdf4j.org/)と並んでよく利用されているRDFライブラリです。一説によるとJenaのほうがいろいろできる代わりに、学習が大変ということらしい。

実際、普通にRDFを作るだけだと結構簡単なのですが、OWLなどのオントロジを扱おうとすると急にハードルが上がる気がしています。

Apache JenaではRDFS、OWLなど扱うための一貫したAPIを提供しています。この辺は日本語のソースが少ないようなので、ここにメモがてら残しておきます。

# Ontology APIの基本
OWLはRDFS（RDFスキーマ）のスーパーセットのようなもので、RDFSで表せるものは大体表現できます。例えば、RDFのプロパティは階層的に表現できますが、OWLのプロパティではtransitive, semantric, functionalに拡張することができます。他にも相互的（逆の）の関係性を記述できたりします。

ちなみにOWLには、記述論理をベースにタイプ区別を厳密にしたOWL DLと、実用的なオントロジー構築を念頭においたOWL Fullがあります。また、より実装しやすいOWL DLのサブセットであるOWL Liteも合わせて提供されています。

オントロジを使うメリットはReasonerを使って、データについての推論ができることです。JenaではInference APIによって、様々な推論エンジンを利用することができます。

OntClassというのが基本のクラスで、このクラスで様々なスキーマ（プロファイル）を表現することが出います。このクラスはJenaのModelクラスを拡張したクラスで、オントロジで規定される制約（construct）などを定めています。具体的には以下のようにFactoryメソッドを介して生成します。

```
OntModel m = ModelFactory.createOntologyModel();
```

この場合、デフォルトのセッティング（OWL-Full, In-Memory, RDFS推論）で生成されます。一般的に負荷が大きいので、適切なセッティングを使うべきです。その場合は、引数にOntModelSpecを入力します。以下の感じです。利用するLanguage Profile(OWL Full, OWL DL, OWL Lite, RDFS)についても、この引数で設定します。16個のプロファイルがあります。具体的には[APIドキュメント](http://jena.apache.org/documentation/javadoc/jena/org/apache/jena/ontology/OntModelSpec.html)を参照ください。

```
OntModel m = ModelFactory.createOntologyModel( OntModelSpec.OWL_MEM);
```

Jenaのオントロジモデルでは、複数のオントロジを扱おうとする際は、インポートするモデルのcollectionを持つこととなります。一般的なJanaの使い方と同じで、オントロジをインポートする際も`read`メソッドを使います。

```
read( String url )
read( Reader reader, String base )
read( InputStream reader, String base )
read( String url, String lang )
read( Reader reader, String base, String Lang )
read( InputStream reader, String base, String Lang )
```

オントロジを読み込んだ際、デフォルトではそれ自身の参照URIを含みます。具体的には`rdf:about`によって指定されるURIです。公式サイトのサンプルでは以下のように紹介されています。`owl:import`で参照・読み込んでいるオントロジが示されています。`dc`はDublin Coreですかね。

```
<owl:Ontology rdf:about="">
  <dc:creator rdf:value="Ian Dickinson" />
  <owl:imports rdf:resource="http://jena.apache.org/examples/example-ont" />
</owl:Ontology>
```

このようにして読み込まれたオントロジは別々のグラフ構造として保持されます。複数読み込まれた場合は、Union Graphとして統合されてReasonerからは参照されます。

これらのオントロジを使ったRDFの永続化などについては様々なオプションがあります。公式サイトには以下の例が紹介されています。`OntDocumentManager`はオントロジの処理をアシストしてくれるモジュールで、そこで`addAltEntry`メソッドを呼んでいます。インターネットを参照して取得したESWCオントロジをローカルのRDFにコピーして処理することが記載されています。全部覚えるのはなかなか覚えるのが大変ですね。。。

```java
OntModel m = ModelFactory.createOntologyModel();
OntDocumentManager dm = m.getDocumentManager();
dm.addAltEntry( "http://www.eswc2006.org/technologies/ontology",
                "file:" + JENA + "src/examples/resources/eswc-2006-09-21.rdf" );
m.read( "http://www.eswc2006.org/technologies/ontology" );
```

#Scalaでの練習
世の中にはscalaでネイティブ実装した[banana-rdf](https://github.com/banana-rdf/banana-rdf)というのがあるようですが、ドキュメントが充実していないので、Jenaをscalaでラップして使ってみたいと思います。

今回は[Ammoniteで-REPL](http://ammonite.io/)での手順を書いてみます。

```scala
// Jenaのダウンロード
import $ivy.`org.apache.jena:jena-core:3.8.0`

import scala.collection.JavaConverters._
import org.apache.jena.rdf.model._
import org.apache.jena.ontology.OntModelSpec._

// ベースモデルを生成
val SOURCE = " http://rdfs.org/sioc/ns"
val NS = SOURCE  + "#"
val base = ModelFactory.createOntologyModel(OWL_MEM)
base.read(SOURCE, "RDF/XML")

// ベースモデルによる推論モデルを生成
val inf = ModelFactory.createOntologyModel(OWL_MEM_MICRO_RULE_INF, base)

val user = base.getOntClass(NS + "UserAccont")
val u1 = base.createIndividual(NS + "user1", user)
u1.listRDFTypes(true).toList.asScala.foreach{`type` => println( c1.getURI() + " is asserted in class " + `type`}
// http://rdfs.org/sioc/ns#account1 is asserted in class http://rdfs.org/sioc/ns#UserAccount
 
val inf_user = inf.getIndividual(NS + "user1")
inf_user.listRDFTypes(true).toList.asScala.foreach{`type` => println( inf_user.getURI() + " is asserted in class " + `type`}
// http://rdfs.org/sioc/ns#account1 is asserted in class http://rdfs.org/sioc/ns#UserAccount 
// http://rdfs.org/sioc/ns#account1 is asserted in class http://rdfs.org/sioc/ns#User
```

まずはウェブ上のオントロジを拾ってきて読み込みます。
続いて、Individualを生成するためのオントロジのクラスを参照し（`getOntClass`の部分）、`createIndividual`で生成しています。
最後の部分は生成したIndividualのURIを使って推論をしています。`listRDFTypes`の論理値の引数は、直接（Direct）に参照されているクラスかどうかを示すものです。上記のコメント部分に書かれている出力では、2つのクラスが示されていますが、引数をfalseとすると以下の出力を得ることができます。なんとなく意味は分かるよね。

```
http://rdfs.org/sioc/ns#account1 is asserted in class http://rdfs.org/sioc/ns#UserAccount
http://rdfs.org/sioc/ns#account1 is asserted in class http://rdfs.org/sioc/ns#User
http://rdfs.org/sioc/ns#account1 is asserted in class http://www.w3.org/2002/07/owl#Thing
http://rdfs.org/sioc/ns#account1 is asserted in class http://www.w3.org/2000/01/rdf-schema#Resource
http://rdfs.org/sioc/ns#account1 is asserted in class http://xmlns.com/foaf/0.1/OnlineAccount
```

このほかにも、プロパティの記述や拘束条件の記述など覚えることはたくさんあります。いずれにせよ、Ontorogy APIを利用すると、既往のオントロジを利用した様々な推論が可能になることが分かります。

今日はここまで。