6 RDF Semantic Graph support for Apache Jena
RDF Semantic Graph support for Apache Jena(以降、support for Apache Jenaとも記載)は、既知のJenaグラフ、JenaモデルおよびJena DatasetGraphのAPIを実装することによって、Oracle Spatial and Graph RDF Semantic GraphへのJavaベースのインタフェースを提供します。
注意:
この機能は、以前はJena Adapter for Oracle DatabaseまたはJena Adapterと呼ばれていました。
support for Apache Jenaは、Oracle Database RDF/OWLのセマンティク・データ管理機能を拡張します。
(Apache Jenaはオープン・ソース・フレームワークです。ライセンスと著作権条件は、http://www.apache.org/licenses/
およびhttp://www.apache.org/licenses/LICENSE-2.0
を参照してください
名前付きグラフ・データ(クワッドとも呼ぶ)の管理には、DatasetGraph APIを使用します。また、RDF Semantic Graph support for Apache JenaをOracle Spatial and Graphのネットワークデータ・モデル・グラフ機能と統合することで、セマンティク・データでのネットワーク解析機能を利用できます。
「RDFセマンティク・グラフの概要」と「OWLの概要」で説明されている主要な概念について十分に理解していることが前提です。Jena Javaフレームワークの性能全体についても十分に理解していることを前提とします。Jenaフレームワークの詳細は、http://jena.apache.org/
の、特にJenaドキュメントのページを参照してください。ネットワーク分析関数を使用するには、『Oracle Spatial and Graphトポロジ・データ・モデルおよびネットワーク・データ・モデル・グラフ開発者ガイド』に説明されている、ネットワーク・データ・モデルのグラフ機能についても理解しておく必要があります。
注意:
RDF Semantic Graph support for Apache Jenaの現在のリリースは、Apache Jena 2.11.1およびJoseki 3.4.4に対してテストされています。オープンソース・プロジェクトの性質上、これよりも新しいバージョンのJenaまたはJosekiでは、このsupport for Apache Jenaを使用しないでください。
- ソフトウェア環境の設定
Support for Apache Jenaを使用するには、システム環境に必要なソフトウェア(Oracle Database 11gリリース2以上に加えて、Spatial and GraphおよびPartitioningのオプション、RDFセマンティク・グラフのサポート、Jenaバージョン2.11.1、Support for Apache JenaおよびJDK 1.6以上)があることを、最初に確認しておく必要があります。 - SPARQLサービスの設定
この項では、joseki.war
ファイルをWebLogic Serverにデプロイすることにより、SPARQL Webサービス・エンドポイントを設定する方法について説明します。 - 動的なSPARQLエンドポイントの設定
動的なSPARQL Webサービス・エンドポイントを、Apache Jena JosekiおよびApache Jena Fusekiを使用して設定できます。 - Josekiサーブレットへのクロスサイト・リクエスト・フォージェリ(CSRF)に対する防御の追加
クロスサイト・リクエスト・フォージェリ(CSRF)に対する防御を、Josekiサーブレットに追加できます。 - RDFセマンティク・グラフ環境の設定
Support for Apache Jenaを使用して問合せを実行するには、(適切な権限を持つ)任意のユーザーで接続し、セマンティク・ネットワークで任意のモデルを使用します。 - SEM_MATCHおよびRDF Semantic Graph support for Apache Jenaの問合せの比較
Oracle Databaseに格納されているセマンティク・データを問い合せる方法は2つあります。SEM_MATCHベースのSQL文とSupport for Apache Jenaを介したSPARQL問合せです。 - SEM_MATCHまたはSQLベースの問合せ結果からのユーザーフレンドリJavaオブジェクトの取得
ここで述べる方法を使用して、セマンティク・グラフの問合せができます。 - SPARQL問合せ処理の最適化
この項では、SPARQL問合せ処理を強化できる、Support for Apache Jenaのいくつかのパフォーマンス関連機能について説明します。これらの機能は、デフォルトでは自動的に実行されます。 - その他の機能をサポートするSPARQL構文の追加
RDF Semantic Graph support for Apache Jenaにより、ヒントと追加の問合せオプションの引渡しが可能です。問合せオプションを含むOracle固有の名前空間を使用してSPARQL名前空間接頭辞の構文をオーバーロードすることで、これらの機能を実装できます。 - RDF Semantic Graph Support for Apache JenaによりSPARQL問合せでサポートされる関数
ここでは、Support for Apache JenaによりサポートされるSPARQL問合せで使用できる関数について述べます。 - SPARQL更新のサポート
RDF Semantic Graph support for Apache Jenaは、SPARQLの更新(SPARULとも呼ばれる)(http://www.w3.org/TR/sparql11-update/
)をサポートしています。 - RDFデータを対象とする解析関数
oracle.spatial.rdf.client.jena
パッケージのSemNetworkAnalyst
クラスを使用して、RDFデータに対して解析関数を実行できます。 - サーバー側APIのサポート
この項では、RDF Semantic Graph Support for Apache Jenaによって使用可能になるRDFセマンティク・グラフ機能の一部について説明します。 - RDF Semantic Graph Support for Apache Jenaを使用したバルク・ロード
数千から数十万のRDF/OWLデータ・ファイルをOracle Databaseに簡単にロードするには、OracleBulkUpdateHandler
JavaクラスのprepareBulk
メソッドとcompleteBulk
メソッドを使用します。 - 変数名の自動変更
以前は正常終了しなかった特定の問合せが、変数名の自動変更で使用できるようになることがあります。 - JavaScript Object Notation (JSON)形式のサポート
SPARQL問合せへの応答に関して、JavaScript Object Notation (JSON)形式がサポートされています。JSONデータ形式は単純、コンパクトで、JavaScriptプログラムに適しています。 - その他の推奨事項とガイドライン
この項では、SPARQL問合せに関連する様々な推奨事項およびその他の情報について説明します。 - RDF Semantic Graph Support for Apache Jenaを使用した問合せの例
ここでは、Support for Apache Jenaを使用した問合せの例を示します。それぞれの例は個々に完結しており、通常はモデルの作成、トリプルの作成、推論を含む可能性のある問合せの実行、結果の表示およびモデルの削除を行います。 - SPARQL Gatewayとセマンティク・データ
SPARQL Gatewayは、Support for Apache Jenaに含まれるJ2EE Webアプリケーションです。Oracle Business Intelligence Enterprise Edition (OBIEE) 11gなどの、リレーショナル・データおよびXMLデータで稼働するアプリケーションで、セマンティク・データ(RDF/OWL/SKOS)を容易に利用可能にすることを目的としています。 - Apache TomcatまたはJBossにおけるJosekiのデプロイ
JosekiをOracle WebLogic Serverにデプロイしないことにする場合、Apache TomcatまたはJBossにデプロイすることもできます。
親トピック: 概念および使用方法に関する情報
6.1 ソフトウェア環境の設定
Support for Apache Jenaを使用するには、システム環境に必要なソフトウェア(Oracle Database 11gリリース2以上に加えて、Spatial、GraphおよびPartitioningのオプション、RDFセマンティク・グラフのサポート、Apache Jena 2.11.1およびJDK 1.6以上など)があることを、最初に確認しておく必要があります。
次の手順を実行することによって、ソフトウェア環境を設定できます。
-
Oracle Database Enterprise Editionと、Oracle Spatial and GraphオプションおよびOracle Partitioningオプションをインストールします。
-
Oracle Databaseリリース11.2.0.3以上をまだインストールしていない場合は、Oracle Database Serverの11.2.0.2パッチ・セット(
https://updates.oracle.com/Orion/PatchDetails/process_form?patch_num=10098816
)をインストールします。 -
「RDFセマンティク・グラフ・サポートの有効化」の説明のとおり、RDFセマンティク・グラフのサポートを有効にします。
-
RDF Semantic Graph support for Apache JenaをMy Oracle Support (
http://support.oracle.com/
)からダウンロードします。ナレッジ・ベースでバグ識別子17241927を検索します。RDF Semantic Graph support for Apache Jenaの完全な評価版は、
http://www.oracle.com/technetwork/database-options/spatialandgraph/
のOTNからダウンロードできます。「Downloads」タブをクリックし、Licensed Softwareの下の「RDF Semantic Graph Licensed Software」をクリックします。 -
キットを
/tmp/jena_adapter
(Linuxシステム)などの一時ディレクトリに解凍します。(この一時ディレクトリがまだ作成されていない場合は、解凍操作の前に作成します。)RDF Semantic Graph Support for Apache Jenaには、最上位に次のようなディレクトリがあります。
|-- META-INF |-- examples |-- jar |-- javadoc |-- joseki |-- joseki_web_app |-- protege_plugin |-- sparqlgateway |-- sparqlgateway_web_app |-- fuseki |-- web
-
JDK 1.6以上がインストールされていない場合は、インストールします。
-
JAVA_HOME環境変数にJDK 1.6以上がインストールが指定されていない場合は、適切に定義します。たとえば、次のようにします。
setenv JAVA_HOME /usr/local/packages/jdk16/
-
SPARQLプロトコルをサポートするためのSPARQLサービスが設定されていない場合は、「SPARQLサービスの設定」の説明のとおりに設定します。
ソフトウェア環境を設定した後、「RDFセマンティク・グラフ環境の設定」の説明にあるとおり、RDFセマンティク・グラフ環境でsupport for Apache Jenaを使用して問合せを実行できることを確認します。
6.1.1 以前のバージョンのsupport for Apache Jenaを使用していた場合
前のバージョンのsupport for Apache Jenaを使用していた場合は、次に示す、このバージョンでの重要な変更点に注意してください。
-
com.hp.hpl.jena.sparql.core.DataSourceImpl
は、com.hp.hpl.jena.sparql.core.DatasetImpl
に置換されます。Javaソース・コードに
import com.hp.hpl.jena.sparql.core.DataSourceImpl
がある場合は、import com.hp.hpl.jena.sparql.core.DatasetImpl
に更新する必要があります。Javaソース・コードに
DataSourceImpl.wrap
がある場合は、DatasetImpl.wrap"
に更新する必要があります。 -
joseki-config.ttl
は、joseki.war
のWEB-INF/classes
ディレクトリ下に移動されています。この設定ファイルは、これまでjoseki.war
のトップレベル・ディレクトリ下に置かれていました。次の例に新しい配置を示します。% /usr/local/packages/jdk16/bin/jar tf joseki.war application.xml index.html joseki-config-ttl_now_under_WEB-INF_classes META-INF/ META-INF/MANIFEST.MF ojdbc6.jar StyleSheets/ StyleSheets/joseki.css update.html WEB-INF/ WEB-INF/lib/ WEB-INF/lib/sdordfclient.jar WEB-INF/lib/jena-arq-2.11.1.jar WEB-INF/lib/log4j-1.2.16.jar WEB-INF/lib/jcl-over-slf4j-1.6.4.jar WEB-INF/lib/httpclient-4.2.3.jar WEB-INF/lib/commons-codec-1.6.jar WEB-INF/lib/slf4j-log4j12-1.6.4.jar WEB-INF/lib/servlet-api-2.5-20081211.jar WEB-INF/lib/xercesImpl-2.11.0.jar WEB-INF/lib/slf4j-api-1.6.4.jar WEB-INF/lib/jena-tdb-1.0.1.jar WEB-INF/lib/jena-core-2.11.1.jar WEB-INF/lib/httpcore-4.2.2.jar WEB-INF/lib/joseki-3.4.4.oracle_build_jena211.jar WEB-INF/lib/jena-iri-1.0.1.jar WEB-INF/lib/sdordf.jar WEB-INF/lib/xml-apis-1.4.01.jar WEB-INF/web.xml WEB-INF/classes/ WEB-INF/classes/joseki-config.ttl xml-to-html.xsl
親トピック: ソフトウェア環境の設定
6.2 SPARQLサービスの設定
この項では、joseki.war
ファイルをWebLogic Serverにデプロイすることにより、SPARQL Webサービス・エンドポイントを設定する方法について説明します。
注意:
SPARQLサービスからOracle Databaseへ最初に接続する前に、データベースのユーザーにはCREATE PROCEDURE権限が割り当てられている必要があります。たとえば今、データベースのユーザーがSCOTTで、その権限が与えられていない場合、権限が与えられているアカウントから、次のように入力します。
SQL> GRANT CREATE PROCEDURE TO scott;
SPARQLサービスからOracle Databaseへの接続が最初に確立されると、ユーザー・スキーマにPL/SQLのヘルパー・サブプログラムがいくつか作成されます。このとき、ユーザーにはCREATE PROCEDURE権限が与えられている必要があります。
注意:
WebLogic ServerのかわりにApache TomcatまたはJBossにJosekiをデプロイする場合は、「Apache TomcatまたはJBossにおけるJosekiのデプロイ」を参照してください。
-
Oracle WebLogic Server 11g以上をダウンロードしてインストールします。
-
Joseki 3.4.4に必要であるため、Java 6以上をインストールしておきます。
-
WebLogic Server管理コンソールを使用し、OracleSemDSという名前のJ2EEデータ・ソースを作成します。データ・ソースの作成中に、SPARQL問合せの実行対象になる関連セマンティク・データを含むデータベース・スキーマのユーザーとパスワードを指定できます。
このデータ・ソースの作成に関する情報は、「WebLogic Serverを使用した必要なデータ・ソースの作成」を参照してください。
-
次のとおり、WebLogic Serverの
autodeploy
ディレクトリに移動し、ファイルをコピーします。(開発ドメインでのアプリケーションの自動デプロイに関する詳細は、http://docs.oracle.com/cd/E24329_01/web.1211/e24443/autodeploy.htm
を参照してください。)cd <domain_name>/autodeploy cp -rf /tmp/jena_adapter/joseki_web_app/joseki.war <domain_name>/autodeploy
前述の例で、<domain_name>はWebLogic Serverドメインの名前です。
WebLogic Serverドメインを2つの異なるモード(開発とプロダクション)で実行することはできますが、自動デプロイメント機能を使用できるのは開発モードのみであることに注意してください。
-
Webブラウザを使用し、URLに書式
http://
< hostname>
:7001/joseki
で接続して(Webアプリケーションはポート7001でデプロイされているとします)、デプロイメントを確認します。「Oracle SPARQL Service Endpoint using Joseki」というタイトルのページが表示され、最初のテキスト・ボックスにSPARQLの問合せ例が入力されています。
-
「問合せの発行」をクリックします。
「Oracle SPARQL Endpoint Query Results」というタイトルのページが表示されます。問合せが実行される基礎となるセマンティク・モデルに応じて、結果がある場合とない場合があります。
デフォルトでは、joseki-config.ttl
ファイルには、M_NAMED_GRAPHS
という名前のモデルを使用したoracle:Dataset
定義が含まれます。次のスニペットは、構成を示しています。oracle:allGraphs
の述語は、SPARQLサービス・エンドポイントがM_NAMED_GRAPHS
モデルに格納されているすべてのグラフを使用して問合せを提供することを意味します。
<#oracle> rdf:type oracle:Dataset; joseki:poolSize 1 ; ## Number of concurrent connections allowed to this dataset. oracle:connection [ a oracle:OracleConnection ; ]; oracle:allGraphs [ oracle:firstModel "M_NAMED_GRAPHS" ] .
M_NAMED_GRAPHS
モデルがまだ存在しない場合は、初回のSPARQL問合せリクエスト時に自動的に作成されます。トリプルおよびクワッドの例をいくつか追加して、名前付きグラフ機能をテストすることができます。その例は次のとおりです。
SQL> CONNECT username/password
SQL> INSERT INTO m_named_graphs_tpl VALUES(sdo_rdf_triple_s('m_named_graphs','<urn:s>','<urn:p>','<urn:o>'));
SQL> INSERT INTO m_named_graphs_tpl VALUES(sdo_rdf_triple_s('m_named_graphs:<urn:G1>','<urn:g1_s>','<urn:g1_p>','<urn:g1_o>'));
SQL> INSERT INTO m_named_graphs_tpl VALUES(sdo_rdf_triple_s('m_named_graphs:<urn:G2>','<urn:g2_s>','<urn:g2_p>','<urn:g2_o>'));
SQL> COMMIT;
行を挿入した後、http://
<hostname>
:7001/joseki
に移動し、次のSPARQL問合せを入力して、「問合せの発行」をクリックします。
SELECT ?g ?s ?p ?o WHERE { GRAPH ?g { ?s ?p ?o} }
結果は、4つの列と2つの結果バインディング・セットがあるHTML表になります。
http://
<hostname>
:7001/joseki
ページにもJSON出力オプションがあります。このオプションを選択する(使用可能にする)と、SPARQL問合せのレスポンスがJSON形式に変換されます。
- WebLogic Serverを使用した必要なデータソースの作成
- JosekiベースSPARQLサービスの構成
- FusekiをベースとしたSPARQLサービスの構成
ここでは、Oracle Databaseに接続するFusekiベースのSPARQLサービスについて、その構成方法と設定方法を説明します。 - 長時間にわたるSPARQL問合せの終了
- 非ASCII文字のN-Tripleエンコーディング
6.2.1 WebLogic Serverを使用した必要なデータソースの作成
WebLogic Server管理コンソールを使用して必要なJ2EEデータ・ソースを作成するには、次のステップに従います。
親トピック: SPARQLサービスの設定
6.2.2 JosekiをベースとしたSPARQLサービスの構成
デフォルトでは、SPARQLサービスのエンドポイントは、プリセット名を持つセマンティク・モデルに対して問合せが実行されることが前提になっています。このセマンティック・モデルは、デフォルトのJNDI名OracleSemDSとしてJ2EEデータソースで指定されているスキーマに所有されています。このモデルはPL/SQLやJavaを使用して明示的に作成する必要はないことに注意してください(モデルがネットワークに存在しない場合は、必要なアプリケーション表や索引とあわせて自動的に作成されます)。
注意:
2011年11月のsupport for Apache Jenaリリースから、アプリケーション表索引(<model_name>_idx)定義が、名前付きグラフ・データ(クワッド)に対応するように変更されました。
以前のバージョンのsupport for Apache Jenaで作成された既存のモデルについては、oracle.spatial.rdf.client.jena
パッケージのstatic OracleUtils.migrateApplicationTableIndex(oracle, graph, dop)
メソッドを使用して、アプリケーション表索引の名前と定義を移行できます。(詳細は、Javadocを参照してください。)新しい索引定義は、アプリケーション表に対するDML操作のパフォーマンスにとって非常に重要です。
デフォルトのJNDI名を変更するか、デフォルトのセマンティック・モデルを使用するには、ビルトイン・アプリケーションjoseki_web_app/joseki.war
のWEB-INF/classes
ディレクトリ下に埋め込まれているjoseki-config.ttl
設定ファイルを編集して、SPARQLサービスを構成する方法があります。(前のバージョンのsupport for Apache Jenaを使用していた場合は、joseki-config.ttl
は、Webアプリケーションのトップレベル・ディレクトリ下ではなく、WEB-INF/classes
ディレクトリ下に置かれていることに注意してください。)
提供されるjoseki-config.ttl
ファイルには、Oracleデータセット用に次のようなセクションが含まれます。
# ## Datasets # [] ja:loadClass "oracle.spatial.rdf.client.jena.assembler.OracleAssemblerVocab" . oracle:Dataset rdfs:subClassOf ja:RDFDataset . <#oracle> rdf:type oracle:Dataset; joseki:poolSize 1 ; ## Number of concurrent connections allowed to this dataset. oracle:connection [ a oracle:OracleConnection ; oracle:dataSourceName "OracleSemDS" ]; oracle:defaultModel [ oracle:firstModel "TEST_MODEL" ] .
ファイルのこのセクションでは、次のことができます。
-
joseki:poolSize
値の変更。この値は、このOracleデータセット(<#oracle> rdf:type oracle:Dataset;
)に許可される同時接続数を指定し、データベース内の様々なRDFモデルをポイントします。 -
データ・ソース名をカスタマイズします。アプリケーション要件に応じて、OracleSemDSのデフォルト名を変更できます。ただし、その名前は、「WebLogic Serverを使用した必要なデータソースの作成」で指定したデータ・ソース名と一致する必要があります。
-
defaultModel
の名前(またはoracle:firstModel
述語のオブジェクト値)の変更。これは、問合せに対して異なるセマンティク・モデルを使用するためのものです。このdefaultModel
に対して複数のモデルを指定することも、1つまたは複数のルールベースを指定することもできます。たとえば、次のように2つのモデル(
ABOX
とTBOX
という名前)とOWLPRIMEルールベースをデフォルトのモデルに指定できます。oracle:modelName
述語で指定されたモデルが必ず存在します。これらのモデルは自動的に作成されません。<#oracle> rdf:type oracle:Dataset; joseki:poolSize 1 ; ## Number of concurrent connections allowed to this dataset. oracle:connection [ a oracle:OracleConnection ; oracle:dataSourceName "OracleSemDS" ]; oracle:defaultModel [ oracle:firstModel "ABOX"; oracle:modelName "TBOX"; oracle:rulebaseName "OWLPRIME" ] .
-
データセットで名前付きグラフを指定します。たとえば次のようにして、2つのOracleモデルと1つの伴意に基づき、
<http://G1>
と呼ばれる名前付きグラフを作成できます。<#oracle> rdf:type oracle:Dataset; joseki:poolSize 1 ; ## Number of concurrent connections allowed to this dataset. oracle:connection [ a oracle:OracleConnection ; ]; oracle:namedModel [ oracle:firstModel "ABOX"; oracle:modelName "TBOX"; oracle:rulebaseName "OWLPRIME"; oracle:namedModelURI <http://G1> ] .
namedModel
オブジェクトには、defaultModel
と同じ指定が可能であるため、仮想モデルがここでも同様にサポートされます(次の項目も参照)。 -
次の例に示すとおり、
oracle:useVM "TRUE"
を追加することによって、問合せに仮想モデルを使用します。指定した仮想モデルが存在しない場合は、必要に応じて自動的に作成されます。<#oracle> rdf:type oracle:Dataset; joseki:poolSize 1 ; ## Number of concurrent connections allowed to this dataset. oracle:connection [ a oracle:OracleConnection ; ]; oracle:defaultModel [ oracle:firstModel "ABOX"; oracle:modelName "TBOX"; oracle:rulebaseName "OWLPRIME"; oracle:useVM "TRUE" ] .
詳細は、「仮想モデルのサポート」を参照してください。
-
次の、
TRIPLE_DATA_VM_0
という名前の仮想モデルの例に示すとおり、述語oracle:virtualModelName
を使用することで、SPARQL問合せに応答するためのデフォルトのモデルとして仮想モデルを指定します。oracle:defaultModel [ oracle:virtualModelName "TRIPLE_DATA_VM_0" ] .
基礎となるデータがクワッドで構成される場合、
oracle:virtualModelName
とともにoracle:allGraphs
を使用できます。oracle:allGraphs
を使用することで、DatasetGraphOracleSem
オブジェクトのインスタンス化が名前付きグラフ問合せへの応答になります。次に例を示します。oracle:allGraphs [ oracle:virtualModelName "QUAD_DATA_VM_0" ] .
仮想モデル名がデフォルトのグラフとして指定されると、エンドポイントは問合せリクエストのみに対応し、SPARQL更新操作はサポートされないことに注意してください。
-
問合せの動作と推定更新モードを変更するには、
queryOptions
とinferenceMaintenance
プロパティを設定します。(QueryOptions
とInferenceMaintenanceMode
の詳細は、Javadocを参照してください。)デフォルトでは、問合せの柔軟性と効率を最大限にするため、
QueryOptions.ALLOW_QUERY_INVALID_AND_DUP
とInferenceMaintenanceMode.NO_UPDATE
が設定されます。
6.2.2.1 クライアント識別子
support for Apache Jenaによって作成または使用されたデータベース接続ごとに、クライアント識別子が関連付けられます。クライアント識別子は、特に、Real Application Cluster (Oracle RAC)環境で、パフォーマンス分析とチューニングを実行しているときに、他のデータベース・アクティビティからRDF Semantic Graph support for Apache Jena関連のアクティビティを特定するために有用です。
デフォルトで割り当てられるクライアント識別子は、JenaAdapter
です。ただし、次の形式を使用してJava VM clientIdentifier
プロパティを設定することによって、異なる値を指定できます。
-Doracle.spatial.rdf.client.jena.clientIdentifier=<identificationString>
データベース側でRDF Semantic Graph support for Apache Jena関連のアクティビティのみのトレースを開始するには、DBMS_MONITOR.CLIENT_ID_TRACE_ENABLEプロシージャを使用します。たとえば、次のようにします。
SQL> EXECUTE DBMS_MONITOR.CLIENT_ID_TRACE_ENABLE('JenaAdapter', true, true);
親トピック: JosekiベースSPARQLサービスの構成
6.2.2.2 アプリケーション表およびステージング表に対するOLTP圧縮の使用
デフォルトでは、RDF Semantic Graph support for Apache Jenaは、次の構文に従った基本的な表圧縮を使用して、アプリケーション表と任意のステージング表(後者は「 RDF Semantic Graph support for Apache Jenaを使用したバルク・ロード」で説明されているようにバルク・ロードに使用される)を作成します。
CREATE TABLE .... (... column definitions ...) ... compress;
ただし、データベースにOracle Advanced Compressionオプションの使用がライセンスされている場合は、次のJVMプロパティを設定してOLTP圧縮をオンにできますので、これによって基礎となるアプリケーション表とステージング表に対するすべてのDML操作時にデータが圧縮されます。
-Doracle.spatial.rdf.client.jena.advancedCompression="compress for oltp"
親トピック: JosekiベースSPARQLサービスの構成
6.2.3 FusekiをベースとしたSPARQLサービスの構成
ここでは、Oracle Databaseに接続するFusekiベースのSPARQLサービスについて、その構成方法と設定方法を説明します。
FusekiベースSPARQLサービスの概念と使用法は、JosekiベースSPARQLサービスの場合と同様です。「JosekiベースSPARQLサービスの構成」の説明を参照してください。同様に、そこで述べられているクライアント識別子およびOLTP圧縮に関する情報も、FusekiベースのSPARQLサービスにあてはまります。また、defaultModel
およびallGraphs
の方法も同じです。
Fusekiベースのサービスに対するoracle
サービスの例が、config-oracle.ttl
ファイルに含まれています。詳細は、『Fuseki: HTTPでのRDFデータの提供』(http://jena.apache.org/documentation/serving_data/
)を参照してください。
Oracle Databaseに接続するFusekiベースのSPARQLサービスを使用するには、最初に次のコマンドを入力します。
cd fuseki/
% ./fuseki-server --config config-oracle.ttl
Fusekiの実行中は、形式http://your-hostname:3030/
のURLへ移動して、そのステータスを確認することができます。
親トピック: SPARQLサービスの設定
6.2.4 長時間にわたるSPARQL問合せの終了
一部のアプリケーションでは長時間にわたるSPARQL問合せを終了できるようにする必要があるため、RDF Semantic Graph support for Apache JenaとJosekiの設定で強制終了のフレームワークが導入されています。基本的に、実行に時間がかかりそうな問合せに対しては、各々に一意の問合せID (qid)値を指定する必要があります。
たとえば、次のSPARQL問合せでは、すべてのトリプルの主語を選択します。リクエストに応じてこの問合せを終了できるように、問合せID (qid)が設定されます。
PREFIX ORACLE_SEM_FS_NS: <http://example.com/semtech#qid=8761> SELECT ?subject WHERE {?subject ?property ?object }
qid
属性値は、長整数型です。qid
の値は、独自のアプリケーション・ニーズに基づき、特定の問合せに合わせて選択することができます。
qid値とともに送信されたSPARQL問合せを終了するには、アプリケーションから次の形式で強制終了リクエストをサーブレットに送信し、一致するQID値を指定します。
http://<hostname>:7001/joseki/querymgt?abortqid=8761
親トピック: SPARQLサービスの設定
6.2.5 非ASCII文字のN-Tripleエンコーディング
RDFリソースの字句表現において、文字がOracle Databaseに挿入される際に、非ASCII文字に対して\uHHHH
N-Tripleエンコーディングが使用されます。(N-Tripleエンコーディングの詳細は、http://www.w3.org/TR/rdf-testcases/#ntrip_grammar
を参照してください。)SPARQL問合せの通常リソースのエンコーディングは、同じように処理されます。
\uHHHH
N-Tripleエンコーディングを使用することによって、サポートされるUnicodeキャラクタ・セットがOracle Databaseで使用されていない場合でも、国際的な文字(ノルウェー語とスウェーデンの文字の混在など)のサポートが可能になります。
親トピック: SPARQLサービスの設定
6.3 動的なSPARQLエンドポイントの設定
動的なSPARQL Webサービス・エンドポイントを、Apache Jena JosekiおよびApache Jena Fusekiを使用して設定できます。
動的なSPARQLエンドポイントにより、SPARQL問合せと更新サービスが拡張されて、操作の対象が構成ファイルで明示的に指定されたグラフやモデルの範囲を超えて拡大されます。このようにして、SPARQLサービスでは、更新された構成を再起動によって構成ファイルから読み取る必要がありません。RDFセマンティク・グラフの動的なSPARQLエンドポイントの機能は、物理的モデル、仮想モデル、ハイブリッド・グラフおよびRDB2RDFで動作します。
動的なSPARQLエンドポイントによるアクセスを、権限の与えられたグラフに限定するために、SPARQLサービスの構成ファイルにブラックリストまたはホワイトリストを入力しておくことができます。ブラックリストまたはホワイトリストの入力値は、Javaの正規表現を用いて定義されたパターンの集まりで、パターンには、動的なSPARQLエンドポイントの使用でアクセスが禁止または許可されるモデル名のリストが指定されています。このようにして、ホワイトリストにあるパターンの少なくとも1つに一致し、なおかつブラックリストには一致するパターンがない名前のモデルのみが、動的なSPARQLエンドポイントでアクセスできるようになります。
値が、ブラックリストとホワイトリストの両方で指定されている場合、ブラックリストの値が優先されます。具体的には、次のとおりです。
-
モデル名がブラックリストのパターンと一致する場合は、アクセス対象外です。
-
モデル名が、ブラックリストにあるいずれのパターンにも一致しないものの、ホワイトリストのいずれのパターンにも一致しない場合、そのモデル名はアクセスの対象外です。
-
モデル名がブラックリストにあるいずれのパターンにも一致せず、なおかつホワイトリストにある1つ以上のパターンに一致する場合、そのモデルはアクセス対象になります。
6.3.1 動的なSPARQLエンドポイントのFusekiサーバーでの構成
Fusekiで動的なSPARQLエンドポイントを構成するには、config-oracle.ttl
ファイルで、2つの新規サービスを定義する必要があります。1つはSPARQL問合せに対するoracle/model/*
、もう1つはSPARQL更新に対するoracle/updatemodel/*
です。この2つのサービスは、動的なSPARQL Webサービス・エンドポイントでモデルへアクセスする際に使用されます。さらに、グラフ(モデル)名との照合に使用されるブラックリストおよびホワイトリストのパターンを定義する必要があります。
ここで述べたサービスとリスト・パターンを追加するには、次のようにします。
-
Fusekiサーバーを停止します。
-
追加のトリプルを、
model/*
サービスおよびupdatemodel/*
サービスとともに、config-oracle.ttl
構成ファイルのサービス記述部に挿入します。該当部分は次のようになります。<#service1> rdf:type fuseki:Service ; ... # Dynamic SPARQL Endpoint Query service fuseki:serviceQuery "model/*" ; ... # Dynamic SPARQL Endpoint Update service fuseki:serviceUpdate "updatemodel/*" ; ... fuseki:dataset <#oracle> ; .
-
モデル名に対する照合が行われるブラックリストおよびホワイトリストのパターンを定義します。パターンを構成するには、述語
oracle:blackListRegex
およびoracle:whiteListRegex
を持つトリプルを、config-oracle.ttl
ファイルに挿入します。次に示す断片は、動的なSPARQLエンドポイントによるアクセスの際に、名前に「nice」、「ok」または「showme」を含み、「forbidden」も「secret」も含まないモデルへのアクセスのみを許すパターンの例です。<#oracle> oracle:blackListRegex ".*forbidden.*"; oracle:blackListRegex ".*secret.*"; oracle:whiteListRegex ".*ok.*" ; oracle:whiteListRegex ".*nice.*" ; oracle:whiteListRegex ".*showme.*" .
-
Fusekiサーバーを再起動します。
このように構成を追加することで、構成ファイルのデータセット記述部で明示的に定義されていなくても、ホワイトリストとブラックリストのパターンで許可されているかぎり、mynicegraph
というモデルへ、次のようなURLでSPARQL問合せによりアクセスできるようになりました。
http://<hostname:port>/oracle/model/mynicegraph
SPARQL更新の場合は、次のようなURLを使用します。
http://<hostname:port>/oracle/updatemodel/mynicegraph
親トピック: 動的なSPARQLエンドポイントの設定
6.3.2 動的なSPARQLエンドポイントのJosekiサーブレットでの構成
Josekiで動的なSPARQLエンドポイントを構成するには、joseki-config.ttl
ファイルで、2つの新規サービスを定義する必要があります。1つはSPARQL問合せに対するoracle/model/*
、もう1つはSPARQL更新に対するoracle/updatemodel/*
です。この2つのサービスは、動的なSPARQL Webサービス・エンドポイントでモデルへアクセスする際に使用されます。さらに、グラフ(モデル)名との照合に使用されるブラックリストおよびホワイトリストのパターンを定義する必要があります。
ここで述べたサービスとリスト・パターンを追加するには、次のようにします。
-
Josekiサービスが実行されているWebサーバーを停止します。
-
joseki.war
ファイルから、joseki-config.ttl
ファイルを一時保存場所に抽出します。たとえば、次のようにします。cd /tmp/jena_adapter/war cp <your_directory>/joseki.war /tmp/jena_adapter/war/ jar -xf joseki.war WEB-INF/classes/joseki-config.ttl
-
Josekiで動的なSPARQL問合せサービスを構成するには、すでに定義されているサービス同様、主語<#serviceDynamicQuery>および<#serviceDynamicUpdate>の付いたトリプルの集まりを、構成ファイルjoseki-config.ttlに含めます。
それらのトリプルで、サービスoracle/model/*およびoracle/updatemodel/*が定義されます。述語joseki:serviceRefは、oracle/model/* SPARQLサービス・エンドポイントで問合せが、oracle/updatemodel/* SPARQLサービス・エンドポイントで更新が、それぞれURLエンコーディングのモデル名を使用して行われることを示しています。動的SPARQL問合せサービスの記述部分は、次のようになります。
# Dynamic SPARQL Query Service <#serviceDynamicQuery> rdf:type joseki:Service ; rdfs:label "model SPARQL with Oracle Semantic Data Management" ; joseki:serviceRef "oracle/model/*" ; # web.xml must route this name to Joseki # dataset part joseki:dataset <#oracle> ; # Service part. # This processor will not allow either the protocol, # nor the query, to specify the dataset. Joseki:processor joseki:ProcessorSPARQL_FixedDS ; .
動的SPARQL更新サービスの記述部分は、次のようになります。
# Dynamic SPARQL Update Service <#serviceDynamicUpdate> rdf:type joseki:Service ; rdfs:label "SPARQL/Update" ; joseki:serviceRef "oracle/updatemodel/*" ; # dataset part joseki:dataset <#oracle>; # Service part. # This processor will not allow either the protocol, # nor the query, to specify the dataset. joseki:processor joseki:ProcessorSPARQLUpdate .
-
モデル名に対する照合が行われるブラックリストおよびホワイトリストのパターンを定義します。パターンを構成するには、述語
oracle:blackListRegex
およびoracle:whiteListRegex
を持つトリプルを、joseki-config.ttl
ファイルに挿入します。次に示す断片は、動的なSPARQLエンドポイントによるアクセスの際に、名前に単語「cool」または「good」を含み、「banned」も「test」も含まないモデルへのアクセスのみを許すパターンの例です。動的な問合せまたは更新で、ユーザーがこれ以外のモデルにアクセスしようとすると、モデルが利用できないことを示すエラー・メッセージが返されます。
<#oracle> oracle:blackListRegex ".*banned.*"; oracle:blackListRegex ".*test.*"; oracle:whiteListRegex ".*cool.*" ; oracle:whiteListRegex ".*good.*" .
-
warファイルの
.ttl
構成ファイルを更新します。たとえば、次のようにします。jar -uf joseki.war WEB-INF/classes/joseki-config.ttl
-
joseki.war
ファイルから、Web記述子ファイルを一時保存場所に抽出します。たとえば、次のようにします。cd /tmp/jena_adapter/war/ jar -xf joseki.war WEB-INF/web.xml
-
URL経路
model/*
およびupdatemodel/*
を、Web記述子でJosekiサーブレットにマッピングします。サーブレットへの新規マッピングをweb.xml
ファイルに挿入します。サーブレットをマッピングする部分は、次のようになります。... <servlet> <servlet-name>SPARQL service processor</servlet-name> <servlet-class>org.joseki.http.Servlet</servlet-class> <init-param> <param-name>org.joseki.rdfserver.config</param-name> <param-value>joseki-oracle-config.ttl</param-value> </init-param> </servlet> ... <servlet> <servlet-name>SPARQL/Update service processor</servlet-name> <servlet-class>org.joseki.http.ServletUpdate</servlet-class> <init-param> <param-name>org.joseki.rdfserver.config</param-name> <param-value>joseki-oracle-config.ttl</param-value> </init-param> </servlet> ... <servlet-mapping> <servlet-name>SPARQL service processor</servlet-name> <url-pattern>/oracle/model/*</url-pattern> </servlet-mapping> ... <servlet-mapping> <servlet-name>SPARQL/Update service processor</servlet-name> <url-pattern>/oracle/updatemodel/*</url-pattern> </servlet-mapping> ...
-
warファイルのWeb記述子ファイルを更新します。たとえば、次のようにします。
jar -uf joseki.war web.xml
-
joseki.war
ファイルを、同じJ2EEコンテナに再度デプロイします。
このように構成を追加することで、構成ファイルのデータセット記述部で明示的に定義されていなくても、ホワイトリストとブラックリストのパターンで許可されているかぎり、mycoolgraph
というモデルへ、次のようなURLでSPARQL問合せによりアクセスできるようになりました。
http://<hostname:port>/joseki/oracle/model/mycoolgraph
SPARQL更新の場合は、次のようなURLを使用します。
http://<hostname:port>/joseki/oracle/updatemodel/mycoolgraph
親トピック: 動的なSPARQLエンドポイントの設定
6.4 Josekiサーブレットへのクロスサイト・リクエスト・フォージェリ(CSRF)に対する防御の追加
クロスサイト・リクエスト・フォージェリ(CSRF)を、Josekiサーブレットへ追加できます。
クロスサイト・リクエスト・フォージェリ(CSRF、あるいはXSRFと呼ばれることもあります)攻撃は、不正な無作為のリクエストをWebサイトに送信する悪用の一種です。こうした不正なリクエストは、認証済のユーザーまたはWebサイトで信頼されているユーザーから送られてくるため、正当なリクエストと区別する方法がありません。この種の攻撃は、ワンクリック攻撃またはセッション・ライディングとしても知られており、WebアプリケーションでSSL暗号化(HTTPS)が使用されていても発生することがあります。
Oracle Spatial and Graph RDFセマンティク・グラフでは、Double Submit Cookieパターンの実装により、JosekiサーブレットへのCSRF攻撃に対する防御が可能になっています。このセキュリティ・パターンにより、セキュリティ・トークンがパラメータとしてリクエストに含まれていて、なおかつこのセキュリティ・トークンが、アプリケーションにより使用され設定されたクッキーで指定されているトークンと一致する場合にのみ、更新リクエストが受け付けられるようになります。旧リリースとの互換性を確保するため、CSRFに対する防御は、デフォルトでは有効化されていません。
Double Submit Cookieパターンを実装するアプリケーションは、セキュリティ・トークンを生成し、それをCookieに値として設定する必要があります。RDFセマンティク・グラフの実装では、このタスクはサーブレットorg.joseki.http.CookieTokenSetter
により実行されます。同様に、CSRF攻撃に対する防御が行われているアプリケーションにリクエストを送るクライアントは、Cookieからこの値を取得し、追加のパラメータとしてリクエストに設定する必要があります。RDFセマンティク・グラフの機能では、 update.html
ファイルのJavaScriptを使用して、サーバーに有効なリクエストを送るための特別なパラメータとして、_RDF_AUTH_TOKEN_HIDDEN
が使用されています。
6.4.1 クロスサイト・リクエスト・フォージェリに対する防御を追加するためのJosekiサーバーの構成
JosekiサービスでJosekiサーブレットへのクロスサイト・リクエスト・フォージェリ(CSRF)に対する防御を有効にするには、次のようにします。
-
Josekiサービスが実行されているWebサーバーを停止します。
-
joseki.war
ファイルから、Web記述子ファイルを一時保存場所に抽出します。たとえば、次のようにします。cd /tmp/jena_adapter/war jar -xf joseki.war WEB-INF/web.xml
-
Web記述子に、サーブレット
org.joseki.http.CookieTokenSetter
を指定します。このサーブレットにより、CSRF攻撃からSPARQLエンドポイントを防御するランダムなセキュリティ・トークンが生成されます。ファイルweb.xml
には次のような短いコードが含まれている必要があります。<!-- RDF AUTH TOKEN COOKIE --> <servlet> <servlet-name>OracleRdfCookieTokenSetter</servlet-name> <servlet-class>org.joseki.http.CookieTokenSetter</servlet-class> </servlet> ... <servlet-mapping> <servlet-name>OracleRdfCookieTokenSetter</servlet-name> <url-pattern>/oracle/getCookie</url-pattern> </servlet-mapping>
-
warファイルのWeb記述子ファイルを更新します。たとえば、次のようにします。
jar -uf joseki.war WEB-INF/web.xml
-
joseki.warファイルを、同じJ2EEコンテナに再度デプロイします。
-
Joseki SPARQLサービスを実行する前に、Javaプロパティ
oracle.spatial.rdf.client.jena.enableCsrfProtection
を有効にします。-Doracle.spatial.rdf.client.jena.enableCsrfProtection=true
-
サーバーをもう一度、再起動します。CSRF攻撃に対し、Josekiサービスが防御されるようになります。
http://hostname:port/joseki/oracle/getCookie
「クロスサイト・リクエスト・フォージェリに対する防御を追加するためのJosekiクライアントの構成」には、このトークンの取得方法と使用方法が述べられています。
6.4.2 クロスサイト・リクエスト・フォージェリに対する防御を追加するためのJosekiクライアントの構成
CSRFから防御されたJosekiサービスに対して有効なリクエストを送るには、クライアント・アプリケーションにもいくつか追加の構成を行う必要があります。
ここでは、防御されているJosekiサーバーへ有効なリクエストを送るクライアント・アプリケーションの構成と使用について、その手順の一例を説明します。セキュリティ・トークンが_RDF_AUTH_TOKEN_HIDDEN
パラメータで、なおかつCookieで送られているかぎりは、その他の方法を用いることもできます。なお、例として示すこの手順で、クライアント・アプリケーションは、実際には単純なSPARQL更新インタフェースを持つHTMLページです。また、このクライアント・アプリケーションは、同じjoseki.war
ファイルでバンドルされています。
-
Josekiが実行されているWebサーバーを停止します。
-
joseki.war
ファイルから、update.html
ファイルを一時保存場所に抽出します。たとえば、次のようにします。cd /tmp/jena_adapter/war jar -xf joseki.war update.html
-
ファイルupdate.htmlを編集して、submitによる入力の部分を削除し、カスタムのJavaScript関数を呼び出すボタンによる入力に置き換えます。ファイルには、次のような短いコードが含まれている必要があります。
<form id=" formSPARQLUpdate" action="update/service" method="post"> <p>Type in your SPARQL/Update request</p> <p> <textarea style="background-color: #F0F0F0;" name="request" cols="70" rows="20"></textarea> <br/> <input type="hidden" name="_RDF_AUTH_TOKEN_HIDDEN" id="_RDF_AUTH_TOKEN_HIDDEN" value=""/> <!-- <input type="submit" value="Perform SPARQL Update" /> --> <input type="button" value="Perform SPARQL Update" onclick=" postSPARQLUpdate()"> </p> </form>
-
スクリプトを、JosekiサーブレットにPOSTリクエストを送るカスタム関数とともに、
update.html
ファイルに追加します。この関数によって、セキュリティ・トークンがCookieの値から読み取られ、_RDF_AUTH_TOKEN_HIDDEN
パラメータとして、リクエスト送信前に設定される必要があります。スクリプトには、次のような短いコードが含まれている必要があります。<script type="text/javascript"> function postSPARQLUpdate() { var form = document.getElementById("formSPARQLUpdate"); var token = getCookie('RDF_AUTH_TOKEN_COOKIE'); document.getElementById('_RDF_AUTH_TOKEN_HIDDEN').value = token; form.submit(); } function getCookie(cname) { var name = cname + "="; var ca = document.cookie.split(';'); for(var i=0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1); if (c.indexOf(name) == 0) return c.substring(name.length,c.length); } return ""; } </script>
-
warファイルの
update.html
ファイルを更新します。たとえば、次のようにします。jar -uf joseki.war update.html
-
joseki.war
ファイルを、選択したJ2EEコンテナに再度デプロイします。 -
Webサーバーを再起動します。
この修正により、Josekiの単純なSPARQL更新クライアント・アプリケーションで、CSRFから防御されたJosekiサービスを、次に示すWebサイトで正しく使用できるようになります。(なお、必要に応じて異なるクライアントの実装と使用が可能です。)
http://hostname:port/joseki/update.html
6.5 RDFセマンティク・グラフ環境の設定
RDFセマンティク・グラフ環境が要件をすでに満たしている場合は、support for Apache Jenaを使用するJavaコードを直接コンパイルして実行することができます。support for Apache Jenaを使用できるようにRDFセマンティク・グラフ環境を設定していない場合は、次の例のようなステップを実行します。
6.6 SEM_MATCHおよびRDF Semantic Graph support for Apache Jenaの問合せの比較
Oracle Databaseに格納されているセマンティク・データを問い合せる方法は2つあります。SEM_MATCHベースのSQL文とsupport for Apache Jenaを介したSPARQL問合せです。
それぞれの方法での問合せは、表面的には類似していますが、動作には重要な違いがあります。アプリケーションの動作を一貫性のあるものにするには、SEM_MATCH問合せとSPARQL問合せの違いを理解し、その問合せ結果を処理する際に注意が必要です。
2つの方法を次の簡単な例で示します。
問合せ1 (SEM_MATCHベース)
select s, p, o from table(sem_match('{?s ?p ?o}', sem_models('Test_Model'), ....))
問合せ2 (support for Apache Jenaを介したSPARQL問合せ)
select ?s ?p ?o where {?s ?p ?o}
これらの2つの問合せは、同じ種類の機能を実行しますが、いくつか重要な違いがあります。問合せ1 (SEM_MATCHベース)は次のようになります。
-
Test_Model
からすべてのトリプルを読み取ります。 -
URI、bNode、プレーン・リテラルおよび型付きリテラルを区別せず、長いリテラルを処理しません。
-
特定の文字(
'\n'
など)はエスケープ解除しません。
問合せ2 (support for Apache Jenaを介して実行されるSPARQL問合せ)もTest_Model
からすべてのトリプルを読み取ります(同じ基礎となるTest_Model
を参照しているModelOracleSem
に対してコールを実行したと想定します)。ただし、問合せ2は次のようになります。
-
(SEM_MATCH表関数による、
s
、p
およびo
列のみではなく)追加の列を読み取り、URI、bNodes、プレーン・リテラル、型付きリテラルおよび長いリテラルを区別します。これによって、Jena Nodeオブジェクトを適切に作成できるようになります。 -
Oracle Databaseに格納される際にエスケープされる文字をエスケープ解除します。
2つの方法でのもう1つの違いは、空白ノード処理です。
-
SEM_MATCHベースの問合せにおいて、空白ノードは常に定数とみなされます。
-
SPARQL問合せにおいて、
<
と>
で囲まれていない 空白ノードは、問合せがSupport for Apache Jenaを介して実行されるときに変数とみなされます。これは、SPARQL標準セマンティクと一致します。ただし、<と>
で囲まれた
空白ノードは、問合せが実行されるときに定数とみなされ、空白ノード・ラベルには、基礎となるデータのモデル化で必要とされる適切な接頭辞が、support for Apache Jenaによって追加されます。
support for Apache Jena APIを使用して作成されるセマンティク・モデルの名前の最大長は、22文字です。
6.7 SEM_MATCHまたはSQLベースの問合せ結果からのユーザーフレンドリJavaオブジェクトの取得
セマンティク・グラフの問合せは、次のいずれかの方法を用いて行うことができます。
-
SPARQL (JavaメソッドまたはWebサービス・エンドポイントを使用)
-
SEM_MATCH (SPARQL問合せを埋め込んだ表関数)
-
SQL (MDSYS.RDFM_<model>ビューを問い合せて、MDSYS.RDF_VALUE$や他の表と結合)
Java開発者が使用しやすいのは、最初の方法の結果です。2番目と3番目の方法の結果はJava開発者にとっては使用しにくいかもしれません。型付きRDFリテラルとマッピングされた適切な型付きJavaオブジェクトを取得するために、様々な列を解析する必要があるためです。RDF Semantic Graph support for Apache Jenaは、JDBC結果セットから適切な型付きJavaオブジェクトを取得するタスクを簡略化できるように、いくつかのメソッドとヘルパー関数をサポートしています。これらのメソッドとヘルパー関数を次の例に示します。
これらの例は、次のコードのように一連の型付きリテラルが追加されるテスト表TGRAPH_TPLを使用しています(また、それに基づいてTGRAPHをモデル化しています)。
create table tgraph_tpl(triple sdo_rdf_triple_s); exec sem_apis.create_sem_model('tgraph','tgraph_tpl','triple'); truncate table tgraph_tpl; -- Add some triples insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph','<urn:s1>','<urn:p1>', '<urn:o1>')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph','<urn:s2>','<urn:p2>', '"hello world"')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph','<urn:s3>','<urn:p3>', '"hello world"@en')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph','<urn:s4>','<urn:p4>', '" o1o "^^<http://www.w3.org/2001/XMLSchema#string>')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph','<urn:s4>','<urn:p4>', '"xyz"^^<http://mytype>')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph','<urn:s5>','<urn:p5>', '"123"^^<http://www.w3.org/2001/XMLSchema#integer>')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph','<urn:s5>','<urn:p5>', '"123.456"^^<http://www.w3.org/2001/XMLSchema#double>')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph','<urn:s6>','<urn:p6>', '_:bn1')); -- Add some quads insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph:<urn:g1>','<urn:s1>','<urn:p1>', '<urn:o1>')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s1>','<urn:p1>', '<urn:o1>')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s2>','<urn:p2>', '"hello world"')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s3>','<urn:p3>', '"hello world"@en')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s4>','<urn:p4>', '" o1o "^^<http://www.w3.org/2001/XMLSchema#string>')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s4>','<urn:p4>', '"xyz"^^<http://mytype>')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s5>','<urn:p5>', '"123"^^<http://www.w3.org/2001/XMLSchema#integer>')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s5>','<urn:p5>', '"123.456"^^<http://www.w3.org/2001/XMLSchema#double>')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s6>','<urn:p6>', '_:bn1')); insert into tgraph_tpl values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s7>','<urn:p7>', '"2002-10-10T12:00:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime>'));
例6-1 SQLベースのグラフ問合せ
例6-1では、純粋なSQLベースのグラフ問合せを実行して、Jenaオブジェクトを作成します。
iTimeout = 0; // no time out iDOP = 1; // degree of parallelism iStartColPos = 2; queryString = "select 'hello'||rownum as extra, o.VALUE_TYPE,o.LITERAL_TYPE,o.LANGUAGE_TYPE,o.LONG_VALUE,o.VALUE_NAME " + " from mdsys.rdfm_tgraph g, mdsys.rdf_value$ o where g.canon_end_node_id = o.value_id"; rs = oracle.executeQuery(queryString, iTimeout, iDOP, bindValues); while (rs.next()) { node = OracleSemIterator.retrieveNodeFromRS(rs, iStartColPos, OracleSemQueryPlan.CONST_FIVE_COL, translator); System.out.println("Result " + node.getClass().getName() + " = " + node + " " + rs.getString(1)); }
例6-1では、次のような出力が生成されます。
Result com.hp.hpl.jena.graph.Node_URI = urn:o1 hello1 Result com.hp.hpl.jena.graph.Node_URI = urn:o1 hello2 Result com.hp.hpl.jena.graph.Node_Literal = "hello world" hello3 Result com.hp.hpl.jena.graph.Node_Literal = "hello world"@en hello4 Result com.hp.hpl.jena.graph.Node_Literal = " o1o " hello5 Result com.hp.hpl.jena.graph.Node_Literal = "xyz" hello6 Result com.hp.hpl.jena.graph.Node_Literal = "123"^^http://www.w3.org/2001/XMLSchema#decimal hello7 Result com.hp.hpl.jena.graph.Node_Literal = "1.23456E2"^^http://www.w3.org/2001/XMLSchema#double hello8 Result com.hp.hpl.jena.graph.Node_Blank = m8g3C75726E3A67323Egmbn1 hello9 Result com.hp.hpl.jena.graph.Node_Literal = "2002-10-10T17:00:00Z"^^http://www.w3.org/2001/XMLSchema#dateTime hello10 Result com.hp.hpl.jena.graph.Node_Literal = "1.23456E2"^^http://www.w3.org/2001/XMLSchema#double hello11 Result com.hp.hpl.jena.graph.Node_URI = urn:o1 hello12 Result com.hp.hpl.jena.graph.Node_Literal = "hello world" hello13 Result com.hp.hpl.jena.graph.Node_Literal = "hello world"@en hello14 Result com.hp.hpl.jena.graph.Node_Literal = " o1o " hello15 Result com.hp.hpl.jena.graph.Node_Literal = "xyz" hello16 Result com.hp.hpl.jena.graph.Node_Literal = "123"^^http://www.w3.org/2001/XMLSchema#decimal hello17 Result com.hp.hpl.jena.graph.Node_Blank = m8mbn1 hello18
例6-2 SEM_MATCHと標準SQL構成要素が混在するハイブリッド問合せ
例6-2は、OracleSemIterator.retrieveNodeFromRS
APIを使用してJenaオブジェクトを作成します。連続した5個の列を(値タイプ、リテラル・タイプ、言語タイプ、ロング値、値名の順序どおりに)読み取り、必要なエスケープ解除とオブジェクトのインスタンス化を実行します。この例では、SEM_MATCHを省いて、グラフ・ビューをMDSYS.RDF_VALUE$と直接結合しています。
iStartColPos = 1; queryString = "select g$RDFVTYP, g, count(1) as cnt " + " from table(sem_match('{ GRAPH ?g { ?s ?p ?o . } }',sem_models('tgraph'),null,null,null,null,null)) " + " group by g$RDFVTYP, g"; rs = oracle.executeQuery(queryString, iTimeout, iDOP, bindValues); while (rs.next()) { node = OracleSemIterator.retrieveNodeFromRS(rs, iStartColPos, OracleSemQueryPlan.CONST_TWO_COL, translator); System.out.println("Result " + node.getClass().getName() + " = " + node + " " + rs.getInt(iStartColPos + 2)); }
例6-2では、次のような出力が生成されます。
Result com.hp.hpl.jena.graph.Node_URI = urn:g2 9 Result com.hp.hpl.jena.graph.Node_URI = urn:g1 1
次に、例6-2について説明します。
-
Oracle
クラスのヘルパー関数executeQuery
がSQL文の実行に使用され、OracleSemIterator.retrieveNodeFromRS
API (例6-1でも使用)がJenaオブジェクトの作成に使用されます。 -
出力では2つの列、値タイプ(g$RDFVTYP)と値名(g)のみが使用されます。このg変数は決してリテラルRDFリソースにはならないことが明らかです。
-
列の順序は重要です。2列からなる変数の場合、最初の列が値タイプ、2番目の列が値名であることが必要です。
例6-3 SEM_MATCH問合せ
例6-3は、SEM_MATCH問合せを実行し、Jenaオブジェクトのリストを返すイテレータ(OracleSemIterator
のインスタンス)を返します。
queryString = "select g$RDFVTYP, g, s$RDFVTYP, s, p$RDFVTYP, p, o$RDFVTYP,o$RDFLTYP,o$RDFLANG,o$RDFCLOB,o " + " from table(sem_match('{ GRAPH ?g { ?s ?p ?o . } }',sem_models('tgraph'),null,null,null,null,null))"; guide = new ArrayList<String>(); guide.add(OracleSemQueryPlan.CONST_TWO_COL); guide.add(OracleSemQueryPlan.CONST_TWO_COL); guide.add(OracleSemQueryPlan.CONST_TWO_COL); guide.add(OracleSemQueryPlan.CONST_FIVE_COL); rs = oracle.executeQuery(queryString, iTimeout, iDOP, bindValues); osi = new OracleSemIterator(rs); osi.setGuide(guide); osi.setTranslator(translator); while (osi.hasNext()) { result = osi.next(); System.out.println("Result " + result.getClass().getName() + " = " + result); }
例6-3では、次のような出力が生成されます。
Result com.hp.hpl.jena.graph.query.Domain = [urn:g1, urn:s1, urn:p1, urn:o1] Result com.hp.hpl.jena.graph.query.Domain = [urn:g2, urn:s1, urn:p1, urn:o1] Result com.hp.hpl.jena.graph.query.Domain = [urn:g2, urn:s2, urn:p2, "hello world"] Result com.hp.hpl.jena.graph.query.Domain = [urn:g2, urn:s3, urn:p3, "hello world"@en] Result com.hp.hpl.jena.graph.query.Domain = [urn:g2, urn:s4, urn:p4, " o1o "] Result com.hp.hpl.jena.graph.query.Domain = [urn:g2, urn:s4, urn:p4, "xyz"] Result com.hp.hpl.jena.graph.query.Domain = [urn:g2, urn:s5, urn:p5, "123"^^http://www.w3.org/2001/XMLSchema#decimal] Result com.hp.hpl.jena.graph.query.Domain = [urn:g2, urn:s5, urn:p5, "1.23456E2"^^http://www.w3.org/2001/XMLSchema#double] Result com.hp.hpl.jena.graph.query.Domain = [urn:g2, urn:s6, urn:p6, m8g3C75726E3A67323Egmbn1] Result com.hp.hpl.jena.graph.query.Domain = [urn:g2, urn:s7, urn:p7, "2002-10-10T17:00:00Z"^^http://www.w3.org/2001/XMLSchema#dateTime]
次に、例6-3について説明します。
-
OracleSemIterator
がJDBC結果セットを取得します。OracleSemIterator
には、SPARQL変数のバインド値を表すすべての列を解析するためのガイダンスが必要です。ガイドは単純な文字列値のリストです。2列の変数(主語と述語の位置)と5列の変数(目的語の位置)を区別する2つの定数が定義されています。トランスレータも必要です。 -
出力では4つの変数が使用されます。最初の3つの変数はRDFリテラル・リソースではないため、CONST_TWO_COLがガイドとして使用されます。最後の変数はRDFリテラル・リソースになることができます。したがって、CONST_FIVE_COLがガイドとして使用されます。
-
列の順序が重要です。例のとおりにする必要があります。
6.8 SPARQL問合せ処理の最適化
この項では、SPARQL問合せ処理を強化できる、support for Apache Jenaのいくつかのパフォーマンス関連機能について説明します。これらの機能は、デフォルトでは自動的に実行されます。
ここでは、CONSTRUCT機能およびプロパティ・パスなど、SPARQLについての知識があることを前提としています。
6.8.1 単一のSEM_MATCHコールへのSPARQL問合せのコンパイル
DISTINCT、OPTIONAL、FILTER、UNION、ORDER BYおよびLIMITを含むSPARQL問合せは、単一のOracle SEM_MATCH表関数に変換されます。SEM_MATCHでサポートされないSPARQL機能(CONSTRUCTなど)を使用しているために、問合せを直接SEM_MATCHに変換できない場合、support for Apache Jenaは、ハイブリッドな方法を採用し、単一のSEM_MATCH関数を使用して問合せの最も大きな部分を実行しながら、Jena ARQ問合せエンジンを使用して残りの部分の実行を試みます。
たとえば、次のSPARQL問合せは、単一のSEM_MATCH表関数に直接変換されます。
PREFIX dc: <http://purl.org/dc/elements/1.1/> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT ?person ?name WHERE { {?alice foaf:knows ?person . } UNION { ?person ?p ?name. OPTIONAL { ?person ?x ?name1 } } }
一方、次の問合せ例は、CONSTRUCTキーワードのため、単一のSEM_MATCH表関数に直接変換できません。
PREFIX vcard: <http://www.w3.org/2001/vcard-rdf/3.0#> CONSTRUCT { <http://example.org/person#Alice> vcard:FN ?obj } WHERE { { ?x <http://pred/a> ?obj.} UNION { ?x <http://pred/b> ?obj.} }
この場合、support for Apache Jenaは、内側のUNION問合せを単一のSEM_MATCH表関数に変換し、その結果セットをさらに評価するため、Jena ARQ問合せエンジンに渡します。
親トピック: SPARQL問合せ処理の最適化
6.8.2 プロパティ・パスの処理の最適化
Jenaに定義されているとおり、プロパティ・パスは2つのグラフ・ノード間でRDFグラフを介して使用可能なルートです。プロパティ・パスはSPARQLの拡張機能であり、RDFグラフのパターン・マッチングでプロパティに正規表現を使用できるため、基本的なグラフ・パターン問合せよりも表現力が豊かです。プロパティ・パスの詳細は、Jena ARQ問合せエンジンのドキュメントを参照してください。
support for Apache Jenaは、Jena ARQ問合せエンジンとの統合によって、すべてのJenaプロパティ・パス・タイプをサポートしますが、いくつかの一般的なパス・タイプは、パフォーマンスを向上するため、ネイティブSQL階層問合せ(SEM_MATCHベースではない)に直接変換されます。次のタイプのプロパティ・パスは、トリプル・データを処理する際、support for Apache JenaによってSQLに直接変換されます。
-
述語選択肢: (p1 | p2 | … | pn) piはプロパティURIです。
-
述語順序: (p1 / p2 / … / pn) piはプロパティURIです。
-
逆パス: ( ^ p ) pは述語URIです。
-
複雑なパス: p+、p*、p{0, n} pは選択肢、順序、逆パスまたはプロパティURIです。
この文法で対応できないパス表現は、support for Apache JenaによってSQLに直接変換することができず、Jena問合せエンジンを使用して応答されます。
次の例では、パス順序を使用したプロパティ・パス表現を使用するコード・スニペットが含まれます。
String m = "PROP_PATH"; ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle, m); GraphOracleSem graph = new GraphOracleSem(oracle, m); // populate the RDF Graph graph.add(Triple.create(Node.createURI("http://a"), Node.createURI("http://p1"), Node.createURI("http://b"))); graph.add(Triple.create(Node.createURI("http://b"), Node.createURI("http://p2"), Node.createURI("http://c"))); graph.add(Triple.create(Node.createURI("http://c"), Node.createURI("http://p5"), Node.createURI("http://d"))); String query = " SELECT ?s " + " WHERE {?s (<http://p1>/<http://p2>/<http://p5>)+ <http://d>.}"; QueryExecution qexec = QueryExecutionFactory.create(QueryFactory.create(query, Syntax.syntaxARQ), model); try { ResultSet results = qexec.execSelect(); ResultSetFormatter.out(System.out, results); } finally { if (qexec != null) qexec.close(); } OracleUtils.dropSemanticModel(oracle, m); model.close();
親トピック: SPARQL問合せ処理の最適化
6.9 他の機能をサポートするためのSPARQL構文への追加
RDF Semantic Graph support for Apache Jenaでは、ヒントと追加の問合せオプションを渡すことができます。問合せオプションを含むOracle固有の名前空間を使用してSPARQL名前空間接頭辞の構文をオーバーロードすることで、これらの機能を実装できます。
PREFIX ORACLE_SEM_
xx_NS
形式の名前空間では、xxの部分に機能の種別(ヒントならHT
、AP
なら追加の述語など)が表されています。
6.9.1 SQLヒント
SQLヒントは、次の形式の行を含むSEM_MATCH問合せに渡すことができます。
PREFIX ORACLE_SEM_HT_NS: <http://oracle.com/semtech#hint>
ここでのhintは、SEM_MATCHによってサポートされる任意のヒントです。たとえば、次のようにします。
PREFIX ORACLE_SEM_HT_NS: <http://oracle.com/semtech#leading(t0,t1)> SELECT ?book ?title ?isbn WHERE { ?book <http://title> ?title. ?book <http://ISBN> ?isbn }
この例で、t0,t1
は、問合せの1番目と2番目のパターンを指します。
SEM_MATCHと比較すると、ヒントの指定に若干違いがあることに注意してください。名前空間の値の構文の制限により、カンマ(,
)は空白ではなく、t0
とt1
(または他のヒント・コンポーネント)を区切るために使用されます。
SQLヒントの使用に関する詳細は、「SEM_MATCH表関数を使用したセマンティク・データの問合せ」を、特にoptions
属性でのHINT0
キーワードに関する資料を参照してください。
親トピック: 他の機能をサポートするためのSPARQL構文への追加
6.9.2 SPARQL問合せでのバインド変数の使用
Oracle Databaseでバインド変数を使用すると、問合せの解析時間を削減し、問合せ効率と同時実行性を向上させることができます。SPARQL問合せにおけるバインド変数のサポートは、ORACLE_SEM_FS_NSと同様の名前空間プラグマ指定を通して提供されます。
アプリケーションが2つのSPARQL問合せを実行する事例について考えます(2番目(問合せ2)は、1番目(問合せ1)の結果の一部または全部に応じて異なります)。バインド変数を必要としないいくつかの方法を次に示します。
-
問合せ1の結果を繰り返して、1組の問合せを生成します。(ただし、この方法は、問合せ1の結果の数と同数の問合せを必要とします。)
-
問合せ1の結果に基づいて、SPARQLフィルタ式を構築します。
-
問合せ1を副問合せとみなします。
この場合のもう1つの方法は、次のサンプル・シナリオのように、バインド変数を使用することです。
Query 1: SELECT ?x WHERE { ... <some complex query> ... }; Query 2: SELECT ?subject ?x WHERE {?subject <urn:related> ?x .};
次の例は、support for Apache Jenaでバインド変数を使用するための構文を含む問合せ2を示します。
PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#no_fall_back,s2s> PREFIX ORACLE_SEM_UEAP_NS: <http://oracle.com/semtech#x$RDFVID%20in(?,?,?)> PREFIX ORACLE_SEM_UEPJ_NS: <http://oracle.com/semtech#x$RDFVID> PREFIX ORACLE_SEM_UEBV_NS: <http://oracle.com/semtech#1,2,3> SELECT ?subject ?x WHERE { ?subject <urn:related> ?x };
この構文では、次の名前空間が使用されています。
-
ORACLE_SEM_UEAP_NSはORACLE_SEM_AP_NSと同様ですが、ORACLE_SEM_UEAP_NSの値の部分はURLエンコードされています。値の部分は、使用する前にURLデコードされている必要があり、それによってSPARQL問合せへの追加述語とみなされます。
この例では、URLデコーディングの後に、このORACLE_SEM_UEAP_NS接頭辞の値部分(
#
文字の後)が「x$RDFVID in(?,?,?)
」になります。3つの疑問符は、問合せ1の3つの値に対する暗黙的なバインディングを示します。 -
ORACLE_SEM_UEPJ_NSは、関係する追加の投影を指定します。この場合、ORACLE_SEM_UEAP_NSがx$RDFVID列(問合せのSELECT句には出現しません)を参照するため、指定する必要があります。複数の投影は、カンマで区切ります。
-
ORACLE_SEM_UEBV_NSは、最初にURLエンコードされ、次に連結されてカンマで区切られたバインド値のリストを指定します。
前述の問合せ例は、次の非SPARQL構文の問合せと概念的に同じであり、1、2および3はバインド値とみなされます。
SELECT ?subject ?x WHERE { ?subject <urn:related> ?x } AND ?x$RDFVID in (1,2,3);
前述の問合せ2のSPARQLの例で、3つの整数1、2および3は問合せ1からのものです。oext:build-uri-for-id
関数を使用して、そのような内部の整数IDをRDFリソースのために生成することができます。次の例は、問合せ1からの内部整数IDを取得します。
PREFIX oext: <http://oracle.com/semtech/jena-adaptor/ext/function#> SELECT ?x (oext:build-uri-for-id(?x) as ?xid) WHERE { ... <some complex query> ... };
?xid
の値は、<rdfvid:整数値>の形式です。アプリケーションは、山カッコと文字列rdfvid:を無視して整数値を取り出し、これらを問合せ2に渡します。
もう1つの例として、単一の問合せ構造だが、多数の異なる定数がある可能性がある場合について考えてみます。たとえば、次のSPARQL問合せは、趣味を持っており、アプリケーションにログインしている各ユーザーの趣味を検索します。アプリケーションのユーザーは異なるURIを使用して表現されるため、このSPARQL問合せに対して様々なユーザーから様々な<uri>値が提供されます。
SELECT ?hobby WHERE { <uri> <urn:hasHobby> ?hobby };
1つの方法(バインド変数を使用しない)は、異なる<uri>値ごとに異なるSPARQL問合せを生成することです。たとえば、ユーザーJane Doeが、次のSPARQL問合せの実行をトリガーするとします。
SELECT ?hobby WHERE { <http://www.example.com/Jane_Doe> <urn:hasHobby> ?hobby };
一方、もう1つの方法は、ユーザーJane Doeを指定している次の例のように、バインド変数を使用することです。
PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#no_fall_back,s2s> PREFIX ORACLE_SEM_UEAP_NS: <http://oracle.com/semtech#subject$RDFVID%20in(ORACLE_ORARDF_RES2VID(?))> PREFIX ORACLE_SEM_UEPJ_NS: <http://oracle.com/semtech#subject$RDFVID> PREFIX ORACLE_SEM_UEBV_NS: <http://oracle.com/semtech#http%3a%2f%2fwww.example.com%2fJohn_Doe> SELECT ?subject ?hobby WHERE { ?subject <urn:hasHobby> ?hobby };
前述の問合せ例は、次の非SPARQL構文の問合せと概念的に同じであり、http://www.example.com/Jane_Doe
はバインド変数とみなされます。
SELECT ?subject ?hobby WHERE { ?subject <urn:hasHobby> ?hobby } AND ?subject$RDFVID in (ORACLE_ORARDF_RES2VID('http://www.example.com/Jane_Doe'));
この例で、ORACLE_ORARDF_RES2VIDは、URIとリテラルを内部整数ID表現に変換する関数です。この関数が自動的に作成されるのは、Oracleデータベースに接続するためにsupport for Apache Jenaが使用されるときです。
親トピック: 他の機能をサポートするためのSPARQL構文への追加
6.9.3 追加のWHERE句述語
SEM_MATCH filter
属性に、WHEREキーワードのないWHERE句の形式の文字列として、追加の選択基準を指定することができます。次の形式の1行を含めることで、追加のWHERE句述語をSEM_MATCH問合せに渡すことができます。
PREFIX ORACLE_SEM_AP_NS: <http://oracle.com/semtech#pred>
predは、問合せに追加されるWHERE句の内容を反映します。たとえば、次のようにします。
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> PREFIX ORACLE_SEM_AP_NS:<http://www.oracle.com/semtech#label$RDFLANG='fr'> SELECT DISTINCT ?inst ?label WHERE { ?inst a <http://someCLass>. ?inst rdfs:label ?label . } ORDER BY (?label) LIMIT 20
この例では、ラベル変数の言語形式が'fr'
である必要がある問合せに、制限事項が追加されます。
親トピック: 他の機能をサポートするためのSPARQL構文への追加
6.9.4 追加の問合せオプション
追加の問合せオプションは、次の形式の行を含むSEM_MATCH問合せに渡すことができます。
PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#option>
optionは、問合せに追加される問合せオプション(またはカンマで区切られた複数の問合せオプション)を反映します。たとえば、次のようにします。
PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#timeout=3,dop=4,INF_ONLY,ORDERED,ALLOW_DUP=T> SELECT * WHERE {?subject ?property ?object }
次の問合せオプションがサポートされています。
-
ALLOW_DUP=t
は、結果が重複する場合がありますが、複数のセマンティク・モデルを問い合せるための、より高速な方法です。 -
BEST_EFFORT_QUERY=t
が、TIMEOUT=
n
オプションとともに使用されると、SPARQL問合せに対して、n秒以内に検出されるすべての一致が返されます。 -
DEGREE=
nは、問合せに対して並列度(n)を文レベルで指定します。マルチコアまたはマルチCPUのプロセッサで、異なるDOP
値(4または8など)を試すと、パフォーマンスが向上する場合があります。DEGREE
と比較すると、DOP
はセッション・レベルで並列度を指定します。DEGREE
はDOP
よりも処理オーバーヘッドが少ないため、support for Apache Jenaでの使用にはDEGREE
が推奨されます。 -
DOP=
nは、問合せに対して並列度(n)をセッション・レベルで指定します。マルチコアまたはマルチCPUのプロセッサで、異なるDOP
値(4または8など)を試すと、パフォーマンスが向上する場合があります。 -
INF_ONLY
を指定すると、推論されたモデルのみが問い合せられます。 -
JENA_EXECUTOR
は、SEM_MATCH (またはネイティブSQL)に対してSPARQL問合せのコンパイルを無効にし、かわりにJenaネイティブ問合せエグゼキュータが使用されます。 -
JOIN=
n
は、SPARQL SERVICEコールからフェデレーテッド問合せへの結果を、どのように問合せの他の部分と結合できるかを指定します。フェデレーテッド問合せとJOIN
オプションに関する詳細は、「JOINオプションとフェデレーテッド問合せ」を参照してください。 -
NO_FALL_BACK
は、SQL例外が発生したときに、基礎となる問合せ実行エンジンがJena実行メカニズムにフォール・バックしないようにします。 -
ODS=
n
は、動的なサンプリングのレベルを、文レベルで指定します。(動的なサンプリングの説明については、『Oracle Database SQLチューニング・ガイド』の動的なサンプリングによる統計の見積りに関する説明を参照してください。)nの有効値は、1から10までです。たとえば、複雑な問合せにはODS=3
を試すことができます。 -
ORDERED
は、最後に必要なRDF_VALUE$結合を実行している間、問合せトリプル・パターン結合のために主要なSQLヒントに変換されます。 -
PLAIN_SQL_OPT=F
は問合せを直接SQLにネイティブ・コンパイルする機能を無効にします。 -
QID=
nは、問合せID番号を指定します。この機能は、問合せに応答がない場合、その問合せを取り消すために使用できます。 -
RESULT_CACHE
は、問合せにOracle RESULT_CACHEディレクティブを使用します。 -
REWRITE=F
は、SEM_MATCH表関数に対してODCI_Table_Rewriteを無効にします。 -
S2S
(SPARQL to pure SQL)は、基礎となるSEM_MATCHベースの問合せ、またはSPARQL問合せに基づいて生成された問合せを、SEM_MATCH表関数を使用しないで、さらにSQL問合せに変換します。結果として生成されたSQL問合せはOracleコストベース・オプティマイザによって実行され、その結果はクライアントに渡される前にsupport for Apache Jenaによって処理されます。S2S
オプションの利点と使用方法などの詳細は、「S2Sオプションの利点と使用方法の情報」を参照してください。S2S
は、すべてのSPARQL問合せについてデフォルトで使用可能です。S2S
を無効にするには、次のJVMシステム・プロパティを設定します。-Doracle.spatial.rdf.client.jena.defaultS2S=false
-
SKIP_CLOB=T
は、問合せに対してCLOB値が戻されないようにします。 -
STRICT_DEFAULT=F
は、デフォルトのグラフがトリプルを名前付きグラフに含められるようにします。デフォルトでは、STRICT_DEFAULT=T
は、データセット情報が指定されない場合に、デフォルト・グラフを名前なしトリプルに制限します。 -
TIMEOUT=
n
(問合せタイムアウト)は、問合せが、終了されるまで実行する秒数(n)を指定します。SPARQL問合せから生成される基礎となるSQLは、多数の一致を戻し、副問合せおよび割当てと同様の機能を使用することができ、これらのすべてには、多くの時間がかかることがあります。TIMEOUT
とBEST_EFFORT_QUERY=t
オプションは、問合せに過度な処理時間がかからないようにするために使用できます。
6.9.4.1 JOINオプションとフェデレーテッド問合せ
SPARQLフェデレーテッド問合せは、W3Cドキュメントの説明のとおり、分散データ上の問合せであり、そのために、1つのソースを問い合せて、取得した情報を使用して次のソースの問合せを制約します。詳細は、『SPARQL 1.1フェデレーテッド問合せ』 (http://www.w3.org/2009/sparql/docs/fed/service
)を参照してください。
JOINオプション(「追加の問合せオプション」を参照)とSERVICEキーワードは、Support for Apache Jenaを使用するフェデレーテッド問合せで使用できます。たとえば、次の問合せを考えてみます。
SELECT ?s ?s1 ?o WHERE { ?s1 ?p1 ?s . { SERVICE <http://sparql.org/books> { ?s ?p ?o } } }
ローカルの問合せ部分(?s1 ?p1 ?s,
)が非常に選択的である場合、次の問合せに示すように、join=2
を指定します。
PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#join=2>
SELECT ?s ?s1 ?o
WHERE { ?s1 ?p1 ?s .
{
SERVICE <http://sparql.org/books> { ?s ?p ?o }
}
}
この場合、ローカルの問合せ部(?s1 ?p1 ?s,
)は、Oracle Databaseに対してローカルに実行されます。その後、結果からの?s
の各バインディングは、SERVICE部分(リモート問合せ部)にプッシュされ、コールはエンドポイントが指定したサービスに行われます。この方法は、概念的にはネステッド・ループ結合と似ています。
リモート問合せ部(?s ?s1 ?o
)が非常に選択的である場合、次の問合せに示すように、join=3
を指定することで、リモート部分は最初に実行され、結果はローカルの部分の実行をドライブするために使用されます。
PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#join=3>
SELECT ?s ?s1 ?o
WHERE { ?s1 ?p1 ?s .
{
SERVICE <http://sparql.org/books> { ?s ?p ?o }
}
}
この場合、単一のコールは遠隔サービス・エンドポイントに対して行われ、?s
の各バインディングは、ローカルの問合せをトリガーします。join=2
と同様に、この方法は概念的にはネステッド・ループベースの結合ですが、違いは順序が切り替えられるということです。
ローカルの問合せ部もリモートの問合せ部もあまり選択的でない場合、次の問合せに示すように、join=1を選択できます。
PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#join=1>
SELECT ?s ?s1 ?o
WHERE { ?s1 ?p1 ?s .
{
SERVICE <http://sparql.org/books> { ?s ?p ?o }
}
}
この場合、リモートの問合せ部とローカルの部分は独立して実行され、結果はJenaによって結合されます。この方法は、概念的にはハッシュ結合と似ています。
フェデレーテッド問合せをデバッグまたはトレースするには、Oracle JDeveloperのHTTPアナライザを使用して、基礎となるSERVICEコールを調べます。
親トピック: 追加の問合せオプション
6.9.4.2 S2Sオプションの利点と使用方法の情報
S2S
オプション(「追加の問合せオプション」参照)には、潜在的に次の利点があります。
-
RESULT_CACHE
オプションと連携し、問合せパフォーマンスを向上します。S2S
とRESULT_CACHE
オプションを使用すると、特に、頻繁に実行される問合せに有用です。 -
SEM_MATCH表関数の解析時間を削減し、多くの動的に生成されたSPARQL問合せを含むアプリケーションに有用です。
-
問合せ本体の4000バイトの制限(SEM_MATCH表関数の最初のパラメータ)を除外し、より長く複雑な問合せがサポートされます。
S2Sオプションは、内部のインメモリー・キャッシュを、変換されたSQL問合せ文で使用されるようにします。この内部キャッシュのデフォルト・サイズは1024(つまり1024のSQL問合せ)ですが、サイズは、次のJava VMプロパティを使用して調整できます。
-Doracle.spatial.rdf.client.jena.queryCacheSize=<size>
親トピック: 追加の問合せオプション
6.9.5 中間層リソース・キャッシング
セマンティク・データが格納されると、すべてのリソース値がIDにハッシュされ、トリプル表に格納されます。値IDからの完全なリソース値へのマッピングは、MDSYS.RDF_VALUE$表に格納されます。問合せ時、選択された変数ごとにOracle DatabaseでRDF_VALUE$表による結合を実行し、リソースを取得する必要があります。
ただし、結合の数を減らすため、中間層キャッシュ・オプションを使用して、値IDとリソース値の間のマッピングを格納するために中間層でのインメモリー・キャッシュが使用されるようにできます。この機能を使用するには、SPARQL問合せに次のPREFIXプラグマを含めます。
PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#midtier_cache>
インメモリー・キャッシュの最大サイズ(バイト)を制御するには、oracle.spatial.rdf.client.jena.cacheMaxSize
システム・プロパティを使用します。デフォルトの最大キャッシュ・サイズは、1GBです。
中間層リソース・キャッシングは、ORDER BYまたはDISTINCT(あるいは両方とも)構造体を使用した問合せ、または複数の投影変数による問合せに最も効果的です。中間層キャッシュは、「追加の問合せオプション」で指定したその他のオプションと組み合せることができます。
モデルのすべてのリソースをキャッシュに事前挿入するには、GraphOracleSem.populateCache
メソッドまたはDatasetGraphOracleSem.populateCache
メソッドを使用します。どちらのメソッドも、内部の中間層キャッシュを構築するために使用されるスレッドの数を指定するパラメータをとります。どちらかのメソッドをパラレルに実行すると、複数のCPU(コア)を搭載したマシンで、パフォーマンスを構築しているキャッシュを大幅に増やすことができます。
親トピック: 他の機能をサポートするためのSPARQL構文への追加
6.10 RDF Semantic Graph support for Apache JenaによりSPARQL問合せでサポートされる関数
Support for Apache Jenaを介したSPARQL問合せでは、次に示す種類の関数を使用できます。
-
Jena ARQ問合せエンジンの関数ライブラリにある関数
-
投影変数に関するOracle Databaseのネイティブ関数
-
ユーザー定義関数
6.10.1 ARQ関数ライブラリの関数
support for Apache Jenaを介したSPARQL問合せは、Jena ARQ問合せエンジンの関数ライブラリにある関数を使用できます。これらの問合せは、中間層で実行されます。
次の例は、upper-case
関数とnamespace
関数を使用します。これらの例で、接頭辞fn
は<http://www.w3.org/2005/xpath-functions#>
、接頭辞afn
は<http://jena.hpl.hp.com/ARQ/function#>
です。
PREFIX fn: <http://www.w3.org/2005/xpath-functions#> PREFIX afn: <http://jena.hpl.hp.com/ARQ/function#> SELECT (fn:upper-case(?object) as ?object1) WHERE { ?subject dc:title ?object } PREFIX fn: <http://www.w3.org/2005/xpath-functions#> PREFIX afn: <http://jena.hpl.hp.com/ARQ/function#> SELECT ?subject (afn:namespace(?object) as ?object1) WHERE { ?subject <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?object }
6.10.2 射影された変数に対するネイティブなOracle Database関数
support for Apache Jenaを介したSPARQL問合せは、射影変数に関するOracle Databaseのネイティブ・ファンクションを使用できます。これらの問合せとファンクションは、データベース内部で実行されます。この項で説明したファンクションは、ARQファンクション(「ARQファンクション・ライブラリのファンクション」を参照)とともには使用しないでください。
この項では、サポートされるネイティブ関数の一覧と、いくつかの例を示します。例で、接頭辞oext
は、< http://oracle.com/semtech/jena-adaptor/ext/function#>
です。
注意:
前述のURLで、jena-adapt
or
の綴りに注意してください(これは、既存のアプリケーションとの互換性のために保持されており、問合せではこれを使用する必要があります)。Oracleドキュメントのスタイル・ガイドに従い、通常のテキストではadaptとerいう綴りを使用します。
-
oext:upper-literal
は、リテラル値(長いリテラルを除く)を大文字に変換します。たとえば、次のようにします。PREFIX oext: <http://oracle.com/semtech/jena-adaptor/ext/function#> SELECT (oext:upper-literal(?object) as ?object1) WHERE { ?subject dc:title ?object }
-
oext:lower-literal
は、リテラル値(長いリテラルを除く)を小文字に変換します。たとえば、次のようにします。PREFIX oext: <http://oracle.com/semtech/jena-adaptor/ext/function#> SELECT (oext:lower-literal(?object) as ?object1) WHERE { ?subject dc:title ?object }
-
oext:build-uri-for-id
は、URI、bNodeまたはリテラルの値IDをURIフォームに変換します。たとえば、次のようにします。PREFIX oext: <http://oracle.com/semtech/jena-adaptor/ext/function#> SELECT (oext:build-uri-for-id(?object) as ?object1) WHERE { ?subject dc:title ?object }
出力の例は、次のようになります。
<rdfvid:1716368199350136353>
この関数の1つの用途は、Javaアプリケーションがメモリー内で、それらの値IDからURI、bNodeまたはリテラルの字句形式へのマッピングを保持できるようにすることです。MDSYS.RDF_VALUE$表は、Oracle Databaseでこのようなマッピングを提供します。
変数
?var
について、oext:build-uri-for-id(?var)
のみが投影される場合、問合せへの応答に必要な内部表の結合操作がより少なくなるため、問合せのパフォーマンスはより高速になります。 -
oext:literal-strlen
は、リテラル値(長いリテラルを除く)の長さを返します。たとえば、次のようにします。PREFIX oext: <http://oracle.com/semtech/jena-adaptor/ext/function#> SELECT (oext:literal-strlen(?object) as ?objlen) WHERE { ?subject dc:title ?object }
6.10.3 ユーザー定義関数
support for Apache Jenaを介したSPARQL問合せは、データベースに格納されているユーザー定義関数を使用できます。
次の例で、長いリテラル(CLOB)および短いリテラルを処理する文字列長関数(my_strlen
)を定義するとします。SPARQL問合せ側では、この関数をouext
(http://oracle.com/semtech/jena-adaptor/ext/user-def-function#
)という名前空間の下で参照できます。
PREFIX ouext: <http://oracle.com/semtech/jena-adaptor/ext/user-def-function#> SELECT ?subject ?object (ouext:my_strlen(?object) as ?obj1) WHERE { ?subject dc:title ?object }
データベース内では、この機能を実装するために、my_strlen
、my_strlen_cl
、my_strlen_la
、my_strlen_lt
およびmy_strlen_vt
の関数を定義します。概念的に、これらの関数の戻り値は、表6-1に示すように対応付けられます。
表6-1 my_strlenの関数と戻り値の例
関数名 | 戻り値 |
---|---|
my_strlen |
<VAR> |
my_strlen_cl |
<VAR>$RDFCLOB |
my_strlen_la |
<VAR>$RDFLANG |
my_strlen_lt |
<VAR>$RDFLTYP |
my_strlen_vt |
<VAR>$RDFVTYP |
SPARQLから参照できる1つのユーザー定義関数は、(MDSYS.RDF_VALUE$内の)RDFリソースの内部表現で位置合せするため、これを実装するために一連の関数(合計5つ)が使用されます。RDFリソースの値、言語、リテラル・タイプ、LONG値および値タイプに関して記述する5つの主要な列があり、これらの5つの列はSEM_MATCHを使用して選択されます。この場合、ユーザー定義関数は、5つの列で表される1つのRDFリソースをもう1つのRDFリソースに単純に変換します。
これらの関数は、次のように定義されます。
create or replace function my_strlen(rdfvtyp in varchar2, rdfltyp in varchar2, rdflang in varchar2, rdfclob in clob, value in varchar2 ) return varchar2 as ret_val varchar2(4000); begin -- value if (rdfvtyp = 'LIT') then if (rdfclob is null) then return length(value); else return dbms_lob.getlength(rdfclob); end if; else -- Assign -1 for non-literal values so that application can -- easily differentiate return '-1'; end if; end; / create or replace function my_strlen_cl(rdfvtyp in varchar2, rdfltyp in varchar2, rdflang in varchar2, rdfclob in clob, value in varchar2 ) return clob as begin return null; end; / create or replace function my_strlen_la(rdfvtyp in varchar2, rdfltyp in varchar2, rdflang in varchar2, rdfclob in clob, value in varchar2 ) return varchar2 as begin return null; end; / create or replace function my_strlen_lt(rdfvtyp in varchar2, rdfltyp in varchar2, rdflang in varchar2, rdfclob in clob, value in varchar2 ) return varchar2 as ret_val varchar2(4000); begin -- literal type return 'http://www.w3.org/2001/XMLSchema#integer'; end; / create or replace function my_strlen_vt(rdfvtyp in varchar2, rdfltyp in varchar2, rdflang in varchar2, rdfclob in clob, value in varchar2 ) return varchar2 as ret_val varchar2(3); begin return 'LIT'; end; /
ユーザー定義関数には、VARCHAR2タイプのパラメータを指定することもできます。次の5つの関数は、ともに、部分文字列に整数(VARCHAR2形式)を受け入れ、部分文字列を戻すmy_shorten_str
関数を定義します。(この例の部分文字列は12文字で、4000バイト以下である必要があります。)
-- SPARQL query that returns the first 12 characters of literal values. -- PREFIX ouext: <http://oracle.com/semtech/jena-adaptor/ext/user-def-function#> SELECT (ouext:my_shorten_str(?object, "12") as ?obj1) ?subject WHERE { ?subject dc:title ?object } create or replace function my_shorten_str(rdfvtyp in varchar2, rdfltyp in varchar2, rdflang in varchar2, rdfclob in clob, value in varchar2, arg in varchar2 ) return varchar2 as ret_val varchar2(4000); begin -- value if (rdfvtyp = 'LIT') then if (rdfclob is null) then return substr(value, 1, to_number(arg)); else return dbms_lob.substr(rdfclob, to_number(arg), 1); end if; else return null; end if; end; / create or replace function my_shorten_str_cl(rdfvtyp in varchar2, rdfltyp in varchar2, rdflang in varchar2, rdfclob in clob, value in varchar2, arg in varchar2 ) return clob as ret_val clob; begin -- lob return null; end; / create or replace function my_shorten_str_la(rdfvtyp in varchar2, rdfltyp in varchar2, rdflang in varchar2, rdfclob in clob, value in varchar2, arg in varchar2 ) return varchar2 as ret_val varchar2(4000); begin -- lang if (rdfvtyp = 'LIT') then return rdflang; else return null; end if; end; / create or replace function my_shorten_str_lt(rdfvtyp in varchar2, rdfltyp in varchar2, rdflang in varchar2, rdfclob in clob, value in varchar2, arg in varchar2 ) return varchar2 as ret_val varchar2(4000); begin -- literal type ret_val := rdfltyp; return ret_val; end; / create or replace function my_shorten_str_vt(rdfvtyp in varchar2, rdfltyp in varchar2, rdflang in varchar2, rdfclob in clob, value in varchar2, arg in varchar2 ) return varchar2 as ret_val varchar2(3); begin return 'LIT'; end; /
6.11 SPARQLの更新のサポート
RDF Semantic Graph support for Apache Jenaは、SPARQLの更新(SPARULとも呼ばれる)(http://www.w3.org/TR/sparql11-update/
)をサポートしています。
主要なプログラミングAPIには、JenaクラスUpdateAction
(パッケージcom.hp.hpl.jena.update
内)、RDF Semantic Graph support for Apache JenaクラスGraphOracleSem
およびDatasetGraphOracleSem
が含まれます。例6-4は、SPARQLの更新操作によって、名前付きグラフ<http://example/graph>
のすべてのトリプルが、データベースに格納されている関連したモデルから削除されることを示しています。
例6-4 単純なSPARQL更新
GraphOracleSem graphOracleSem = .... ; DatasetGraphOracleSem dsgos = DatasetGraphOracleSem.createFrom(graphOracleSem); // SPARQL Update operation String szUpdateAction = "DROP GRAPH <http://example/graph>"; // Execute the Update against a DatasetGraph instance (can be a Jena Model as well) UpdateAction.parseExecute(szUpdateAction, dsgos);
Oracle Databaseでは、空の名前付きグラフに関する情報は保持されないことに注意してください。このことは、このグラフにトリプルを追加せずにCREATE GRAPH <graph_name>を起動した場合、アプリケーション表または基礎となるRDF_LINK$表に、追加の行が作成されないことを意味します。Oracle Databaseに対しては、例6-4の例に示すとおり、CREATE GRAPHのステップを安全にスキップできます。
例6-5 挿入と削除の操作によるSPARQLの更新
例6-5は、複数の挿入操作と削除操作を含むSPARQLの更新操作(ARQ 2.8.8から)を示しています。
PREFIX : <http://example/> CREATE GRAPH <http://example/graph> ; INSERT DATA { :r :p 123 } ; INSERT DATA { :r :p 1066 } ; DELETE DATA { :r :p 1066 } ; INSERT DATA { GRAPH <http://example/graph> { :r :p 123 . :r :p 1066 } } ; DELETE DATA { GRAPH <http://example/graph> { :r :p 123 } }
空のDatasetGraphOracleSemに対して例6-5
での更新操作を実行した後、SPARQL問合せSELECT ?s ?p ?o WHERE {?s ?p ?o}
を実行すると、次のレスポンスが生成されます。
----------------------------------------------------------------------------------------------- | s | p | o | =============================================================================================== | <http://example/r> | <http://example/p> | "123"^^<http://www.w3.org/2001/XMLSchema#decimal> | -----------------------------------------------------------------------------------------------
同じデータを使用して、SPARQL問合せSELECT ?g ?s ?p ?o where {GRAPH ?g {?s ?p ?o}}
を実行するとは、次のレスポンスが生成されます。
------------------------------------------------------------------------------------------------------------------------- | g | s | p | o | ========================================================================================================================= | <http://example/graph> | <http://example/r> | <http://example/p> | "1066"^^<http://www.w3.org/2001/XMLSchema#decimal> | -------------------------------------------------------------------------------------------------------------------------
SPARQLの更新操作にJava APIを使用するだけでなく、joseki-config.ttl
ファイルの次の行の最初にあるコメント(##
)文字を削除することによって、SPARQLの更新操作を受け入れるようにJosekiを構成することができます。
## <#serviceUpdate> ## rdf:type joseki:Service ; ## rdfs:label "SPARQL/Update" ; ## joseki:serviceRef "update/service" ; ## # dataset part ## joseki:dataset <#oracle>; ## # Service part. ## # This processor will not allow either the protocol, ## # nor the query, to specify the dataset. ## joseki:processor joseki:ProcessorSPARQLUpdate ## . ## ## <#serviceRead> ## rdf:type joseki:Service ; ## rdfs:label "SPARQL" ; ## joseki:serviceRef "sparql/read" ; ## # dataset part ## joseki:dataset <#oracle> ; ## Same dataset ## # Service part. ## # This processor will not allow either the protocol, ## # nor the query, to specify the dataset. ## joseki:processor joseki:ProcessorSPARQL_FixedDS ; ## .
joseki-config.ttl
ファイルを編集したら、Joseki Webアプリケーションを再起動する必要があります。その後、次のようにして単純な更新操作を試行できます。
-
ブラウザで、
http://
<hostname>
:7001/joseki/update.html
を表示します。 -
テキスト・ボックスで次の内容を入力するか、または貼り付けます。
PREFIX : <http://example/> INSERT DATA { GRAPH <http://example/g1> { :r :p 455 } }
-
「Perform SPARQL Update」をクリックします。
更新操作が成功したことを確認するには、http://
<hostname>
:7001/joseki
に移動し、次の問合せを入力します。
SELECT * WHERE { GRAPH <http://example/g1> {?s ?p ?o}};
レスポンスには、次のトリプルが含まれます。
<http://example/r> <http://example/p> "455"^^<http://www.w3.org/2001/XMLSchema#decimal>
SPARQLの更新は、HTTP POST操作を使用してhttp://
<hostname>
:7001/joseki/update/
サービスに送信することもできます。たとえば、curl
(http://en.wikipedia.org/wiki/CURL
)を使用して更新操作を実行するHTTP POSTリクエストを送信できます。
curl --data "request=PREFIX%20%3A%20%3Chttp%3A%2F%2Fexample%2F%3E%20%0AINSERT%20DATA%20%7B%0A%20%20GRAPH%20%3Chttp%3A%2F%2Fexample%2Fg1%3E%20%7B%20%3Ar%20%3Ap%20888%20%7D%0A%7D%0A" http://hostname:7001/joseki/update/service
前述の例で、URLエンコードされた文字列は、名前付きグラフへの単純なINSERT操作です。デコーディングの後、次のように読み取ります。
PREFIX : <http://example/> INSERT DATA { GRAPH <http://example/g1> { :r :p 888 }
6.12 RDFデータの解析関数
oracle.spatial.rdf.client.jena
パッケージのSemNetworkAnalyst
クラスを使用して、RDFデータで解析関数を実行することができます。
このサポートは、ネットワークデータ・モデル・グラフのロジックを基礎となるRDFデータ構造体に統合します。そのため、RDFデータでの解析関数を使用するには、『Oracle Spatial and Graphトポロジ・データ・モデルおよびネットワーク・データ・モデル・グラフ開発者ガイド』に説明されている、ネットワーク・データ・モデルのグラフ機能についても理解しておく必要があります。
必要なNDM Javaライブラリ(sdonm.jar
とsdoutl.jar
を含む)は、ディレクトリ$ORACLE_HOME/md/jlib
の下にあります。xmlparserv2.jar
($ORACLE_HOME/xdk/lib
の下)を、classpath
定義に含める必要があることに注意してください。
例6-6 RDFデータ上の解析関数の実行
例6-6では、SemNetworkAnalyst
クラス(NDM NetworkAnalyst
APIを内部的に使用)を使用します。
Oracle oracle = new Oracle(jdbcUrl, user, password); GraphOracleSem graph = new GraphOracleSem(oracle, modelName); Node nodeA = Node.createURI("http://A"); Node nodeB = Node.createURI("http://B"); Node nodeC = Node.createURI("http://C"); Node nodeD = Node.createURI("http://D"); Node nodeE = Node.createURI("http://E"); Node nodeF = Node.createURI("http://F"); Node nodeG = Node.createURI("http://G"); Node nodeX = Node.createURI("http://X"); // An anonymous node Node ano = Node.createAnon(new AnonId("m1")); Node relL = Node.createURI("http://likes"); Node relD = Node.createURI("http://dislikes"); Node relK = Node.createURI("http://knows"); Node relC = Node.createURI("http://differs"); graph.add(new Triple(nodeA, relL, nodeB)); graph.add(new Triple(nodeA, relC, nodeD)); graph.add(new Triple(nodeB, relL, nodeC)); graph.add(new Triple(nodeA, relD, nodeC)); graph.add(new Triple(nodeB, relD, ano)); graph.add(new Triple(nodeC, relL, nodeD)); graph.add(new Triple(nodeC, relK, nodeE)); graph.add(new Triple(ano, relL, nodeD)); graph.add(new Triple(ano, relL, nodeF)); graph.add(new Triple(ano, relD, nodeB)); // X only likes itself graph.add(new Triple(nodeX, relL, nodeX)); graph.commitTransaction(); HashMap<Node, Double> costMap = new HashMap<Node, Double>(); costMap.put(relL, Double.valueOf((double)0.5)); costMap.put(relD, Double.valueOf((double)1.5)); costMap.put(relC, Double.valueOf((double)5.5)); graph.setDOP(4); // this allows the underlying LINK/NODE tables // and indexes to be created in parallel. SemNetworkAnalyst sna = SemNetworkAnalyst.getInstance( graph, // network data source true, // directed graph true, // cleanup existing NODE and LINK table costMap ); psOut.println("From nodeA to nodeC"); Node[] nodeArray = sna.shortestPathDijkstra(nodeA, nodeC); printNodeArray(nodeArray, psOut); psOut.println("From nodeA to nodeD"); nodeArray = sna.shortestPathDijkstra( nodeA, nodeD); printNodeArray(nodeArray, psOut); psOut.println("From nodeA to nodeF"); nodeArray = sna.shortestPathAStar(nodeA, nodeF); printNodeArray(nodeArray, psOut); psOut.println("From ano to nodeC"); nodeArray = sna.shortestPathAStar(ano, nodeC); printNodeArray(nodeArray, psOut); psOut.println("From ano to nodeX"); nodeArray = sna.shortestPathAStar(ano, nodeX); printNodeArray(nodeArray, psOut); graph.close(); oracle.dispose(); ... ... // A helper function to print out a path public static void printNodeArray(Node[] nodeArray, PrintStream psOut) { if (nodeArray == null) { psOut.println("Node Array is null"); return; } if (nodeArray.length == 0) {psOut.println("Node Array is empty"); } int iFlag = 0; psOut.println("printNodeArray: full path starts"); for (int iHops = 0; iHops < nodeArray.length; iHops++) { psOut.println("printNodeArray: full path item " + iHops + " = " + ((iFlag == 0) ? "[n] ":"[e] ") + nodeArray[iHops]); iFlag = 1 - iFlag; } }
次に、例6-6について説明します。
-
GraphOracleSem
オブジェクトが構築され、少数のトリプルがGraphOracleSem
オブジェクトに追加されます。これらのトリプルは、複数の個人と、好き、嫌い、知人および他人などの関係を記述します。 -
コスト・マッピングは、数値コストの値を異なるリンク/述語(RDFグラフの)に割り当てるために作成されます。この場合、0.5、1.5および5.5は、それぞれに述語likes、dislikesおよびdiffersに割り当てられます。このコスト・マッピングはオプションです。マッピングがないとき、すべての述語は同じコスト1に割り当てられることになります。コスト・マッピングが指定される際、このマッピングは完全である必要はなく、コスト・マッピングに含まれない述語には、デフォルト値の1が割り当てられます。
例6-6の出力は、次のとおりです。この出力には、指定された開始ノードと終了ノードの最短経路が示されます。sna.shortestPathAStar(ano, nodeX)
の戻り値は、これらの2つのノード間には経路がないため、NULLになります。
From nodeA to nodeC printNodeArray: full path starts printNodeArray: full path item 0 = [n] http://A ## "n" denotes Node printNodeArray: full path item 1 = [e] http://likes ## "e" denotes Edge (Link) printNodeArray: full path item 2 = [n] http://B printNodeArray: full path item 3 = [e] http://likes printNodeArray: full path item 4 = [n] http://C From nodeA to nodeD printNodeArray: full path starts printNodeArray: full path item 0 = [n] http://A printNodeArray: full path item 1 = [e] http://likes printNodeArray: full path item 2 = [n] http://B printNodeArray: full path item 3 = [e] http://likes printNodeArray: full path item 4 = [n] http://C printNodeArray: full path item 5 = [e] http://likes printNodeArray: full path item 6 = [n] http://D From nodeA to nodeF printNodeArray: full path starts printNodeArray: full path item 0 = [n] http://A printNodeArray: full path item 1 = [e] http://likes printNodeArray: full path item 2 = [n] http://B printNodeArray: full path item 3 = [e] http://dislikes printNodeArray: full path item 4 = [n] m1 printNodeArray: full path item 5 = [e] http://likes printNodeArray: full path item 6 = [n] http://F From ano to nodeC printNodeArray: full path starts printNodeArray: full path item 0 = [n] m1 printNodeArray: full path item 1 = [e] http://dislikes printNodeArray: full path item 2 = [n] http://B printNodeArray: full path item 3 = [e] http://likes printNodeArray: full path item 4 = [n] http://C From ano to nodeX Node Array is null
基礎となるRDFグラフ・ビュー(SEMM_<model_name>またはRDFM_<model_name>)は、NDM関数で直接使用することができないため、必要な表(指定されたRDFグラフに導出されるノードとリンクを含む)は、SemNetworkAnalyst
で作成されます。これらの表は、RDFグラフが変更されても自動更新されないため、SemNetworkAnalyst.getInstance
にcleanup
パラメータにtrue
を設定し、古いノードを削除して表をリンクさせ、更新された表を再構築します。
例6-7 セマンティク・データでのNDM nearestNeighbors関数の実装
例6-7では、セマンティク・データの上位に、NDM nearestNeighbors
関数を実装しています。これによってSemNetworkAnalyst
インスタンスからNetworkAnalyst
オブジェクトを取得し、ノードIDを取得してPointOnNet
オブジェクトを作成し、LogicalSubPath
オブジェクトを処理します。
%cat TestNearestNeighbor.java import java.io.*; import java.util.*; import com.hp.hpl.jena.query.*; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.util.FileManager; import com.hp.hpl.jena.util.iterator.*; import com.hp.hpl.jena.graph.*; import com.hp.hpl.jena.update.*; import com.hp.hpl.jena.sparql.core.DatasetImpl; import oracle.spatial.rdf.client.jena.*; import oracle.spatial.rdf.client.jena.SemNetworkAnalyst; import oracle.spatial.network.lod.LODGoalNode; import oracle.spatial.network.lod.LODNetworkConstraint; import oracle.spatial.network.lod.NetworkAnalyst; import oracle.spatial.network.lod.PointOnNet; import oracle.spatial.network.lod.LogicalSubPath; /** * This class implements a nearestNeighbors function on top of semantic data * using public APIs provided in SemNetworkAnalyst and Oracle Spatial NDM */ public class TestNearestNeighbor { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; PrintStream psOut = System.out; Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); String szModelName = "test_nn"; // First construct a TBox and load a few axioms ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle, szModelName); String insertString = " PREFIX my: <http://my.com/> " + " INSERT DATA " + " { my:A my:likes my:B . " + " my:A my:likes my:C . " + " my:A my:knows my:D . " + " my:A my:dislikes my:X . " + " my:A my:dislikes my:Y . " + " my:C my:likes my:E . " + " my:C my:likes my:F . " + " my:C my:dislikes my:M . " + " my:D my:likes my:G . " + " my:D my:likes my:H . " + " my:F my:likes my:M . " + " } "; UpdateAction.parseExecute(insertString, model); GraphOracleSem g = model.getGraph(); g.commitTransaction(); g.setDOP(4); HashMap<Node, Double> costMap = new HashMap<Node, Double>(); costMap.put(Node.createURI("http://my.com/likes"), Double.valueOf(1.0)); costMap.put(Node.createURI("http://my.com/dislikes"), Double.valueOf(4.0)); costMap.put(Node.createURI("http://my.com/knows"), Double.valueOf(2.0)); SemNetworkAnalyst sna = SemNetworkAnalyst.getInstance( g, // source RDF graph true, // directed graph true, // cleanup old Node/Link tables costMap ); Node nodeStart = Node.createURI("http://my.com/A"); long origNodeID = sna.getNodeID(nodeStart); long[] lIDs = {origNodeID}; // translate from the original ID long nodeID = (sna.mapNodeIDs(lIDs))[0]; NetworkAnalyst networkAnalyst = sna.getEmbeddedNetworkAnalyst(); LogicalSubPath[] lsps = networkAnalyst.nearestNeighbors( new PointOnNet(nodeID), // startPoint 6, // numberOfNeighbors 1, // searchLinkLevel 1, // targetLinkLevel (LODNetworkConstraint) null, // constraint (LODGoalNode) null // goalNodeFilter ); if (lsps != null) { for (int idx = 0; idx < lsps.length; idx++) { LogicalSubPath lsp = lsps[idx]; Node[] nodePath = sna.processLogicalSubPath(lsp, nodeStart); psOut.println("Path " + idx); printNodeArray(nodePath, psOut); } } g.close(); sna.close(); oracle.dispose(); } public static void printNodeArray(Node[] nodeArray, PrintStream psOut) { if (nodeArray == null) { psOut.println("Node Array is null"); return; } if (nodeArray.length == 0) { psOut.println("Node Array is empty"); } int iFlag = 0; psOut.println("printNodeArray: full path starts"); for (int iHops = 0; iHops < nodeArray.length; iHops++) { psOut.println("printNodeArray: full path item " + iHops + " = " + ((iFlag == 0) ? "[n] ":"[e] ") + nodeArray[iHops]); iFlag = 1 - iFlag; } } }
例6-7の出力は、次のとおりです。
Path 0 printNodeArray: full path starts printNodeArray: full path item 0 = [n] http://my.com/A printNodeArray: full path item 1 = [e] http://my.com/likes printNodeArray: full path item 2 = [n] http://my.com/C Path 1 printNodeArray: full path starts printNodeArray: full path item 0 = [n] http://my.com/A printNodeArray: full path item 1 = [e] http://my.com/likes printNodeArray: full path item 2 = [n] http://my.com/B Path 2 printNodeArray: full path starts printNodeArray: full path item 0 = [n] http://my.com/A printNodeArray: full path item 1 = [e] http://my.com/knows printNodeArray: full path item 2 = [n] http://my.com/D Path 3 printNodeArray: full path starts printNodeArray: full path item 0 = [n] http://my.com/A printNodeArray: full path item 1 = [e] http://my.com/likes printNodeArray: full path item 2 = [n] http://my.com/C printNodeArray: full path item 3 = [e] http://my.com/likes printNodeArray: full path item 4 = [n] http://my.com/E Path 4 printNodeArray: full path starts printNodeArray: full path item 0 = [n] http://my.com/A printNodeArray: full path item 1 = [e] http://my.com/likes printNodeArray: full path item 2 = [n] http://my.com/C printNodeArray: full path item 3 = [e] http://my.com/likes printNodeArray: full path item 4 = [n] http://my.com/F Path 5 printNodeArray: full path starts printNodeArray: full path item 0 = [n] http://my.com/A printNodeArray: full path item 1 = [e] http://my.com/knows printNodeArray: full path item 2 = [n] http://my.com/D printNodeArray: full path item 3 = [e] http://my.com/likes printNodeArray: full path item 4 = [n] http://my.com/H
6.12.1 グラフにおけるパスの文脈情報の生成
パスそのものに加え、グラフ内のパスに関する文脈情報を参照することは、有用な場合があります。SemNetworkAnalyst
クラスのbuildSurroundingSubGraph
メソッドは、DOTファイル(グラフ記述言語ファイル、拡張子.gv
)を、指定されたWriter
オブジェクトに出力できます。パスのノードごとに、最大10の直接の隣接が、パス周辺のサブグラフを生成するために使用されます。次の例で、DOTファイルを文脈情報を用いて生成する具体的方法を示します。ここでは、文脈情報として、特に例6-6で使用されている解析関数の出力が用いられています。
nodeArray = sna.shortestPathDijkstra(nodeA, nodeD); printNodeArray(nodeArray, psOut); FileWriter dotWriter = new FileWriter("Shortest_Path_A_to_D.gv"); sna.buildSurroundingSubGraph(nodeArray, dotWriter);
先の例から生成される出力DOTファイルは、次の例に示すように単純な形をしています。
% cat Shortest_Path_A_to_D.gv digraph { rankdir = LR; charset="utf-8"; "Rhttp://A" [ label="http://A" shape=rectangle,color=red,style = filled, ]; "Rhttp://B" [ label="http://B" shape=rectangle,color=red,style = filled, ]; "Rhttp://A" -> "Rhttp://B" [ label="http://likes" color=red, style=bold, ]; "Rhttp://C" [ label="http://C" shape=rectangle,color=red,style = filled, ]; "Rhttp://A" -> "Rhttp://C" [ label="http://dislikes" ]; "Rhttp://D" [ label="http://D" shape=rectangle,color=red,style = filled, ]; "Rhttp://A" -> "Rhttp://D" [ label="http://differs" ]; "Rhttp://B" -> "Rhttp://C" [ label="http://likes" color=red, style=bold, ]; "Rm1" [ label="m1" shape=ellipse,color=blue, ]; "Rhttp://B" -> "Rm1" [ label="http://dislikes" ]; "Rm1" -> "Rhttp://B" [ label="http://dislikes" ]; "Rhttp://C" -> "Rhttp://D" [ label="http://likes" color=red, style=bold, ]; "Rhttp://E" [ label="http://E" shape=ellipse,color=blue, ]; "Rhttp://C" -> "Rhttp://E" [ label="http://knows" ]; "Rm1" -> "Rhttp://D" [ label="http://likes" ]; }
SemNetworkAnalyst
クラスとGraphOracleSem
クラスのメソッドを使用して、より洗練された視覚表現で解析関数出力を生成することもできます。
前述のDOTファイルを、様々なイメージ形式に変換できます。図6-1は、前述のDOTファイルの情報を表現したイメージです。
親トピック: RDFデータの解析関数
6.13 サーバー側APIのサポート
この項では、RDF Semantic Graph support for Apache Jenaによって使用可能になるRDFセマンティク・グラフ機能の一部について説明します。
使用可能な機能をサポートするAPIコールの包括的なドキュメントについては、RDF Semantic Graph support for Apache Jenaのリファレンス情報(Javadoc)を参照してください。support for Apache Jenaによって使用可能なサーバー側機能の詳細は、このマニュアルの関連する章を参照してください。
6.13.1 仮想モデルのサポート
仮想モデル(「仮想モデル」を参照)は、GraphOracleSem
コンストラクタで指定され、透過的に処理されます。仮想モデルがモデルとルールベースの組合せのために存在している場合には、問合せの応答に使用されます。そのような仮想モデルが存在しない場合には、データベースに作成されます。
注意:
support for Apache Jenaを介した仮想モデルのサポートは、Oracle Databaseリリース11.2以上でのみ使用可能です。
次の例では、既存の仮想モデルを再利用します。
String modelName = "EX";
String m1 = "EX_1";
ModelOracleSem defaultModel =
ModelOracleSem.createOracleSemModel(oracle, modelName);
// create these models in case they don't exist
ModelOracleSem model1 = ModelOracleSem.createOracleSemModel(oracle, m1);
String vmName = "VM_" + modelName;
//create a virtual model containing EX and EX_1
oracle.executeCall(
"begin sem_apis.create_virtual_model(?,sem_models('"+ m1 + "','"+ modelName+"'),null); end;",vmName);
String[] modelNames = {m1};
String[] rulebaseNames = {};
Attachment attachment = Attachment.createInstance(modelNames, rulebaseNames,
InferenceMaintenanceMode.NO_UPDATE, QueryOptions.ALLOW_QUERY_VALID_AND_DUP);
// vmName is passed to the constructor, so GraphOracleSem will use the virtual
// model named vmname (if the current user has read privileges on it)
GraphOracleSem graph = new GraphOracleSem(oracle, modelName, attachment, vmName);
graph.add(Triple.create(Node.createURI("urn:alice"),
Node.createURI("http://xmlns.com/foaf/0.1/mbox"),
Node.createURI("mailto:alice@example")));
ModelOracleSem model = new ModelOracleSem(graph);
String queryString =
" SELECT ?subject ?object WHERE { ?subject ?p ?object } ";
Query query = QueryFactory.create(queryString) ;
QueryExecution qexec = QueryExecutionFactory.create(query, model) ;
try {
ResultSet results = qexec.execSelect() ;
for ( ; results.hasNext() ; ) {
QuerySolution soln = results.nextSolution() ;
psOut.println("soln " + soln);
}
}
finally {
qexec.close() ;
}
OracleUtils.dropSemanticModel(oracle, modelName);
OracleUtils.dropSemanticModel(oracle, m1);
oracle.dispose();
また、次の例のように、GraphOracleSemコンストラクタを使用して仮想モデルを作成することもできます。
GraphOracleSem graph = new GraphOracleSem(oracle, modelName, attachment, true);
この例で、4つ目のパラメータ(true
)は、指定されたmodelName
とattachment
のために仮想モデルを作成する必要があることを示しています。
親トピック: サーバー側APIのサポート
6.13.2 接続プーリングのサポート
Oracle Database接続プーリングは、support for Apache JenaのOraclePool
クラスを介して提供されます。このクラスが初期化されると、使用可能な接続のプールからOracleオブジェクトを戻すことができます。Oracleオブジェクトは、基本的にデータベース接続ラッパーです。dispose
がOracleオブジェクトでコールされた後、接続がプールに戻されます。OraclePool
の使用に関する詳細は、APIリファレンス情報(Javadoc)を参照してください。
次の例では、5つの初期接続を使用するOraclePoolオブジェクトを設定します。
public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; String szModelName = args[3]; // test with connection properties java.util.Properties prop = new java.util.Properties(); prop.setProperty("MinLimit", "2"); // the cache size is 2 at least prop.setProperty("MaxLimit", "10"); prop.setProperty("InitialLimit", "2"); // create 2 connections at startup prop.setProperty("InactivityTimeout", "1800"); // seconds prop.setProperty("AbandonedConnectionTimeout", "900"); // seconds prop.setProperty("MaxStatementsLimit", "10"); prop.setProperty("PropertyCheckInterval", "60"); // seconds System.out.println("Creating OraclePool"); OraclePool op = new OraclePool(szJdbcURL, szUser, szPasswd, prop, "OracleSemConnPool"); System.out.println("Done creating OraclePool"); // grab an Oracle and do something with it System.out.println("Getting an Oracle from OraclePool"); Oracle oracle = op.getOracle(); System.out.println("Done"); System.out.println("Is logical connection:" + oracle.getConnection().isLogicalConnection()); GraphOracleSem g = new GraphOracleSem(oracle, szModelName); g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"), Node.createURI("u:Mary"))); g.close(); // return the Oracle back to the pool oracle.dispose(); // grab another Oracle and do something else System.out.println("Getting an Oracle from OraclePool"); oracle = op.getOracle(); System.out.println("Done"); System.out.println("Is logical connection:" + oracle.getConnection().isLogicalConnection()); g = new GraphOracleSem(oracle, szModelName); g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"), Node.createURI("u:Jack"))); g.close(); OracleUtils.dropSemanticModel(oracle, szModelName); // return the Oracle object back to the pool oracle.dispose(); }
親トピック: サーバー側APIのサポート
6.13.3 セマンティク・モデルのPL/SQLインタフェース
support for Apache Jenaを介して、複数のセマンティクPL/SQLサブプログラムを使用することができます。表6-2に、サブプログラムと、対応するJavaクラスおよびメソッドを示します。
表6-2 PL/SQLサブプログラムと対応するRDF Semantic Graph support for Apache JenaのJavaクラスおよびメソッド
PL/SQLサブプログラム | 対応するJavaクラスとメソッド |
---|---|
OracleUtils.dropSemanticModel |
|
OracleUtils.mergeModels |
|
OracleUtils.swapNames |
|
OracleUtils.removeDuplicates |
|
OracleUtils.renameModels |
これらのPL/SQLユーティリティ・サブプログラムの詳細は、「SEM_APISパッケージのサブプログラム」のリファレンス情報を参照してください。対応するJavaクラスとメソッドの詳細は、RDF Semantic Graph support for Apache JenaのAPIリファレンス・ドキュメント(Javadoc)を参照してください。
親トピック: サーバー側APIのサポート
6.13.4 推論オプション
Attachment
クラス(パッケージoracle.spatial.rdf.client.jena
)の次のメソッドを使用し、伴意コールにオプションを追加できます。
public void setUseLocalInference(boolean useLocalInference) public boolean getUseLocalInference() public void setDefGraphForLocalInference(String defaultGraphName) public String getDefGraphForLocalInference() public String getInferenceOption() public void setInferenceOption(String inferenceOption)
例6-8 推論オプションの指定
これらのメソッドの詳細は、Javadocを参照してください。
例6-8では、伴意の作成に、パラレル推論(並列度4を使用)とRAW形式を有効化しています。また、伴意の作成に、performInference
メソッドを使用(SEM_APIS.CREATE_ENTAILMENT PL/SQLプロシージャの使用と同じ)します。
import java.io.*; import com.hp.hpl.jena.query.*; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.util.FileManager; import com.hp.hpl.jena.util.iterator.*; import oracle.spatial.rdf.client.jena.*; import com.hp.hpl.jena.graph.*; import com.hp.hpl.jena.update.*; import com.hp.hpl.jena.sparql.core.DatasetImpl; public class TestNewInference { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; PrintStream psOut = System.out; Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); String szTBoxName = "test_new_tbox"; { // First construct a TBox and load a few axioms ModelOracleSem modelTBox = ModelOracleSem.createOracleSemModel(oracle, szTBoxName); String insertString = " PREFIX my: <http://my.com/> " + " PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> " + " INSERT DATA " + " { my:C1 rdfs:subClassOf my:C2 . " + " my:C2 rdfs:subClassOf my:C3 . " + " my:C3 rdfs:subClassOf my:C4 . " + " } "; UpdateAction.parseExecute(insertString, modelTBox); modelTBox.close(); } String szABoxName = "test_new_abox"; { // Construct an ABox and load a few quads ModelOracleSem modelABox = ModelOracleSem.createOracleSemModel(oracle, szABoxName); DatasetGraphOracleSem dataset = DatasetGraphOracleSem.createFrom(modelABox.getGraph()); modelABox.close(); String insertString = " PREFIX my: <http://my.com/> " + " PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> " + " INSERT DATA " + " { GRAPH my:G1 { my:I1 rdf:type my:C1 . " + " my:I2 rdf:type my:C2 . " + " } " + " }; " + " INSERT DATA " + " { GRAPH my:G2 { my:J1 rdf:type my:C3 . " + " } " + " } "; UpdateAction.parseExecute(insertString, dataset); dataset.close(); } String[] attachedModels = new String[1]; attachedModels[0] = szTBoxName; String[] attachedRBs = {"OWL2RL"}; Attachment attachment = Attachment.createInstance( attachedModels, attachedRBs, InferenceMaintenanceMode.NO_UPDATE, QueryOptions.ALLOW_QUERY_INVALID); // We are going to run named graph based local inference attachment.setUseLocalInference(true); // Set the default graph (TBox) attachment.setDefGraphForLocalInference(szTBoxName); // Set the inference option to use parallel inference // with a degree of 4, and RAW format. attachment.setInferenceOption("DOP=4,RAW8=T"); GraphOracleSem graph = new GraphOracleSem( oracle, szABoxName, attachment ); DatasetGraphOracleSem dsgos = DatasetGraphOracleSem.createFrom(graph); graph.close(); // Invoke create_entailment PL/SQL API dsgos.performInference(); psOut.println("TestNewInference: # of inferred graph " + Long.toString(dsgos.getInferredGraphSize())); String queryString = " SELECT ?g ?s ?p ?o WHERE { GRAPH ?g {?s ?p ?o } } " ; Query query = QueryFactory.create(queryString, Syntax.syntaxARQ); QueryExecution qexec = QueryExecutionFactory.create( query, DatasetImpl.wrap(dsgos)); ResultSet results = qexec.execSelect(); ResultSetFormatter.out(psOut, results); dsgos.close(); oracle.dispose(); } }
例6-8の出力は、次のとおりです。
TestNewInference: # of inferred graph 9 -------------------------------------------------------------------------------------------------------------------- | g | s | p | o | ==================================================================================================================== | <http://my.com/G1> | <http://my.com/I2> | <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://my.com/C3> | | <http://my.com/G1> | <http://my.com/I2> | <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://my.com/C2> | | <http://my.com/G1> | <http://my.com/I2> | <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://my.com/C4> | | <http://my.com/G1> | <http://my.com/I1> | <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://my.com/C3> | | <http://my.com/G1> | <http://my.com/I1> | <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://my.com/C1> | | <http://my.com/G1> | <http://my.com/I1> | <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://my.com/C2> | | <http://my.com/G1> | <http://my.com/I1> | <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://my.com/C4> | | <http://my.com/G2> | <http://my.com/J1> | <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://my.com/C3> | | <http://my.com/G2> | <http://my.com/J1> | <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> | <http://my.com/C4> | --------------------------------------------------------------------------------------------------------------------
推論の詳しい使用方法は、「OWL推論の使用方法」を参照してください。
親トピック: サーバー側APIのサポート
6.13.5 非推奨となったPelletInfGraphクラスのサポート
support for Apache JenaでのPelletInfGraph
クラスのサポートは、非推奨になりました。かわりに、Oracle Database向けのリーゾナPelletDb OWL 2を介して、より最適化されたOracle/Pellet統合を使用する必要があります。
親トピック: サーバー側APIのサポート
6.14 RDF Semantic Graph Support for Apache Jenaを使用したバルク・ロード
膨大な数のRDF/OWLデータ・ファイルをOracle Databaseに簡単にロードするには、OracleBulkUpdateHandler
JavaクラスのprepareBulk
メソッドとcompleteBulk
メソッドを使用します。
OracleBulkUpdateHandler
クラスのaddInBulk
メソッドは、グラフまたはモデルのトリプルをOracle Databaseにバルクロード方式でロードできます。グラフまたはモデルがJenaインメモリー・グラフまたはモデルである場合、操作は物理メモリーのサイズによって制限されます。prepareBulk
メソッドは、Jenaのインメモリー・グラフまたはモデルをバイパスし、RDFデータ・ファイルへの直接入力ストリームを取得してデータを解析し、基礎となるステージング表にトリプルをロードします。ステージング表および長いリテラルを格納するための添付表が存在しない場合は、自動的に作成されます。
prepareBulk
メソッドは、複数のデータ・ファイルを同じ基礎となるステージング表へロードするために複数回コールできます。ハードウェア・システムがロードバランシングされており、複数のCPUコアによる十分なI/Oキャパシティが確保されている場合には、同時にコールすることもできます。
すべてのデータ・ファイルがprepareBulk
メソッドによって処理されると、completeBulk
を起動して、すべてのデータをセマンティク・ネットワークにロードできます。
例6-9 ステージング表へのデータのロード(prepareBulk)
例6-9に、ディレクトリdir_1
のデータ・ファイルすべてを、基礎となるステージング表へロードする方法を示します。長いリテラルがサポートされ、別々の表に格納されます。記憶域容量を節約するため、GZIPを使用してデータ・ファイルを圧縮することができ、そのデータ・ファイルがGZIPを使用して圧縮されているかどうかを、prepareBulk
メソッドで自動的に検出できます。
Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); GraphOracleSem graph = new GraphOracleSem(oracle, szModelName); PrintStream psOut = System.out; String dirname = "dir_1"; File fileDir = new File(dirname); String[] szAllFiles = fileDir.list(); // loop through all the files in a directory for (int idx = 0; idx < szAllFiles.length; idx++) { String szIndFileName = dirname + File.separator + szAllFiles[idx]; psOut.println("process to [ID = " + idx + " ] file " + szIndFileName); psOut.flush(); try { InputStream is = new FileInputStream(szIndFileName); graph.getBulkUpdateHandler().prepareBulk( is, // input stream "http://example.com", // base URI "RDF/XML", // data file type: can be RDF/XML, N-TRIPLE, etc. "SEMTS", // tablespace null, // flags null, // listener null // staging table name. ); is.close(); } catch (Throwable t) { psOut.println("Hit exception " + t.getMessage()); } } graph.close(); oracle.dispose();
例6-9のコードは、新しいOracleオブジェクトの作成から、そのOracleオブジェクトを破棄して終了するまでをパラレルで実行できます。データベースのハードウェア・システム上に、クワッド-コアCPUと十分なI/O容量がある場合、すべてのデータ・ファイルを4つの別々のディレクトリ(dir_1
dir_2
、dir_3
およびdir_4
)に分割して保存することができます。4つのJavaプロセス・スレッドを起動し、それらのディレクトリで別々に同時に動作させることができます。(詳細は、「パラレル(マルチスレッド)モードでのprepareBulkの使用」を参照してください。)
例6-10 ステージング表からセマンティク・ネットワーク(completeBulk)へのデータのロード
すべてのデータ・ファイルが処理された後、1回だけcompleteBulk
メソッドを起動し、例6-10に示すとおり、ステージング表のデータをセマンティク・ネットワークにロードできます。長いリテラルを持つトリプルもロードされます。
graph.getBulkUpdateHandler().completeBulk( null, // flags for invoking SEM_APIS.bulk_load_from_staging_table null // staging table name );
また、prepareBulk
メソッドは、Jenaモデルも入力データソースとして取得でき、この場合は、そのJenaモデルのトリプルを基礎となるステージング表にロードします。詳細は、Javadocを参照してください。
例6-11 prepareBulkでのRDFaの使用
Jenaモデルとデータ・ファイルからトリプルをロードする以外に、prepareBulk
メソッドは、例6-11に示すとおり、RDFaをサポートします。(RDFaについては、http://www.w3.org/TR/xhtml-rdfa-primer/
を参照してください。)
graph.getBulkUpdateHandler().prepareBulk( rdfaUrl, // url to a web page using RDFa "SEMTS", // tablespace null, // flags null, // listener null // staging table name );
RDFaを解析するには、関連するjava-rdfa
ライブラリをクラスパスに含める必要があります。その他の設定やAPIコールは必要ありません。(java-rdfaの詳細は、http://www.rootdev.net/maven/projects/java-rdfa/
およびProject Informationの下のその他のトピックを参照してください。)
rdfaUrl
がファイアウォールの外側にある場合は、次のHTTPプロキシ関連のJava VMプロパティを設定する必要がある場合があります。
-Dhttp.proxyPort=... -Dhttp.proxyHost=...
例6-12 DatasetGraphへのクワッドのロード
この項の前述の例では、トリプル・データを単一のグラフにロードします。複数の名前付きグラフにわたる場合がある(NQUADS形式のデータなど)クワッド・データのロードには、DatasetGraphOracleSem
クラスの使用が必要です。例6-12
に示すとおり、DatasetGraphOracleSem
クラスはBulkUpdateHandler
APIを使用しませんが、同様のprepareBulk
インタフェースとcompleteBulkインタフェースを提供します。
Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); // Can only create DatasetGraphOracleSem from an existing GraphOracleSem GraphOracleSem graph = new GraphOracleSem(oracle, szModelName); DatasetGraphOracleSem dataset = DatasetGraphOracleSem.createFrom(graph); // Don't need graph anymore, close it to free resources graph.close(); try { InputStream is = new FileInputStream(szFileName); // load NQUADS file into a staging table. This file can be gzipp'ed. dataset.prepareBulk( is, // input stream "http://my.base/", // base URI "N-QUADS", // data file type; can be "TRIG" "SEMTS", // tablespace null, // flags null, // listener null, // staging table name false // truncate staging table before load ); // Load quads from staging table into the dataset dataset.completeBulk( null, // flags; can be "PARSE PARALLEL_CREATE_INDEX PARALLEL=4 // mbv_method=shadow" on a quad core machine null // staging table name ); } catch (Throwable t) { System.out.println("Hit exception " + t.getMessage()); } finally { dataset.close(); oracle.dispose(); }
6.14.1 パラレル(マルチスレッド)・モードでのprepareBulkの使用
例6-9には、ファイル・システム・ディレクトリ下の一連のファイルを、Oracle Database表(ステージング表)へ、順番にロードする方法が示されていました。例6-13では、一連のファイルを同時にOracle表(ステージング表)にロードします。並列度は、入力パラメータiMaxThreads
によって制御されます。
4つ以上のCPUコアによる均等なハードウェア設定で、iMaxThreads
に8(または16)を設定すると、多数のデータ・ファイルが処理される場合に、prepareBulk
操作の速度を大幅に向上できます。
例6-13 iMaxThreadsによるprepareBulkの使用
public void testPrepareInParallel(String jdbcUrl, String user, String password, String modelName, String lang, String tbs, String dirname, int iMaxThreads, PrintStream psOut) throws SQLException, IOException, InterruptedException { File dir = new File(dirname); File[] files = dir.listFiles(); // create a set of physical Oracle connections and graph objects Oracle[] oracles = new Oracle[iMaxThreads]; GraphOracleSem[] graphs = new GraphOracleSem[iMaxThreads]; for (int idx = 0; idx < iMaxThreads; idx++) { oracles[idx] = new Oracle(jdbcUrl, user, password); graphs[idx] = new GraphOracleSem(oracles[idx], modelName); } PrepareWorker[] workers = new PrepareWorker[iMaxThreads]; Thread[] threads = new Thread[iMaxThreads]; for (int idx = 0; idx < iMaxThreads; idx++) { workers[idx] = new PrepareWorker( graphs[idx], files, idx, iMaxThreads, lang, tbs, psOut ); threads[idx] = new Thread(workers[idx], workers[idx].getName()); psOut.println("testPrepareInParallel: PrepareWorker " + idx + " running"); threads[idx].start(); } psOut.println("testPrepareInParallel: all threads started"); for (int idx = 0; idx < iMaxThreads; idx++) { threads[idx].join(); } for (int idx = 0; idx < iMaxThreads; idx++) { graphs[idx].close(); oracles[idx].dispose(); } } static class PrepareWorker implements Runnable { GraphOracleSem graph = null; int idx; int threads; File[] files = null; String lang = null; String tbs = null; PrintStream psOut; public void run() { long lStartTime = System.currentTimeMillis(); for (int idxFile = idx; idxFile < files.length; idxFile += threads) { File file = files[idxFile]; try { FileInputStream fis = new FileInputStream(file); graph.getBulkUpdateHandler().prepareBulk( fis, "http://base.com/", lang, tbs, null, // flags new MyListener(psOut), // listener null // table name ); fis.close(); } catch (Exception e) { psOut.println("PrepareWorker: thread ["+getName()+"] error "+ e.getMessage()); } psOut.println("PrepareWorker: thread ["+getName()+"] done to " + idxFile + ", file = " + file.toString() + " in (ms) " + (System.currentTimeMillis() - lStartTime)); } } public PrepareWorker(GraphOracleSem graph, File[] files, int idx, int threads, String lang, String tbs, PrintStream psOut) { this.graph = graph; this.files = files; this.psOut = psOut; this.idx = idx; this.threads = threads; this.files = files; this.lang = lang; this.tbs = tbs ; } public String getName() { return "PrepareWorker" + idx; } } static class MyListener implements StatusListener { PrintStream m_ps = null; public MyListener(PrintStream ps) { m_ps = ps; } long lLastBatch = 0; public void statusChanged(long count) { if (count - lLastBatch >= 10000) { m_ps.println("process to " + Long.toString(count)); lLastBatch = count; } } public int illegalStmtEncountered(Node graphNode, Triple triple, long count) { m_ps.println("hit illegal statement with object " + triple.getObject().toString()); return 0; // skip it } }
6.14.2 データ・ロード中の無効な構文の処理
prepareBulk
を使用すると、無効なトリプルとクワッドをスキップできます。この機能は、ソースのRDFデータに構文エラーが含まれることが考えられる場合に有用です。例6-14で、StatusListener
インタフェースのカスタマイズされた実装(パッケージoracle.spatial.rdf.client.jena
で定義される)が、prepareBulkへのパラメータとして渡されます。この例で、illegalStmtEncountered
メソッドは、prepareBulk
が無効なトリプルをスキップして進むことができるように、その無効なトリプルのオブジェクト・フィールドを出力し、0を戻します。
例6-14 無効な構文によるトリプルのスキップ
.... Oracle oracle = new Oracle(jdbcUrl, user, password); GraphOracleSem graph = new GraphOracleSem(oracle, modelName); PrintStream psOut = System.err; graph.getBulkUpdateHandler().prepareBulk( new FileInputStream(rdfDataFilename), "http://base.com/", // base lang, // data format, can be "N-TRIPLES" "RDF/XML" ... tbs, // tablespace name null, // flags new MyListener(psOut), // call back to show progress and also process illegal triples/quads null, // tableName, if null use default names false // truncate existing staging tables ); graph.close(); oracle.dispose(); .... // A customized StatusListener interface implementation public class MyListener implements StatusListener { PrintStream m_ps = null; public MyListener(PrintStream ps) { m_ps = ps; } public void statusChanged(long count) { // m_ps.println("process to " + Long.toString(count)); } public int illegalStmtEncountered(Node graphNode, Triple triple, long count) { m_ps.println("hit illegal statement with object " + triple.getObject().toString()); return 0; // skip it } }
6.15 変数名の自動変更
以前は正常終了しなかった特定の問合せが、変数名の自動変更で使用できるようになることがあります。
以前、SPARQL問合せで使用された変数名は、SQL文の一部としてOracle Databaseに直接渡されました。変数名にSQLまたはPL/SQLの予約済キーワードを含めると、その問合せは実行できませんでした。たとえば、次のSPARQL問合せは、dateという語がOracle DatabaseのSQL処理エンジンにとって特別な意味であることが理由で失敗していました。
select ?date { :event :happenedOn ?date }
現在では、この問合せは失敗しません。問合せが、実行のためにOracle Databaseに送信される前にスマート・スキャンが実行され、特定の予約済変数名(あるいは非常に長い変数名)の自動置換が実行されるためです。置換は、予約されたキーワード・リスト(sdordfclient.jar
内の次のファイルに格納されている)に基づいています。
oracle/spatial/rdf/client/jena/oracle_sem_reserved_keywords.lst
このファイルには100以上のエントリが含まれており、必要に応じてファイルを編集し、エントリを追加できます。
次は、SQLまたはPL/SQLの予約済キーワードを変数として使用するSPARQL問合せの例で、変数名が自動的に変更されるため、正常に実行されます。
-
変数名に
SELECT
を使用する問合せ:PREFIX foaf: <http://xmlns.com/foaf/0.1/> select ?SELECT ?z where { ?SELECT foaf:name ?y. optional {?SELECT foaf:knows ?z.} }
-
変数名に
ARRAY
とDATE
を使用する問合せ:PREFIX x: <http://example.com#> construct { ?ARRAY x:date ?date . } where { ?ARRAY x:happenedOn ?date . }
6.16 JavaScript Object Notation (JSON)形式のサポート
JavaScript Object Notation (JSON)形式は、SPARQL問合せのレスポンスのためにサポートされます。JSONデータ形式は単純、コンパクトで、JavaScriptプログラムに適しています。
たとえば、次のJavaコード・スニペット(ResultSetFormatter.outputAsJSON
メソッドをコールする)があるとします。
Oracle oracle = new Oracle(jdbcUrl, user, password);
GraphOracleSem graph = new GraphOracleSem(oracle, modelName);
ModelOracleSem model = new ModelOracleSem(graph);
graph.add(new Triple(
Node.createURI("http://ds1"),
Node.createURI("http://dp1"),
Node.createURI("http://do1")
)
);
graph.add(new Triple(
Node.createURI("http://ds2"),
Node.createURI("http://dp2"),
Node.createURI("http://do2")
)
);
graph.commitTransaction();
Query q = QueryFactory.create("select ?s ?p ?o where {?s ?p ?o}",
Syntax.syntaxARQ);
QueryExecution qexec = QueryExecutionFactory.create(q, model);
ResultSet results = qexec.execSelect();
ResultSetFormatter.outputAsJSON(System.out, results);
JSON出力は次のとおりです。
{ "head": { "vars": [ "s" , "p" , "o" ] } , "results": { "bindings": [ { "s": { "type": "uri" , "value": "http://ds1" } , "p": { "type": "uri" , "value": "http://dp1" } , "o": { "type": "uri" , "value": "http://do1" } } , { "s": { "type": "uri" , "value": "http://ds2" } , "p": { "type": "uri" , "value": "http://dp2" } , "o": { "type": "uri" , "value": "http://do2" } } ] } }
前述の例を、Oracle Databaseに対して直接ではなく、リモートのSPARQLエンドポイントを問い合せるようにするには、次のように変更します。(リモートのSPARQLエンドポイントがファイアウォールの外側にある場合、HTTPプロキシを設定する必要があります。)
Query q = QueryFactory.create("select ?s ?p ?o where {?s ?p ?o}", Syntax.syntaxARQ); QueryExecution qe = QueryExecutionFactory.sparqlService(sparqlURL, q); ResultSet results = qexec.execSelect(); ResultSetFormatter.outputAsJSON(System.out, results);
この項の最初の例を名前付きグラフに拡張するため、次のコード・スニペットでは、同じOracleモデルに2つのクワッドを追加し、名前付きグラフベースのSPARQL問合せを実行して、問合せ出力をJSON形式にシリアライズします。
DatasetGraphOracleSem dsgos = DatasetGraphOracleSem.createFrom(graph);
graph.close();
dsgos.add(new Quad(Node.createURI("http://g1"),
Node.createURI("http://s1"),
Node.createURI("http://p1"),
Node.createURI("http://o1")
)
);
dsgos.add(new Quad(Node.createURI("http://g2"),
Node.createURI("http://s2"),
Node.createURI("http://p2"),
Node.createURI("http://o2")
)
);
Query q1 = QueryFactory.create(
"select ?g ?s ?p ?o where { GRAPH ?g {?s ?p ?o} }");
QueryExecution qexec1 = QueryExecutionFactory.create(q1,
DatasetImpl.wrap(dsgos));
ResultSet results1 = qexec1.execSelect();
ResultSetFormatter.outputAsJSON(System.out, results1);
dsgos.close();
oracle.dispose();
JSON出力は次のとおりです。
{ "head": { "vars": [ "g" , "s" , "p" , "o" ] } , "results": { "bindings": [ { "g": { "type": "uri" , "value": "http://g1" } , "s": { "type": "uri" , "value": "http://s1" } , "p": { "type": "uri" , "value": "http://p1" } , "o": { "type": "uri" , "value": "http://o1" } } , { "g": { "type": "uri" , "value": "http://g2" } , "s": { "type": "uri" , "value": "http://s2" } , "p": { "type": "uri" , "value": "http://p2" } , "o": { "type": "uri" , "value": "http://o2" } } ] } }
また、次の例のように、JosekiベースのSPARQLエンドポイントに対してHTTPを通してJSONレスポンスを取得することもできます。通常、SPARQL Webサービス・エンドポイントに対してSPARQL問合せを実行する場合は、Accept request-head
フィールドはapplication/sparql-results+xml
に設定されます。JSON出力形式の場合は、Accept request-head
フィールドをapplication/sparql-results+json
に置き換えます。
http://hostname:7001/joseki/oracle?query=<URL_ENCODED_SPARQL_QUERY>&output=json
6.17 その他の推奨事項とガイドライン
この項では、SPARQL問合せに関連する様々な推奨事項およびその他の情報について説明します。
6.17.1 EXISTSまたはNOT EXISTSにかわるBOUNDまたは!BOUNDの使用
パフォーマンスをさらに向上するには、EXISTS
やNOT EXISTS
のかわりに、BOUND
や!BOUND
を使用します。
親トピック: その他の推奨事項とガイドライン
6.17.2 SPARQL 1.1 SELECT式
関数が現在Oracle Databaseでサポートされていなくても、パフォーマンスに大きなオーバーヘッドを発生させることなく、SPARQL 1.1のSELECT表現を使用できます。例には次のものがあります。
-- Query using MD5 and SHA1 functions PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> PREFIX eg: <http://biometrics.example/ns#> SELECT ?name (md5(?name) as ?name_in_md5) (sha1(?email) as ?sha1) WHERE { ?x foaf:name ?name ; eg:email ?email . } -- Query using CONCAT function PREFIX foaf: <http://xmlns.com/foaf/0.1/> SELECT ( CONCAT(?G, " ", ?S) AS ?name ) WHERE { ?P foaf:givenName ?G ; foaf:surname ?S }
親トピック: その他の推奨事項とガイドライン
6.17.3 bnode(空白ノード)を含む構文
bnodeを含む構文を問合せパターンの中で自由に使用できます。たとえば、次のbnode関連の構文はパーサー・レベルでサポートされるため、各構文はそのトリプル問合せパターンベースの完全なバージョンと同等です。
:x :q [ :p "v" ] . (1 ?x 3 4) :p "w" . (1 [:p :q] ( 2 ) ) .
親トピック: その他の推奨事項とガイドライン
6.17.4 SERVICE句の制限
SPARQL 1.1のフェデレーテッド問合せを記述する際に、SERVICE句内の副問合せで戻される行に対して制限を設定できます。これによって、ローカルのリポジトリとリモートのSPARQLエンドポイントの間で転送されるデータ量を効果的に制限できます。
たとえば、次の問合せでは、SERVICE句の副問合せでlimit 100
を指定しています。
PREFIX : <http://example.com/> SELECT ?s ?o WHERE { ?s :name "CA" SERVICE <http://REMOTE_SPARQL_ENDPOINT_HERE> { select ?s ?o {?s :info ?o} limit 100 } }
親トピック: その他の推奨事項とガイドライン
6.17.5 OracleGraphWrapperForOntModelクラスによるパフォーマンス向上
Jena OntModel
クラスを使用すると、Jenaモデルに格納されているオントロジを作成、変更および分析できます。ただし、OntModel
の実装は、データベースに格納されているセマンティク・データにとって最適とはいえません。OracleモデルでOntModel
を使用する場合は、次善のパフォーマンスとなります。そのため、クラスOracleGraphWrapperForOntModel
は、このようなパフォーマンスの問題を軽減するために作成されました。
OracleGraphWrapperForOntModel
クラスは、Jena Graph
インタフェースを実装し、Jena OntModel
APIで使用するためのOracle RDF/OWLモデルに基づくグラフを表します。OracleGraphWrapperForOntModel
クラスは、問合せに対する持続的な変更と応答のため、2つのセマンティク・ストアを組み合せて使用します。両方のセマンティク・ストアに同じデータが含まれますが、一方はメモリーに存在し、他方はOracle Databaseに存在します。
OntModel
を介して問合せがあると、OracleGraphWrapperForOntModel
グラフは、パフォーマンスを向上するためにインメモリー・ストアに対して問合せを実行します。ただしOracleGraphWrapperForOntModel
クラスでは、クラスの追加または削除など、両方のストアに変更を適用することによって、OntModel
を介して変更を行います。
ハイブリッドな方法であることから、OracleGraphWrapperForOntModel
グラフでは、メモリーにオントロジのコピーを格納するため、十分なメモリーがJVMに割り当てられている必要があります。内部の実験では、およそ3,000,000のトリプルによるオントロジで、6GB以上の物理メモリーを必要とすることが分かっています。
例6-15 OntModelとOracle Databaseに格納されたオントロジの使用
例6-15では、OntModel
APIとOracleモデルに格納されている既存のオントロジを使用する方法を表示します
// Set up connection to Oracle semantic store and the Oracle model // containing the ontology Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); GraphOracleSem oracleGraph = new GraphOracleSem(oracle, szModelName); // Create a new hybrid graph using the oracle graph to persist // changes. This method will copy all the data from the oracle graph // into an in-memory graph, which may significantly increase JVM memory // usage. Graph hybridGraph = OracleGraphWrapperForOntModel.getInstance(oracleGraph); // Build a model around the hybrid graph and wrap the model with Jena's // OntModel Model model = ModelFactory.createModelForGraph(hybridGraph); OntModel ontModel = ModelFactory.createOntologyModel(ontModelSpec, model); // Perform operations on the ontology OntClass personClass = ontModel.createClass("<http://someuri/person>"); ontModel.createIndividual(personClass); // Close resources (will also close oracleGraph)! hybridGraph.close(); ontModel.close();
OracleGraphWrapperForOntModel
を使用して作成されたOntModel
オブジェクトは、(別のOntModel
、または同じ基礎となるモデルを参照する別のOracleグラフを介した)別のプロセスによって行われた、基礎となるOracleモデルへの変更を反映しません。オントロジへのすべての変更は、モデルまたはグラフが閉じられるまで、単一のOntModel
オブジェクトと、その基礎となるOracleGraphWrapperForOntModel
グラフを介して実行される必要があります。
例6-16 カスタム・インメモリー・グラフの使用
OracleGraphWrapperForOntModel
によって使用されるデフォルトのインメモリー・セマンティク・ストアが、オントロジとシステムにとって十分ではない場合、インメモリー・ストアとして使用するカスタム・グラフを指定するためのインタフェースが、クラスによって提供されます。例6-16に、カスタム・インメモリー・グラフを使用してOntModel
からの問合せに応答するOracleGraphWrapperForOntModel
を作成する方法を示します。
// Set up connection to Oracle semantic store and the Oracle model // containing the ontology Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); GraphOracleSem oracleGraph = new GraphOracleSem(oracle, szModelName); // Create a custom in-memory graph to use instead of the default // Jena in-memory graph for quickly answering OntModel queries. // Note that this graph does not *need* to be in-memory, but in-memory // is preferred. GraphBase queryGraph = new CustomInMemoryGraphImpl(); // Create a new hybrid graph using the oracle graph to persist // changes and the custom in-memory graph to answer queries. // Also set the degree of parallelism to use when copying data from // the oracle graph to the querying graph. int degreeOfParallelism = 4; Graph hybridGraph = OracleGraphWrapperForOntModel.getInstance(oracleGraph, queryGraph, degreeOfParallelism); // Build a model and wrap the model with Jena's OntModel Model model = ModelFactory.createModelForGraph(hybridGraph); OntModel ontModel = ModelFactory.createOntologyModel(ontModelSpec, model); // Perform operations on the ontology // ... // Close resources (will close oracleGraph and queryGraph)! hybridGraph.close(); ontModel.close();
親トピック: その他の推奨事項とガイドライン
6.18 RDF Semantic Graph support for Apache Jenaを使用する問合せ例
この項では、support for Apache Jenaを使用した問合せの例を示します。それぞれの例は個々に完結しており、通常はモデルの作成、トリプルの作成、推論を含む可能性のある問合せの実行、結果の表示およびモデルの削除を行います。
この項では、次の手順を実行する問合せについて説明します。
-
URLによるオントロジの参照、およびローカル・ファイルからオントロジをバルク・ロードする方法の両方によって、universityオントロジの例で表明されたトリプルと表明に加えて推論されたトリプルをカウントします。
-
familyオントロジを使用して複数のSPARQL問合せを実行します(LIMIT、OFFSET、TIMEOUT、DOP (並列度)、ASK、DESCRIBE、CONSTRUCT、GRAPH、ALLOW_DUP (複数のモデルによる重複トリプル)、SPARUL (データの挿入)などの機能が含まれます)。
-
ARQ組込み関数を使用します。
-
SELECTキャスト問合せを使用します。
-
OracleConnectionを使用してOracle Databaseをインスタンス化します。
-
Oracle Database接続プーリングを使用します。
問合せを実行するには、次の手順を実行する必要があります。
-
コードをJavaソース・ファイルに含めます。この項で使用される例は、support for Apache Jenaダウンロードの
examples
ディレクトリのファイルで提供されています。 -
Javaソース・ファイルをコンパイルします。たとえば、次のようにします。
> javac -classpath ../jar/'*' Test.java
注意:
javac
コマンドとjava
コマンドは、それぞれ1行のコマンドである必要があります。 -
コンパイルされたファイルを実行します。たとえば、次のようにします。
> java -classpath ./:../jar/'*' Test jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
- Test.java: 家族関係を問い合せる
- Test6.java: OWLオントロジをロードしてOWLPrime推論を実行する
- Test7.java: OWLオントロジをバルク・ロードしてOWLPrime推論を実行する
- Test8.java: SPARQL OPTIONAL問合せ
- Test9.java: SPARQL問合せでのLIMITおよびOFFSETの使用
- Test10.java: SPARQL問合せでのTIMEOUTおよびDOPの使用
- Test11.java: 名前付きグラフを含む問合せ
- Test12.java: SPARQL ASK問合せ
- Test13.java: SPARQL DESCRIBE問合せ
- Test14.java: SPARQL CONSTRUCT問合せ
- Test15.java: 複数のモデルを問い合せ、重複の許可を指定する
- Test16.java: SPARQLの更新
- Test17.java: SPARQL問合せでのARQ組込みファンクションの使用
- Test18.java: SELECTキャスト問合せ
- Test19.java: OracleConnectionを使用してOracle Databaseをインスタンス化する
- Test20.java: Oracle Database接続プーリング
6.18.1 Test.java: 家族関係の問合せ
例6-17 家族関係を問い合せる
例6-17は、JohnがMaryの父であることを指定し、次に、各fatherOf
関係で主語と目的語を選択して表示します。
import oracle.spatial.rdf.client.jena.*; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.graph.*; import com.hp.hpl.jena.query.*; public class Test { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; String szModelName = args[3]; Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); Model model = ModelOracleSem.createOracleSemModel( oracle, szModelName); model.getGraph().add(Triple.create( Node.createURI("http://example.com/John"), Node.createURI("http://example.com/fatherOf"), Node.createURI("http://example.com/Mary"))); Query query = QueryFactory.create( "select ?f ?k WHERE {?f <http://example.com/fatherOf> ?k .}"); QueryExecution qexec = QueryExecutionFactory.create(query, model); ResultSet results = qexec.execSelect(); ResultSetFormatter.out(System.out, results, query); model.close(); oracle.dispose(); } }
次のコマンドは、javaコマンドの想定される出力に加え、例6-17
をコンパイルして実行します。
javac -classpath ../jar/'*' Test.java
java -classpath ./:../jar/'*' Test jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
---------------------------------------------------------
| f | k |
=========================================================
| <http://example.com/John> | <http://example.com/Mary> |
---------------------------------------------------------
6.18.2 Test6.java: OWLオントロジのロードとOWLPrime推論の実行
例6-18は、OWLオントロジをロードして、OWLPrime推論を実行します。OWLオントロジがRDF/XML形式であり、Oracleにロードされた後にN-triple形式でシリアライズされることに注意してください。また、表明および推論されたトリプルの数を問い合せます。
この例のオントロジはhttp://swat.cse.lehigh.edu/onto/univ-bench.owl
から入手することができます。そこには、ロール、リソースおよび大学環境での関係が記述されています。
例6-18 OWLオントロジをロードし、OWLPrime推論を実行する
import java.io.*; import com.hp.hpl.jena.query.*; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.util.FileManager; import oracle.spatial.rdf.client.jena.*; public class Test6 { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; String szModelName = args[3]; Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); Model model = ModelOracleSem.createOracleSemModel(oracle, szModelName); // load UNIV ontology InputStream in = FileManager.get().open("./univ-bench.owl" ); model.read(in, null); OutputStream os = new FileOutputStream("./univ-bench.nt"); model.write(os, "N-TRIPLE"); os.close(); String queryString = " SELECT ?subject ?prop ?object WHERE { ?subject ?prop ?object } "; Query query = QueryFactory.create(queryString) ; QueryExecution qexec = QueryExecutionFactory.create(query, model) ; try { int iTriplesCount = 0; ResultSet results = qexec.execSelect() ; for ( ; results.hasNext() ; ) { QuerySolution soln = results.nextSolution() ; iTriplesCount++; } System.out.println("Asserted triples count: " + iTriplesCount); } finally { qexec.close() ; } Attachment attachment = Attachment.createInstance( new String[] {}, "OWLPRIME", InferenceMaintenanceMode.NO_UPDATE, QueryOptions.DEFAULT); GraphOracleSem graph = new GraphOracleSem(oracle, szModelName, attachment); graph.analyze(); graph.performInference(); query = QueryFactory.create(queryString) ; qexec = QueryExecutionFactory.create(query,new ModelOracleSem(graph)) ; try { int iTriplesCount = 0; ResultSet results = qexec.execSelect() ; for ( ; results.hasNext() ; ) { QuerySolution soln = results.nextSolution() ; iTriplesCount++; } System.out.println("Asserted + Infered triples count: " + iTriplesCount); } finally { qexec.close() ; } model.close(); OracleUtils.dropSemanticModel(oracle, szModelName); oracle.dispose(); } }
次のコマンドは、javaコマンドの想定される出力に加え、例6-18
をコンパイルして実行します。
javac -classpath ../jar/'*' Test6.java
java -classpath ./:../jar/'*' Test6 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
Asserted triples count: 293
Asserted + Infered triples count: 340
この出力には、以前のバージョンのLUBMオントロジが反映されていることに注意してください。最新バージョンのオントロジには、より多くのトリプルがあります。
6.18.3 Test7.java: OWLオントロジをバルク・ロードしてOWLPrime推論を実行する
例6-19では、「Test6.java: OWLオントロジのロードとOWLPrime推論の実行」と同じOWLオントロジがロードされますが、バルク・ローダーの使用によりローカル・ファイルに保存されます。オントロジは増分およびバッチ・ローダーを使用してロードすることもでき、例にはこれらの2つの方法も示されています。
例6-19 OWLオントロジをバルク・ロードし、OWLPrime推論を実行する
import java.io.*; import com.hp.hpl.jena.query.*; import com.hp.hpl.jena.graph.*; import com.hp.hpl.jena.rdf.model.*; import com.hp.hpl.jena.util.*; import oracle.spatial.rdf.client.jena.*; public class Test7 { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; String szModelName = args[3]; // in memory Jena Model Model model = ModelFactory.createDefaultModel(); InputStream is = FileManager.get().open("./univ-bench.owl"); model.read(is, "", "RDF/XML"); is.close(); Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); ModelOracleSem modelDest = ModelOracleSem.createOracleSemModel(oracle, szModelName); GraphOracleSem g = modelDest.getGraph(); g.dropApplicationTableIndex(); int method = 2; // try bulk loader String tbs = "SYSAUX"; // can be customized if (method == 0) { System.out.println("start incremental"); modelDest.add(model); System.out.println("end size " + modelDest.size()); } else if (method == 1) { System.out.println("start batch load"); g.getBulkUpdateHandler().addInBatch( GraphUtil.findAll(model.getGraph()), tbs); System.out.println("end size " + modelDest.size()); } else { System.out.println("start bulk load"); g.getBulkUpdateHandler().addInBulk( GraphUtil.findAll(model.getGraph()), tbs); System.out.println("end size " + modelDest.size()); } g.rebuildApplicationTableIndex(); long lCount = g.getCount(Triple.ANY); System.out.println("Asserted triples count: " + lCount); model.close(); OracleUtils.dropSemanticModel(oracle, szModelName); oracle.dispose(); } }
次のコマンドは、javaコマンドの想定される出力に加え、例6-19
をコンパイルして実行します。
javac -classpath ../jar/'*' Test7.java
java -classpath ./:../jar/'*' Test7 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
start bulk load
end size 293
Asserted triples count: 293
この出力には、以前のバージョンのLUBMオントロジが反映されていることに注意してください。最新バージョンのオントロジには、より多くのトリプルがあります。
6.18.4 Test8.java: SPARQL OPTIONAL問合せ
例6-20には、SPARQL OPTIONAL問合せが示されています。次の条件を持つトリプルを挿入します。
-
Johnは、Maryの親です。
-
Johnは、Jackの親です。
-
Maryは、Jillの親です。
次に親子関係を見つけ、必要に応じて孫(gkid)の関係も含めます。
例6-20 SPARQLのOPTIONAL問合せ
import java.io.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.util.FileManager;
import oracle.spatial.rdf.client.jena.*;
import com.hp.hpl.jena.graph.*;
public class Test8
{
public static void main(String[] args) throws Exception
{
String szJdbcURL = args[0];
String szUser = args[1];
String szPasswd = args[2];
String szModelName = args[3];
Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd);
ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle,
szModelName);
GraphOracleSem g = model.getGraph();
g.add(Triple.create(
Node.createURI("u:John"), Node.createURI("u:parentOf"),
Node.createURI("u:Mary")));
g.add(Triple.create(
Node.createURI("u:John"), Node.createURI("u:parentOf"),
Node.createURI("u:Jack")));
g.add(Triple.create(
Node.createURI("u:Mary"), Node.createURI("u:parentOf"),
Node.createURI("u:Jill")));
String queryString =
" SELECT ?s ?o ?gkid " +
" WHERE { ?s <u:parentOf> ?o . OPTIONAL {?o <u:parentOf> ?gkid }} ";
Query query = QueryFactory.create(queryString) ;
QueryExecution qexec = QueryExecutionFactory.create(query, model) ;
try {
int iMatchCount = 0;
ResultSet results = qexec.execSelect() ;
ResultSetFormatter.out(System.out, results, query);
}
finally {
qexec.close() ;
}
model.close();
OracleUtils.dropSemanticModel(oracle, szModelName);
oracle.dispose();
}
}
次のコマンドは、javaコマンドの想定される出力に加え、例6-20
をコンパイルして実行します。
javac -classpath ../jar/'*' Test8.java
java -classpath ./:../jar/'*' Test8 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
----------------------------------
| s | o | gkid |
==================================
| <u:John> | <u:Mary> | <u:Jill> |
| <u:Mary> | <u:Jill> | |
| <u:John> | <u:Jack> | |
----------------------------------
6.18.5 Test9.java: SPARQL問合せでのLIMITおよびOFFSETの使用
例6-21には、LIMITおよびOFFSETを使用するSPARQL問合せが示されています。次の条件を持つトリプルを挿入します。
-
Johnは、Maryの親です。
-
Johnは、Jackの親です。
-
Maryは、Jillの親です。
次に1つの親子関係(LIMIT 1)を検出し、出現した最初の2つの親子関係をスキップ(OFFSET 2)し、必要に応じて、検出された孫(gkid)の関係を含めます。
例6-21 SPARQL問合せでのLIMITおよびOFFSETの使用
import java.io.*; import com.hp.hpl.jena.query.*; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.util.FileManager; import oracle.spatial.rdf.client.jena.*; import com.hp.hpl.jena.graph.*; public class Test9 { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; String szModelName = args[3]; Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle, szModelName); GraphOracleSem g = model.getGraph(); g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"), Node.createURI("u:Mary"))); g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"), Node.createURI("u:Jack"))); g.add(Triple.create(Node.createURI("u:Mary"), Node.createURI("u:parentOf"), Node.createURI("u:Jill"))); String queryString = " SELECT ?s ?o ?gkid " + " WHERE { ?s <u:parentOf> ?o . OPTIONAL {?o <u:parentOf> ?gkid }} " + " LIMIT 1 OFFSET 2"; Query query = QueryFactory.create(queryString) ; QueryExecution qexec = QueryExecutionFactory.create(query, model) ; int iMatchCount = 0; ResultSet results = qexec.execSelect() ; ResultSetFormatter.out(System.out, results, query); qexec.close() ; model.close(); OracleUtils.dropSemanticModel(oracle, szModelName); oracle.dispose(); } }
次のコマンドは、javaコマンドの想定される出力に加え、例6-21
をコンパイルして実行します。
javac -classpath ../jar/'*' Test9.java
java -classpath ./:../jar/'*' Test9 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
------------------------------
| s | o | gkid |
==============================
| <u:John> | <u:Jack> | |
------------------------------
6.18.6 Test10.java: SPARQL問合せでのTIMEOUTおよびDOPの使用
例6-22に、「Test9.java: SPARQL問合せでのLIMITおよびOFFSETの使用」のSPARQL問合せに追加の機能(タイムアウト設定(TIMEOUT=1、(秒))およびパラレル実行設定(DOP=4))を使用した例を示します。
例6-22 SPARQL問合せでのTIMEOUTおよびDOPの使用
import java.io.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.util.FileManager;
import oracle.spatial.rdf.client.jena.*;
import com.hp.hpl.jena.graph.*;
public class Test10 {
public static void main(String[] args) throws Exception {
String szJdbcURL = args[0];
String szUser = args[1];
String szPasswd = args[2];
String szModelName = args[3];
Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd);
ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle, szModelName);
GraphOracleSem g = model.getGraph();
g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"),
Node.createURI("u:Mary")));
g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"),
Node.createURI("u:Jack")));
g.add(Triple.create(Node.createURI("u:Mary"), Node.createURI("u:parentOf"),
Node.createURI("u:Jill")));
String queryString =
" PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#dop=4,timeout=1> "
+ " SELECT ?s ?o ?gkid WHERE { ?s <u:parentOf> ?o . "
+ " OPTIONAL {?o <u:parentOf> ?gkid }} "
+ " LIMIT 1 OFFSET 2";
Query query = QueryFactory.create(queryString) ;
QueryExecution qexec = QueryExecutionFactory.create(query, model) ;
int iMatchCount = 0;
ResultSet results = qexec.execSelect() ;
ResultSetFormatter.out(System.out, results, query);
qexec.close() ;
model.close();
OracleUtils.dropSemanticModel(oracle, szModelName);
oracle.dispose();
}
}
次のコマンドは、javaコマンドの想定される出力に加え、例6-22
をコンパイルして実行します。
javac -classpath ../jar/'*' Test10.java
java -classpath ./:../jar/'*' Test10 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
------------------------------
| s | o | gkid |
==============================
| <u:John> | <u:Jack> | |
------------------------------
6.18.7 Test11.java: 名前付きグラフを含む問合せ
例6-23には、名前付きグラフを含む問合せが示されています。これには、名前付きグラフのURIとその作成者の情報を持つデフォルト・グラフが含まれます。問合せで、グラフ名、グラフの作成者およびfoaf:mbox
述語を使用して各名前付きグラフのメールボックスの値を確認できます。
例6-23 名前付きグラフ・ベースの問合せ
import java.io.*; import com.hp.hpl.jena.graph.*; import com.hp.hpl.jena.sparql.core.*; import com.hp.hpl.jena.query.*; import oracle.spatial.rdf.client.jena.*; public class Test11 { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; String szModelName = args[3]; Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); GraphOracleSem graph = new GraphOracleSem(oracle, szModelName); DatasetGraphOracleSem dataset = DatasetGraphOracleSem.createFrom(graph); // don't need the GraphOracleSem anymore, release resources graph.close(); // add data to the default graph dataset.add(new Quad( Quad.defaultGraphIRI, // specifies default graph Node.createURI("http://example.org/bob"), Node.createURI("http://purl.org/dc/elements/1.1/publisher"), Node.createLiteral("Bob Hacker"))); dataset.add(new Quad( Quad.defaultGraphIRI, // specifies default graph Node.createURI("http://example.org/alice"), Node.createURI("http://purl.org/dc/elements/1.1/publisher"), Node.createLiteral("alice Hacker"))); // add data to the bob named graph dataset.add(new Quad( Node.createURI("http://example.org/bob"), // graph name Node.createURI("urn:bob"), Node.createURI("http://xmlns.com/foaf/0.1/name"), Node.createLiteral("Bob"))); dataset.add(new Quad( Node.createURI("http://example.org/bob"), // graph name Node.createURI("urn:bob"), Node.createURI("http://xmlns.com/foaf/0.1/mbox"), Node.createURI("mailto:bob@example"))); // add data to the alice named graph dataset.add(new Quad( Node.createURI("http://example.org/alice"), // graph name Node.createURI("urn:alice"), Node.createURI("http://xmlns.com/foaf/0.1/name"), Node.createLiteral("Alice"))); dataset.add(new Quad( Node.createURI("http://example.org/alice"), // graph name Node.createURI("urn:alice"), Node.createURI("http://xmlns.com/foaf/0.1/mbox"), Node.createURI("mailto:alice@example"))); DataSource ds = DatasetFactory.create(dataset); String queryString = " PREFIX foaf: <http://xmlns.com/foaf/0.1/> " + " PREFIX dc: <http://purl.org/dc/elements/1.1/> " + " SELECT ?who ?graph ?mbox " + " FROM NAMED <http://example.org/alice> " + " FROM NAMED <http://example.org/bob> " + " WHERE " + " { " + " ?graph dc:publisher ?who . " + " GRAPH ?graph { ?x foaf:mbox ?mbox } " + " } "; Query query = QueryFactory.create(queryString); QueryExecution qexec = QueryExecutionFactory.create(query, ds); ResultSet results = qexec.execSelect(); ResultSetFormatter.out(System.out, results, query); qexec.close(); dataset.close(); oracle.dispose(); } }
次のコマンドは、javaコマンドの想定される出力に加え、例6-23
をコンパイルして実行します。
javac -classpath ./:./jena-2.6.4.jar:./sdordfclient.jar:./ojdbc6.jar:./slf4j-api-1.5.8.jar:./slf4j-log4j12-1.5.8.jar:./arq-2.8.8.jar:./xercesImpl-2.7.1.jar Test11.java java -classpath ./:../jar/'*' Test11 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1 ------------------------------------------------------------------------ | who | graph | mbox | ======================================================================== | "alice Hacker" | <http://example.org/alice> | <mailto:alice@example> | | "Bob Hacker" | <http://example.org/bob> | <mailto:bob@example> | ------------------------------------------------------------------------
6.18.8 Test12.java: SPARQL ASK問合せ
例6-24には、SPARQL ASK問合せが示されています。JohnがMaryの親であるという条件のトリプルを挿入します。次にJohnがMaryの親かどうかを確認します。
例6-24 SPARQLのASK問合せ
import java.io.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.util.FileManager;
import oracle.spatial.rdf.client.jena.*;
import com.hp.hpl.jena.graph.*;
public class Test12
{
public static void main(String[] args) throws Exception
{
String szJdbcURL = args[0];
String szUser = args[1];
String szPasswd = args[2];
String szModelName = args[3];
Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd);
ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle,
szModelName);
GraphOracleSem g = model.getGraph();
g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"),
Node.createURI("u:Mary")));
String queryString = " ASK { <u:John> <u:parentOf> <u:Mary> } ";
Query query = QueryFactory.create(queryString) ;
QueryExecution qexec = QueryExecutionFactory.create(query, model) ;
boolean b = qexec.execAsk();
System.out.println("ask result = " + ((b)?"TRUE":"FALSE"));
qexec.close() ;
model.close();
OracleUtils.dropSemanticModel(oracle, szModelName);
oracle.dispose();
}
}
次のコマンドは、javaコマンドの想定される出力に加え、例6-24
をコンパイルして実行します。
javac -classpath ../jar/'*' Test12.java
java -classpath ./:../jar/'*' Test12 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
ask result = TRUE
6.18.9 Test13.java: SPARQL DESCRIBE問合せ
例6-25には、SPARQL DESCRIBE問合せが示されています。次の条件を持つトリプルを挿入します。
-
Johnは、Maryの親です。
-
Johnは、Jackの親です。
-
Amyは、Jackの親です。
次に、Jackの親を含むすべての関係を検出します。
例6-25 SPARQLのDESCRIBE問合せ
import java.io.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.util.FileManager;
import oracle.spatial.rdf.client.jena.*;
import com.hp.hpl.jena.graph.*;
public class Test13
{
public static void main(String[] args) throws Exception
{
String szJdbcURL = args[0];
String szUser = args[1];
String szPasswd = args[2];
String szModelName = args[3];
Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd);
ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle, szModelName);
GraphOracleSem g = model.getGraph();
g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"),
Node.createURI("u:Mary")));
g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"),
Node.createURI("u:Jack")));
g.add(Triple.create(Node.createURI("u:Amy"), Node.createURI("u:parentOf"),
Node.createURI("u:Jack")));
String queryString = " DESCRIBE ?x WHERE {?x <u:parentOf> <u:Jack>}";
Query query = QueryFactory.create(queryString) ;
QueryExecution qexec = QueryExecutionFactory.create(query, model) ;
Model m = qexec.execDescribe();
System.out.println("describe result = " + m.toString());
qexec.close() ;
model.close();
OracleUtils.dropSemanticModel(oracle, szModelName);
oracle.dispose();
}
}
次のコマンドは、javaコマンドの想定される出力に加え、例6-25
をコンパイルして実行します。
javac -classpath ../jar/'*' Test13.java
java -classpath ./:../jar/'*' Test13 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
describe result = <ModelCom {u:Amy @u:parentOf u:Jack;
u:John @u:parentOf u:Jack; u:John @u:parentOf u:Mary} | [u:Amy, u:parentOf, u:Jack] [u:John, u:parentOf,
u:Jack] [u:John, u:parentOf, u:Mary]>
6.18.10 Test14.java: SPARQL CONSTRUCT問合せ
例6-26には、SPARQL CONSTRUCT問合せが示されています。次の条件を持つトリプルを挿入します。
-
Johnは、Maryの親です。
-
Johnは、Jackの親です。
-
Amyは、Jackの親です。
-
それぞれの親は、自分の子ども全員を愛しています。
次に、誰が誰を愛しているかについての情報でRDFグラフを構築します。
例6-26 SPARQLのCONSTRUCT問合せ
import java.io.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.util.FileManager;
import oracle.spatial.rdf.client.jena.*;
import com.hp.hpl.jena.graph.*;
public class Test14
{
public static void main(String[] args) throws Exception
{
String szJdbcURL = args[0];
String szUser = args[1];
String szPasswd = args[2];
String szModelName = args[3];
Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd);
ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle, szModelName);
GraphOracleSem g = model.getGraph();
g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"),
Node.createURI("u:Mary")));
g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"),
Node.createURI("u:Jack")));
g.add(Triple.create(Node.createURI("u:Amy"), Node.createURI("u:parentOf"),
Node.createURI("u:Jack")));
String queryString = " CONSTRUCT { ?s <u:loves> ?o } WHERE {?s <u:parentOf> ?o}";
Query query = QueryFactory.create(queryString) ;
QueryExecution qexec = QueryExecutionFactory.create(query, model) ;
Model m = qexec.execConstruct();
System.out.println("Construct result = " + m.toString());
qexec.close() ;
model.close();
OracleUtils.dropSemanticModel(oracle, szModelName);
oracle.dispose();
}
}
次のコマンドは、javaコマンドの想定される出力に加え、例6-26
をコンパイルして実行します。
javac -classpath ../jar/'*' Test14.java
java -classpath ./:../jar/'*' Test14 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
Construct result = <ModelCom {u:Amy @u:loves u:Jack;
u:John @u:loves u:Jack; u:John @u:loves u:Mary} | [u:Amy, u:loves, u:Jack] [u:John, u:loves,
u:Jack] [u:John, u:loves, u:Mary]>
6.18.11 Test15.java: 複数のモデルを問い合せ、重複の許可を指定する
例6-27では、複数のモデルを問い合せて重複の許可を使用します。次の条件を持つトリプルを挿入します。
-
Johnは、Jackの親です(モデル1)。
-
Maryは、Jackの親です(モデル2)。
-
それぞれの親は、自分の子ども全員を愛しています。
次に、誰が誰を愛しているかについて検出します。両方のモデルを検索し、モデルでの重複トリプルを(この例に重複はありませんが)許可します。
例6-27 複数のモデルを問い合せて重複の許可を指定する
import java.io.*;
import com.hp.hpl.jena.query.*;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.util.FileManager;
import oracle.spatial.rdf.client.jena.*;
import com.hp.hpl.jena.graph.*;
public class Test15
{
public static void main(String[] args) throws Exception
{
String szJdbcURL = args[0];
String szUser = args[1];
String szPasswd = args[2];
String szModelName1 = args[3];
String szModelName2 = args[4];
Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd);
ModelOracleSem model1 = ModelOracleSem.createOracleSemModel(oracle, szModelName1);
model1.getGraph().add(Triple.create(Node.createURI("u:John"),
Node.createURI("u:parentOf"), Node.createURI("u:Jack")));
model1.close();
ModelOracleSem model2 = ModelOracleSem.createOracleSemModel(oracle, szModelName2);
model2.getGraph().add(Triple.create(Node.createURI("u:Mary"),
Node.createURI("u:parentOf"), Node.createURI("u:Jack")));
model2.close();
String[] modelNamesList = {szModelName2};
String[] rulebasesList = {};
Attachment attachment = Attachment.createInstance(modelNamesList, rulebasesList,
InferenceMaintenanceMode.NO_UPDATE,
QueryOptions.ALLOW_QUERY_VALID_AND_DUP);
GraphOracleSem graph = new GraphOracleSem(oracle, szModelName1, attachment);
ModelOracleSem model = new ModelOracleSem(graph);
String queryString = " CONSTRUCT { ?s <u:loves> ?o } WHERE {?s <u:parentOf> ?o}";
Query query = QueryFactory.create(queryString) ;
QueryExecution qexec = QueryExecutionFactory.create(query, model) ;
Model m = qexec.execConstruct();
System.out.println("Construct result = " + m.toString());
qexec.close() ;
model.close();
OracleUtils.dropSemanticModel(oracle, szModelName1);
OracleUtils.dropSemanticModel(oracle, szModelName2);
oracle.dispose();
}
}
次のコマンドは、javaコマンドの想定される出力に加え、例6-27
をコンパイルして実行します。
javac -classpath ../jar/'*' Test15.java
java -classpath ./:../jar/'*' Test15 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1 M2
Construct result = <ModelCom {u:Mary @u:loves u:Jack; u:John @u:loves u:Jack} | [u:Mary, u:loves, u:Jack] [u:John, u:loves, u:Jack]>
6.18.12 Test16.java: SPARQLの更新
例6-28では、2つのトリプルをモデルに挿入します。
例6-28 SPARQLの更新
import java.io.*; import com.hp.hpl.jena.query.*; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.util.FileManager; import com.hp.hpl.jena.util.iterator.*; import oracle.spatial.rdf.client.jena.*; import com.hp.hpl.jena.graph.*; import com.hp.hpl.jena.update.*; public class Test16 { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; String szModelName = args[3]; Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle, szModelName); GraphOracleSem g = model.getGraph(); String insertString = " PREFIX dc: <http://purl.org/dc/elements/1.1/> " + " INSERT DATA " + " { <http://example/book3> dc:title \"A new book\" ; " + " dc:creator \"A.N.Other\" . " + " } "; UpdateAction.parseExecute(insertString, model); ExtendedIterator ei = GraphUtil.findAll(g); while (ei.hasNext()) { System.out.println("Triple " + ei.next().toString()); } model.close(); OracleUtils.dropSemanticModel(oracle, szModelName); oracle.dispose(); } }
次のコマンドは、javaコマンドの想定される出力に加え、例6-28
をコンパイルして実行します。
javac -classpath ../jar/'*' Test16.java
java -classpath ./:../jar/'*' Test16 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
Triple http://example/book3 @dc:title "A new book"
Triple http://example/book3 @dc:creator "A.N.Other"
6.18.13 Test17.java: SPARQL問合せでのARQ組込み関数の使用
例6-29では、2冊の本に関するデータを挿入し、本のタイトル(すべて大文字で)と、各タイトル文字列の長さを表示します。
例6-29 SPARQL問合せでのARQ組込み関数の使用
import java.io.*; import com.hp.hpl.jena.query.*; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.util.FileManager; import com.hp.hpl.jena.util.iterator.*; import oracle.spatial.rdf.client.jena.*; import com.hp.hpl.jena.graph.*; import com.hp.hpl.jena.update.*; public class Test17 { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; String szModelName = args[3]; Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle, szModelName); GraphOracleSem g = model.getGraph(); String insertString = " PREFIX dc: <http://purl.org/dc/elements/1.1/> " + " INSERT DATA " + " { <http://example/book3> dc:title \"A new book\" ; " + " dc:creator \"A.N.Other\" . " + " <http://example/book4> dc:title \"Semantic Web Rocks\" ; " + " dc:creator \"TB\" . " + " } "; UpdateAction.parseExecute(insertString, model); String queryString = "PREFIX dc: <http://purl.org/dc/elements/1.1/> " + " PREFIX fn: <http://www.w3.org/2005/xpath-functions#> " + " SELECT ?subject (fn:upper-case(?object) as ?object1) " + " (fn:string-length(?object) as ?strlen) " + " WHERE { ?subject dc:title ?object } " ; Query query = QueryFactory.create(queryString, Syntax.syntaxARQ); QueryExecution qexec = QueryExecutionFactory.create(query, model); ResultSet results = qexec.execSelect(); ResultSetFormatter.out(System.out, results, query); model.close(); OracleUtils.dropSemanticModel(oracle, szModelName); oracle.dispose(); } }
次のコマンドは、javaコマンドの想定される出力に加え、例6-29
をコンパイルして実行します。
javac -classpath ../jar/'*' Test17.java
java -classpath ./:../jar/'*' Test17 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
----------------------------------------------------------
| subject | object1 | strlen |
==========================================================
| <http://example/book3> | "A NEW BOOK" | 10 |
| <http://example/book4> | "SEMANTIC WEB ROCKS" | 18 |
----------------------------------------------------------
6.18.14 Test18.java: SELECTキャスト問合せ
例6-30では、2つの華氏温度(18.1と32.0)を摂氏温度に変換します。
例6-30 SELECTキャスト問合せ
import java.io.*; import com.hp.hpl.jena.query.*; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.util.FileManager; import com.hp.hpl.jena.util.iterator.*; import oracle.spatial.rdf.client.jena.*; import com.hp.hpl.jena.graph.*; import com.hp.hpl.jena.update.*; public class Test18 { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; String szModelName = args[3]; Oracle oracle = new Oracle(szJdbcURL, szUser, szPasswd); ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle, szModelName); GraphOracleSem g = model.getGraph(); String insertString = " PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> " + " INSERT DATA " + " { <u:Object1> <u:temp> \"18.1\"^^xsd:float ; " + " <u:name> \"Foo... \" . " + " <u:Object2> <u:temp> \"32.0\"^^xsd:float ; " + " <u:name> \"Bar... \" . " + " } "; UpdateAction.parseExecute(insertString, model); String queryString = " PREFIX fn: <http://www.w3.org/2005/xpath-functions#> " + " SELECT ?subject ((?temp - 32.0)*5/9 as ?celsius_temp) " + "WHERE { ?subject <u:temp> ?temp } " ; Query query = QueryFactory.create(queryString, Syntax.syntaxARQ); QueryExecution qexec = QueryExecutionFactory.create(query, model); ResultSet results = qexec.execSelect(); ResultSetFormatter.out(System.out, results, query); model.close(); OracleUtils.dropSemanticModel(oracle, szModelName); oracle.dispose(); } }
次のコマンドは、javaコマンドの想定される出力に加え、例6-30
をコンパイルして実行します。
javac -classpath ../jar/'*' Test18.java
java -classpath ./:../jar/'*' Test18 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
------------------------------------------------------------------------
| subject | celsius_temp |
========================================================================
| <u:Object1> | "-7.7222223"^^<http://www.w3.org/2001/XMLSchema#float> |
| <u:Object2> | "0.0"^^<http://www.w3.org/2001/XMLSchema#float> |
------------------------------------------------------------------------
6.18.15 Test19.java: OracleConnectionを使用したOracle Databaseのインスタンス化
例6-31では、指定されたOracleConnection
オブジェクトを使用して、異なる方法でOracleオブジェクトをインスタンス化しています。(J2EE Webアプリケーションでは、ユーザーは通常、J2EEデータソースからOracleConnection
オブジェクトを取得できます。)
例6-31 OracleConnectionを使用してOracle Databaseをインスタンス化する
import java.io.*; import com.hp.hpl.jena.query.*; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.util.FileManager; import com.hp.hpl.jena.util.iterator.*; import com.hp.hpl.jena.graph.*; import com.hp.hpl.jena.update.*; import oracle.spatial.rdf.client.jena.*; import oracle.jdbc.pool.*; import oracle.jdbc.*; public class Test19 { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; String szModelName = args[3]; OracleDataSource ds = new OracleDataSource(); ds.setURL(szJdbcURL); ds.setUser(szUser); ds.setPassword(szPasswd); OracleConnection conn = (OracleConnection) ds.getConnection(); Oracle oracle = new Oracle(conn); ModelOracleSem model = ModelOracleSem.createOracleSemModel(oracle, szModelName); GraphOracleSem g = model.getGraph(); g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"), Node.createURI("u:Mary"))); g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"), Node.createURI("u:Jack"))); g.add(Triple.create(Node.createURI("u:Mary"), Node.createURI("u:parentOf"), Node.createURI("u:Jill"))); String queryString = " SELECT ?s ?o WHERE { ?s <u:parentOf> ?o .} "; Query query = QueryFactory.create(queryString) ; QueryExecution qexec = QueryExecutionFactory.create(query, model) ; ResultSet results = qexec.execSelect() ; ResultSetFormatter.out(System.out, results, query); qexec.close() ; model.close(); OracleUtils.dropSemanticModel(oracle, szModelName); oracle.dispose(); } }
次のコマンドは、javaコマンドの想定される出力に加え、例6-31
をコンパイルして実行します。
javac -classpath ../jar/'*' Test19.java
java -classpath ./:../jar/'*' Test19 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
-----------------------
| s | o |
=======================
| <u:John> | <u:Mary> |
| <u:John> | <u:Jack> |
| <u:Mary> | <u:Jill> |
-----------------------
6.18.16 Test20.java: Oracle Database接続プーリング
例6-32では、Oracle Database接続プーリングを使用します。
例6-32 Oracle Database接続プーリング
import java.io.*; import com.hp.hpl.jena.query.*; import com.hp.hpl.jena.rdf.model.Model; import com.hp.hpl.jena.util.FileManager; import com.hp.hpl.jena.util.iterator.*; import com.hp.hpl.jena.graph.*; import com.hp.hpl.jena.update.*; import oracle.spatial.rdf.client.jena.*; import oracle.jdbc.pool.*; import oracle.jdbc.*; public class Test20 { public static void main(String[] args) throws Exception { String szJdbcURL = args[0]; String szUser = args[1]; String szPasswd = args[2]; String szModelName = args[3]; // test with connection properties (taken from some example) java.util.Properties prop = new java.util.Properties(); prop.setProperty("MinLimit", "2"); // the cache size is 2 at least prop.setProperty("MaxLimit", "10"); prop.setProperty("InitialLimit", "2"); // create 2 connections at startup prop.setProperty("InactivityTimeout", "1800"); // seconds prop.setProperty("AbandonedConnectionTimeout", "900"); // seconds prop.setProperty("MaxStatementsLimit", "10"); prop.setProperty("PropertyCheckInterval", "60"); // seconds System.out.println("Creating OraclePool"); OraclePool op = new OraclePool(szJdbcURL, szUser, szPasswd, prop, "OracleSemConnPool"); System.out.println("Done creating OraclePool"); // grab an Oracle and do something with it System.out.println("Getting an Oracle from OraclePool"); Oracle oracle = op.getOracle(); System.out.println("Done"); System.out.println("Is logical connection:" + oracle.getConnection().isLogicalConnection()); GraphOracleSem g = new GraphOracleSem(oracle, szModelName); g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"), Node.createURI("u:Mary"))); g.close(); // return the Oracle back to the pool oracle.dispose(); // grab another Oracle and do something else System.out.println("Getting an Oracle from OraclePool"); oracle = op.getOracle(); System.out.println("Done"); System.out.println("Is logical connection:" + oracle.getConnection().isLogicalConnection()); g = new GraphOracleSem(oracle, szModelName); g.add(Triple.create(Node.createURI("u:John"), Node.createURI("u:parentOf"), Node.createURI("u:Jack"))); g.close(); OracleUtils.dropSemanticModel(oracle, szModelName); // return the Oracle back to the pool oracle.dispose(); } }
次のコマンドは、javaコマンドの想定される出力に加え、例6-32
をコンパイルして実行します。
javac -classpath ../jar/'*' Test20.java
java -classpath ./:../jar/'*' Test20 jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> M1
Creating OraclePool
Done creating OraclePool
Getting an Oracle from OraclePool
Done
Is logical connection:true
Getting an Oracle from OraclePool
Done
Is logical connection:true
6.19 SPARQL Gatewayとセマンティク・データ
SPARQL Gatewayは、support for Apache Jenaに含まれるJ2EE Webアプリケーションです。Oracle Business Intelligence Enterprise Edition (OBIEE) 11gなどの、リレーショナル・データおよびXMLデータで稼働するアプリケーションで、セマンティク・データ(RDF/OWL/SKOS)を容易に利用可能にすることを目的としています。
6.19.1 SPARQL Gatewayの機能および利点の概要
SPARQL Gatewayでは、セマンティク・データを非セマンティク・アプリケーションに公開する際の次のような課題に対処します。
-
RDF構文、SPARQL問合せ構文およびSPARQLプロトコルについて理解しておく必要があること。
-
SPARQL問合せのレスポンス構文を理解しておく必要があること。
-
変換で、SPARQL問合せのレスポンスを、アプリケーションが使用できる形に変更する必要があること。
このような課題に対処するため、SPARQL Gatewayは、SPARQL問合せとXSLT操作を管理し、標準準拠の任意のSPARQLエンドポイントに対してSPARQL問合せを実行して、必要なXSL変換を実行してから、アプリケーションへレスポンスを渡します。こうすると、アプリケーションは既存のデータ・ソースからの場合と同じようにセマンティク・データを使用できるようになります。
異なるトリプル・ストアまたはクワッド・ストアには、異なる機能があります。たとえば、Oracle DatabaseによってサポートされるSPARQLエンドポイントは、指定された標準準拠のSPARQL問合せを解析して応答するというコア機能に加え、RDF Semantic Graph support for Apache JenaおよびJosekiを使用して、パラレル実行、問合せタイムアウト、動的なサンプリング、結果キャッシュおよびその他の機能を実行できます。一方、これらの機能は、指定された別のセマンティク・データ・ストアからは使用できない場合があります。
RDF Semantic Graph SPARQL Gatewayでは、たとえば長時間実行中の問合せにタイムアウトを設定する機能や、複雑な問合せから指定された時間内に結果の一部を取得する機能のような、強く求められる特定の機能を利用することができます。アプリケーションに応答時間の制約があるように、問合せの終了を無期限に待機することは、エンド・ユーザーにとって困難です。SPARQL Gatewayは、SPARQLエンドポイントの上位に、タイムアウトとベスト・エフォート型問合せ関数の両方を提供します。このような効率性によって、SPARQL問合せの実行中のセマンティク・データの使用に関して、不確実性がある程度は効果的に排除されます。(「タイムアウト値の指定」と「ベスト・エフォート型の問合せ実行の指定」を参照してください。)
親トピック: SPARQL Gatewayとセマンティク・データ
6.19.2 SPARQL Gatewayのインストールおよび構成
SPARQL Gatewayをインストールして構成するには、次の主要なステップを実行します(それぞれの項を参照してください)。
- RDF Semantic Graph support for Apache Jena .zipファイルをダウンロードする(まだダウンロードしていない場合)
- WebLogic ServerでのSPARQL Gatewayのデプロイ
- プロキシ設定の変更(必要な場合)
- OracleSGDSデータ・ソースの構成(必要な場合)
- SparqlGatewayAdminGroupグループの追加と構成(必要な場合)
親トピック: SPARQL Gatewayとセマンティク・データ
6.19.2.1 RDF Semantic Graph support for Apache Jena .zipファイルをダウンロードする(まだダウンロードしていない場合)
RDF Semantic Graph support for Apache Jenaファイルをまだダウンロードしていない場合は、「ソフトウェア環境の設定」の説明に従ってRDFセマンティク・グラフ・ページからファイルをダウンロードし、一時ディレクトリに解凍します。
なお、SPARQL GatewayのJavaクラスの実装は、sdordfclient.jar
に含まれています(「SPARQL GatewayのJava APIの使用」を参照)。
親トピック: SPARQLゲートウェイのインストールおよび構成
6.19.2.2 WebLogic ServerでのSPARQL Gatewayのデプロイ
Oracle WebLogic Serverで、次のようにSPARQL Gatewayをデプロイします。
-
次のとおり、WebLogic Serverのautodeployディレクトリに移動し、ビルトイン
sparqlgateway.war
ファイルをコピーします。(開発ドメインでのアプリケーションに対する自動デプロイの詳細は、http://docs.oracle.com/cd/E11035_01/wls100/deployment/autodeploy.html
を参照してください。)cp -rf /tmp/jena_adapter/sparqlgateway_web_app/sparqlgateway.war <domain_name>/autodeploy/sparqgateway.war
この例では、<domain_name>はWebLogic Serverドメインの名前です。
次の方法で、ビルトイン・アプリケーションをカスタマイズできます。
-
必要に応じて、
sparqlgateway_web_app/sparqlgateway.war
に埋め込まれているWEB-INF/web.xml
ファイルを変更します。sparql_gateway_repository_filedir
パラメータとsparql_gateway_repository_url
パラメータに対して、適切な値を指定してください。 -
必要に応じて、XSLTファイルまたはSPARQL問合せファイルを、
sparqlgateway_web_app/sparqlgateway.war
のトップレベル・ディレクトリに追加します。ディレクトリには、Oracle提供のファイル
default.xslt
、noop.xslt
およびqb1.sparql
があります。default.xslt
ファイルは、SPARQL問合せレスポンス(XML)を、主にOracleで利用可能な形式に変換するためのものです。(これらのファイルについては「SPARQL問合せとXSL変換の格納」を、SPARQL GatewayでのOBIEEの使用については「SPARQL GatewayのOBIEEへのXMLデータソースとしての使用」を参照してください。)
-
-
Webブラウザを使用して、次の書式のURLに接続し、デプロイメントを確認します(Webアプリケーションはポート7001でデプロイされているとします)。
http://<hostname>:7001/sparqlgateway
親トピック: SPARQLゲートウェイのインストールおよび構成
6.19.2.3 プロキシ設定の変更(必要な場合)
SPARQL Gatewayがファイアウォールの内側にあり、SPARQL Gatewayでファイアウォール内部のみでなくインターネット上のSPARQLエンドポイントとも通信する必要がある場合は、次のJVM設定を使用する必要があります。
-Dhttp.proxyHost=<your_proxy_host> -Dhttp.proxyPort=<your_proxy_port> -Dhttp.nonProxyHosts=127.0.0.1|<hostname_1_for_sparql_endpoint_inside_firewall>|<hostname_2_for_sparql_endpoint_inside_firewall>|...|<hostname_n_for_sparql_endpoint_inside_firewall>
これらの設定は、startWebLogic.sh
スクリプトに指定することができます。
親トピック: SPARQLゲートウェイのインストールおよび構成
6.19.2.4 OracleSGDSデータ・ソースの構成(必要な場合)
SPARQL GatewayのSPARQL問合せとXSL変換を格納し、アクセスするために、Oracle Databaseを使用する場合は、OracleSGDS
という名前のデータソースを構成する必要があります。
このデータ・ソースを作成するには、「WebLogic Serverを使用した必要なデータソースの作成」の手順に従います。ただしデータソース名には、OracleSemDS
ではなくOracleSGDS
を指定します。
OracleSGDS
データソースが構成されていて使用可能な場合、SPARQL Gatewayサーブレットは、すべての必要な表と索引を初期化時に自動作成します。
親トピック: SPARQLゲートウェイのインストールおよび構成
6.19.2.5 SparqlGatewayAdminGroupグループの追加と構成(必要な場合)
SPARQL Gatewayの次のJSPファイルは、Oracle Databaseに格納されているSPARQL問合せとXSL変換を表示、編集および更新するために役立ちます。
http://<host>:7001/sparqlgateway/admin/sparql.jsp http://<host>:7001/sparqlgateway/admin/xslt.jsp
これらのファイルは、HTTP Basic認証によって保護されています。WEB-INF/weblogic.xml
に、SparqlGatewayAdminGroup
という名前のプリンシパルが定義されます。
これらのJSPページのどちらにでもログインできるように、WebLogic Serverを使用してSparqlGatewayAdminGroup
という名前のグループを追加し、新しいユーザーを作成するか、または既存ユーザーをこのグループに割り当てる必要があります。
親トピック: SPARQLゲートウェイのインストールおよび構成
6.19.3 SPARQL Gatewayでのセマンティク・データの使用
SPARQL Gatewayと対話するアプリケーションの主要なインタフェースには、次の形式のURLを使用します。
http://host:port/sparqlgateway/sg?<SPARQL_ENDPOINT>&<SPARQL_QUERY>&<XSLT>
前述の形式の説明:
-
<SPARQL_ENDPOINT>では、
ee
パラメータを指定します。SPARQLエンドポイントのURLエンコード形式を含みます。たとえば、
ee=http%3A%2F%2Fsparql.org%2Fbooks
はSPARQLエンドポイントhttp://sparql.org/books
のURLエンコード文字列です。これは、SPARQL問合せがエンドポイントhttp://sparql.org/books
に対して実行されることを意味します。 -
<SPARQL_QUERY>では、SPARQL問合せ、またはSPARQL問合せの場所を指定します。
アプリケーションで非常に長いURLを使用できる場合は、SPARQL問合せ全体をエンコードし、URLに
eq=
<encoded_SPARQL_query>
を設定することができます。あまり長いURLをアプリケーションで使用できない場合は、「SPARQL問合せとXSL変換の格納」で説明されている方法の1つを使用して、SPARQL問合せを格納し、これらをSPARQL Gatewayで使用可能にすることができます。 -
<XSLT>では、XSL変換またはXSL変換の場所を指定します。
アプリケーションで非常に長いURLを使用できる場合は、XSL変換全体をエンコードし、URLに
ex=
<encoded_XSLT>
を設定することができます。あまり長いURLをアプリケーションで使用できない場合は、「SPARQL問合せとXSL変換の格納」で説明されている方法の1つを使用して、XSL変換を格納し、これらをSPARQL Gatewayで使用可能にすることができます。
親トピック: SPARQL Gatewayとセマンティク・データ
6.19.3.1 SPARQL問合せとXSL変換の格納
あまり長いURLをアプリケーションで使用できない場合は、SPARQL問合せとXSL変換の場所を、「SPARQL Gatewayでのセマンティク・データの使用」の説明にあるURL形式の<SPARQL_QUERY>と<XSLT>の部分に指定できます。次のいずれかの方法を使用します。
-
SPARQL問合せとXSL変換をSPARQL Gateway Webアプリケーション自体に格納します。
これを行うには、
sparqlgateway.war
ファイルを解凍し、SPARQL問合せとXSL変換を最上位ディレクトリに格納した後、sparqlgateway.war
ファイルを圧縮して、再デプロイします。sparqlgateway.war
ファイルには、サンプル・ファイルqb1.sparql
(SPARQL問合せ)およびdefault.xslt
(XSL変換)が含まれています。ヒント:
SPARQL問合せファイルには、ファイル拡張子
.sparql
を使用し、XSL変換ファイルには、ファイル拡張子.xslt
を使用します。(提供されているサンプル・ファイルの名前を使用して)これらのファイルを指定する構文は、SPARQL問合せファイルについては
wq
=qb1
.sparql、XSL変換ファイルについてはwx
=default.xslt
です。デフォルトのXSL変換をカスタマイズする必要がある場合は、「デフォルトのXSLTファイルのカスタマイズ」の例を参照してください。
wx=noop.xslt
を指定すると、XSL変換は実行されず、SPARQLレスポンスはそのままでクライアントに戻されます。 -
ファイル・システム・ディレクトリにSPARQL問合せとXSL変換を格納し、そのディレクトリがデプロイ済のSPARQL Gateway Webアプリケーションにアクセス可能なことを確認します。
デフォルトでは、次の
<init-param>
設定に示すとおり、そのディレクトリは/tmp
に設定されています。<init-param> <param-name>sparql_gateway_repository_filedir</param-name> <param-value>/tmp/</param-value> </init-param>
SPARQL Gatewayをデプロイする前に、このディレクトリをカスタマイズすることをお薦めします。ディレクトリ設定を変更するには、
<param-value>
タグと</param-value>
タグの間のテキストを編集します。次の例では、
sparql_gateway_repository_filedir
の<init-param>
要素で指定されたディレクトリのSPARQL問合せファイルとXSL変換ファイルを指定します。fq=qb1.sparql fx=myxslt1.xslt
-
SPARQL問合せとXSL変換をWebサイトからアクセス可能にします。
デフォルトでは、次の
<init-param>
設定に示すとおり、そのWebサイト・ディレクトリはhttp://127.0.0.1/queries/
に設定されています。<init-param> <param-name>sparql_gateway_repository_url</param-name> <param-value>http://127.0.0.1/queries/</param-value> </init-param>
このディレクトリは、SPARQL Gatewayをデプロイする前にカスタマイズします。Webサイト設定を変更するには、
<param-value>
タグと</param-value>
タグの間のテキストを編集します。次の例では、
sparql_gateway_repository_url
の<init-param>
要素で指定されたURLのSPARQL問合せファイルとXSL変換ファイルを指定します。uq=qb1.sparql ux=myxslt1.xslt
SPARQL Gatewayの内部では、適切で完全なURLを計算し、内容をフェッチして、問合せ実行を開始し、問合せのレスポンスXMLにXSL変換を適用します。
-
SPARQL問合せとXSL変換をOracle Databaseに格納します。
この方法では、J2EEデータソース
OracleSGDS
を定義しておく必要があります。SPARQL GatewayがOracleSGDSデータソースからデータベース接続を取得すると、データベース表ORACLE_ORARDF_SG_QUERYから指定された整数IDを使用してSPARQL問合せが読み取られます。Oracle DatabaseからSPARQL問合せをフェッチするための構文は
dq=
<integer-id>
、Oracle DatabaseからXSL変換をフェッチするための構文はdx=
<integer-id>
です。サーブレットの初期化時に、次の表がまだ存在しない場合は、自動的に作成されます(手動で作成する必要はありません)。
-
主キーがQID (整数型)のORACLE_ORARDF_SG_QUERY
-
主キーがXID (整数型)のORACLE_ORARDF_SG_XSLT
-
6.19.3.2 タイムアウト値の指定
実行時間が長くなる可能性のある問合せを「セマンティク・データを使用したSPARQL Gatewayの使用」で説明されているURL形式を使用して送信する場合、タイムアウト値をミリ秒で指定して、実行時間を制限することができます。たとえば、SPARQL Gatewayから開始したSPARQL問合せの実行が、1000ミリ秒(1秒)後に終了されるというURL形式とタイムアウトの指定を次に示します。
http://host:port/sparqlgateway/sg?<SPARQL_ENDPOINT>&<SPARQL_QUERY>&<XSLT>&t=1000
タイムアウトが発生したときに問合せが終了していない場合、空のSPARQLレスポンスがSPARQL Gatewayによって構築されます。
SPARQL GatewayがHTTP接続レベルで問合せ実行をタイムアウトしても、サーバー側では問合せの実行が続く場合もあることに注意してください。実際の動作はベンダーによって異なります。
6.19.3.3 ベスト・エフォート型問合せ実行の指定
注意:
ベスト・エフォート型問合せ実行は、タイムアウト値も指定する場合にのみ指定できます(「タイムアウト値の指定」を参照)。
実行時間が長くなる可能性のある問合せを「セマンティク・データを使用したSPARQL Gatewayの使用」で説明されているURL形式を使用して送信する場合、タイムアウト値を指定することで、その問合せにベスト・エフォート型制限を指定することもできます。たとえば次に示すURL形式には、1000ミリ秒(1秒)のタイムアウト指定と、ベスト・エフォート型指定(& b=t
)があわせて示されています。
http://host:port/sparqlgateway/sg?<SPARQL_ENDPOINT>&<SPARQL_QUERY>&<XSLT>&t=1000&b=t
web.xmlファイルには、ベスト・エフォート型オプションの動作に影響する2つのパラメータ設定(sparql_gateway_besteffort_maxrounds
およびsparql_gateway_besteffort_maxthreads
)が含まれます。デフォルトの定義を次に示します。
<init-param> <param-name>sparql_gateway_besteffort_maxrounds</param-name> <param-value>10</param-value> </init-param> <init-param> <param-name>sparql_gateway_besteffort_maxthreads</param-name> <param-value>3</param-value> </init-param>
SPARQLのSELECT問合せがベスト・エフォート型方式で実行されるとき、一連の問合せはSPARQL問合せ本体のLIMIT値を増加させた設定で実行されます。(中心的な考え方は、LIMIT設定をより小さくすることで、SPARQL問合せはより高速に実行されるという見解に基づいています。)SPARQL Gatewayは、LIMIT 1設定で問合せ実行を開始します。タイムアウトの前に、この問合せを完了できることが理想です。この場合、次の問合せでLIMIT制限が増加し、後続の問合せではより高い制限があるとします。問合せ実行の最大数は、sparql_gateway_besteffort_maxrounds
パラメータによって制御されます。
一連の問合せをパラレルで実行可能な場合、sparql_gateway_besteffort_maxthreads
パラメータで並列度を制御します。
6.19.3.4 text/xml以外のコンテンツ・タイプの指定
デフォルトでは、SPARQL GatewayはXSL変換がXMLを生成することを前提としているため、HTTPレスポンスに設定されているデフォルトのコンテンツ・タイプはtext/xml
です。ただし、アプリケーションでXML以外のレスポンス形式が必要である場合は、次の書式でその形式を追加のURLパラメータ(構文&rt=
を使用)に指定することができます。
http://host:port/sparqlgateway/sg?<SPARQL_ENDPOINT>&<SPARQL_QUERY>&<XSLT>&rt=<content_type>
<content_type>はURLエンコードされている必要があることに注意します。
6.19.4 デフォルトのXSLTファイルのカスタマイズ
デフォルトのXSL変換ファイル(wx=default.xslt
を使用して参照される)をカスタマイズすることができます。この項では、いくつかのカスタマイズ例を示します。
次の例では、ある変数のバインドがhttp://purl.org/goodrelations/v1#
で始まるURIを戻したときは、その部分をgr:
に置換し、http://www.w3.org/2000/01/rdf-schema#
で始まるURIを戻したときは、その部分をrdfs:
に置換する、というネームスペース接頭辞置換ロジックを実装します。
<xsl:when test="starts-with(text(),'http://purl.org/goodrelations/v1#')"> <xsl:value-of select="concat('gr:',substring-after(text(),'http://purl.org/goodrelations/v1#'))"/> </xsl:when> ... <xsl:when test="starts-with(text(),'http://www.w3.org/2000/01/rdf-schema#')"> <xsl:value-of select="concat('rdfs:',substring-after(text(),'http://www.w3.org/2000/01/rdf-schema#'))"/> </xsl:when>
次の例では、先頭のhttp://localhost/
または先頭のhttp://127.0.0.1/
を切り捨てるロジックを実装します。
<xsl:when test="starts-with(text(),'http://localhost/')"> <xsl:value-of select="substring-after(text(),'http://localhost/')"/> </xsl:when> <xsl:when test="starts-with(text(),'http://127.0.0.1/')"> <xsl:value-of select="substring-after(text(),'http://127.0.0.1/')"/> </xsl:when>
親トピック: SPARQL Gatewayとセマンティク・データ
6.19.5 SPARQL GatewayのJava APIの使用
Webインタフェースに加え、SPARQL Gateway管理サービスには、SPARQL問合せと関連するXSL変換を管理するための便利なJavaアプリケーション・プログラミング・インタフェース(API)があります。Java APIは、RDF Semantic Graph support for Apache Jenaライブラリsdordfclient.jar
に含まれます。
Java APIリファレンス情報は、SPARQL Gatewayの.zipファイルに含まれるjavadoc_sparqlgateway.zip
ファイルで入手できます(未入手の場合、RDF Semantic Graph Support for Apache Jena .zipファイルのダウンロードを参照してください)。
このAPIのメイン・エントリ・ポイントはoracle.spatial.rdf.client.jena.SGDBHandler
クラス(SPARQL Gatewayデータベース・ハンドラ)で、問合せと変換を管理するために次のような静的メソッドを提供します。
-
deleteSparqlQuery(Connection, int)
-
deleteXslt(Connection, int)
-
insertSparqlQuery(Connection, int, String, String, boolean)
-
insertXslt(Connection, int, String, String, boolean)
-
getSparqlQuery(Connection, int, StringBuilder, StringBuilder)
-
getXslt(Connection, int, StringBuilder, StringBuilder)
これらのメソッドは、Oracle Databaseインスタンスに格納されているSPARQL Gateway関連の表のエントリを操作し、取得します。これらのメソッドを使用するには、必要な関連表がすでに存在している必要があります。表が存在しない場合は、SPARQL GatewayをWebサーバーにデプロイし、次の形式でURLにアクセスします。
http://<host>:<port>/sparqlgateway/sg?
<host>はWebサーバーのホスト名で、<port>はWebサーバーのリスニング・ポートです。表がまだ存在しない場合、このURLにアクセスすると、必要な表が自動的に作成されます。
Java APIを介して行われた変更は、管理Webインタフェースを介して行われた変更と同様に、SPARQL GatewayのWebサービスに影響を及ぼします。これにより、最も都合のよいインタフェースを使用して柔軟に問合せと変換を管理できます。
Java APIにより提供される挿入メソッドでは、表に格納されている既存の問合せや変換を置き換えることができない点に注意してください。既存の問合せまたは変換を置換しようとすると失敗します。問合せまたは変換を置き換えるには、削除メソッドの1つを使用して表にある既存のエントリを削除した後に、挿入メソッドの1つを使用して新しい問合せまたは変換を挿入する必要があります。
次の例に、Java APIを使用して一般的な管理タスクを実行する方法を示します。この例では、SPARQL Gatewayの基盤である、基礎となるOracle Databaseインスタンスへの接続がすでに確立されていることを前提としています。
例6-33 SPARQL問合せとXSL変換の格納
例6-33では、SPARQL Gatewayを使用したデータベースに、問合せとXSL変換を追加します。問合せと変換が追加された後、他のプログラムでは、リクエストURLで適切な問合せID (qid
)とXSL変換ID (xid
)を指定することで、ゲートウェイを介して問合せと変換を使用することができます。
なお、例6-33では、問合せと変換の両方が挿入されていますが、問合せと変換には必ずしも関連はなく、SPARQL Gatewayにアクセスするときに同時に使用される必要もありません。SPARQL Gatewayにリクエストを送信するときは、データベースの任意の問合せをデータベースの任意の変換とともに使用することができます。
String query = "PREFIX ... SELECT ..."; // full SPARQL query text String xslt = "<?xml ...> ..."; // full XSLT transformation text String queryDesc = "Conference attendee information"; // description of SPARQL query String xsltDesc = "BIEE table widget transformation"; // description of XSLT transformation int queryId = queryIdCounter++; // assign a unique ID to this query int xsltId = xsltIdCounter++; // assign a unique ID to this transformation // Inserting a query or transformation will fail if the table already contains // an entry with the same ID. Setting this boolean to true will ignore these // exceptions (but the table will remain unchanged). Here we specify that we // want an exception thrown if we encounter a duplicate ID. boolean ignoreDupException = false; // add the query try { // Delete query if one already exists with this ID (this will not throw an // error if no such entry exists) SGDBHandler.deleteSparqlQuery( connection, queryId ); SGDBHandler.insertSparqlQuery( connection, queryId, query, queryDesc, ignoreDupException ); } catch( SQLException sqle ) { // Handle exception } catch( QueryException qe ) { // Handle query syntax exception } // add the XSLT try { // Delete xslt if one already exists with this ID (this will not throw an // error if no such entry exists) SGDBHandler.deleteXslt( connection, xsltId ); SGDBHandler.insertXslt( connection, xsltId, xslt, xsltDesc, ignoreDupException ); } catch( SQLException sqle ) { // Handle database exception } catch( TransformerConfigurationException tce ) { // Handle XSLT syntax exception }
例6-34 問合せの変更
例6-34では、データベースから既存の問合せを取得し、それを変更した後、更新された問合せを再度データベースに格納します。これらのステップでは、問合せの編集と変更の保存をシミュレートします。(問合せが存在しない場合は、例外がスローされます。)
StringBuilder query; StringBuilder description; // Populate these with the query text and description from the database query = new StringBuilder( ); description = new StringBuilder( ); // Get the query from the database try { SGDBHandler.getSparqlQuery( connection, queryId, query, description ); } catch( SQLException sqle ) { // Handle exception // NOTE: exception is thrown if query with specified ID does not exist } // The query and description should be populated now // Modify the query String updatedQuery = query.toString( ).replaceAll("invite", "attendee"); // Insert the query back into the database boolean ignoreDup = false; try { // First must delete the old query SGDBHandler.deleteSparqlQuery( connection, queryId ); // Now we can add SGDBHandler.insertSparqlQuery( connection, queryId, updatedQuery, description.toString( ), ignoreDup ); } catch( SQLException sqle ) { // Handle exception } catch( QueryException qe ) { // Handle query syntax exception }
例6-35 XSL変換の取得および出力
例6-35では、既存のXSL変換を取得し、標準出力に出力します。(変換が存在しない場合は、例外がスローされます。)
StringBuilder xslt; StringBuilder description; // Populate these with the XSLT text and description from the database xslt = new StringBuilder( ); description = new StringBuilder( ); try { SGDBHandler.getXslt( connection, xsltId, xslt, description ); } catch( SQLException sqle ) { // Handle exception // NOTE: exception is thrown if transformation with specified ID does not exist } // Print it to standard output System.out.printf( "XSLT description: %s\n", description.toString( ) ); System.out.printf( "XSLT body:\n%s\n", xslt.toString( ) );
親トピック: SPARQL Gatewayとセマンティク・データ
6.19.6 SPARQL GatewayのグラフィカルなWebインタフェースの使用
SPARQL Gatewayでは、問合せのテスト、セマンティク・データのナビゲート、SPQARQL問合せとXSLTファイルの管理に役立つブラウザベースのインタフェースがいくつか用意されています。
親トピック: SPARQL Gatewayとセマンティク・データ
6.19.6.1 メイン・ページ(index.html)
http://
<host>:<port>
/sparqlgateway/index.html
は、SPARQL問合せを実行し、さらにdefault.xsltの変換を応答に対して適用するための、単純なインタフェースです。図6-2に、このインタフェースでの問合せの実行を示します。
「SPARQL Endpoint」を入力または選択し、「SPARQL SELECT Query Body」を指定して「Submit Query」を押します。
たとえば、SPARQLエンドポイントとしてhttp://dbpedia.org/sparql
を指定し、図6-2に示したSPARQL問合せ本体を使用すると、応答は図6-3のようになります。この図のXML出力には、デフォルトの変換(default.xslt
)が適用されています。
6.19.6.2 ナビゲーションとブラウジングのページ(browse.jsp)
http://<host>:<port>/sparqlgateway/browse.jsp
では、セマンティク・データ用のナビゲーションとブラウジング機能が提供されています。標準に準拠したすべてのSPARQLエンドポイントに対して使用できます。図6-4に、このインタフェースでの問合せの実行を示します。
図6-4 グラフィカル・インタフェースによるナビゲーションとブラウジングのページ(browse.jsp)
![図6-4の説明が続きます 図6-4の説明が続きます](img/spgateway_browse_11.jpg)
「図6-4 グラフィカル・インタフェースによるナビゲーションとブラウジングのページ(browse.jsp)」の説明
「SPARQL Endpoint」を入力または選択し、「SPARQL SELECT Query Body」を指定し、オプションで「Timeout (ms)」値(ミリ秒)と「Best Effort」オプションを指定して、「Submit Query」を押します。
図6-5に示すとおり、SPARQLレスポンスが解析され、表形式で示されます。
図6-5で、URIはナビゲーションできるようにクリック可能であり、ユーザーがURI上でカーソルを移動すると、読みやすいように短縮されていたURIのツールチップ(図のhttp://purl.org.dc/elements/1.1/title
にdc:title
のツールチップが表示されています)が表示されます。
図6-5
に示されている出力のURIhttp://example.org/book/book5をクリックすると、新しいSPARQL問合せが自動的に生成され、実行されます。図6-6に示すとおり、この生成されたSPARQL問合せには、この特定のURIを主語、述語および目的語として使用する、3つの問合せパターンがあります。このような問合せによって、このURIがどのように使用されるか、およびデータセットの他のリソースとどのように関連するかを理解することができます。
問合せに多数の一致があると、その結果がページに分類され、どのページでもクリックすることができます。デフォルトでは50個の結果が1ページに表示されます。ブラウジングとナビゲーションのページ(browse.jsp
)でのレスポンスを、ページ当たり50行よりも多く(あるいは少なく)表示するには、URLに&resultsPerPage
パラメータを指定します。たとえばページ当たり100行を表示できるようにするには、URLに次を含めます。
&resultsPerPage=100
6.19.6.3 XSLTの管理ページ(xslt.jsp)
http://
<host>:<port>
/sparqlgateway/admin/xslt.jsp
は、単純なXSLT管理インタフェースです。XSLT ID(整数)を入力して「XSLTの取得」をクリックすると、説明とXSLT本体を取得できます。XSLT本体のテキストを変更した後に「XSLTの保存」をクリックすることで、その変更を保存できます。使用可能なXSLT定義のナビゲートに役立つプレビューアがあります。
図6-7は、XSLTの管理ページを示しています。
6.19.6.4 SPARQLの管理ページ(sparql.jsp)
http://
<host>:<port>
/sparqlgateway/admin/xslt.jsp
は、単純なSPARQL管理インタフェースです。SPARQL ID(整数)を入力して「SPARQLの取得」をクリックすると、説明とSPARQL本体を取得できます。SPARQL本体のテキストを変更した後に「SPARQLの保存」をクリックすることで、その変更を保存できます。使用可能なSPARQL問合せのナビゲートに役立つプレビューアがあります。
図6-8は、SPARQLの管理ページを示しています。
6.19.7 OBIEEへのXMLデータソースとしてのSPARQL Gatewayの使用
この項では、SPARQL Gatewayをブリッジとして使用してOBIEEとRDFを統合することによって、Oracle Business Intelligence Enterprise Edition (OBIEE)で使用するXMLデータ・ソースを作成する方法について説明します。(具体的なステップと図は、Oracle BI管理ツールのバージョン11.1.1.3.0.100806.0408.000に基づいています。)
親トピック: SPARQL Gatewayとセマンティク・データ
6.20 Apache TomcatまたはJBossにおけるJosekiのデプロイ
JosekiをOracle WebLogic Server にデプロイしないことにする場合、JosekiをApache TomcatまたはJBossにデプロイすることもできます。
6.20.1 Apache Tomcat 6.0.29または7.0.42におけるJosekiのデプロイ
JosekiをApache Tomcat 6.0.29または7.0.42にデプロイするには、次のステップを実行します。
-
Apache Tomcat 6.0.29または7.0.42をダウンロードしてインストールします。
これらの手順では、Apache Tomcatインストール・ディレクトリのルートを、$CATALINA_HOMEと呼びます。
-
次の例を使用して環境変数を設定します。
setenv JAVA_HOME< your_path_here>/jdk16/ setenv PATH <your_path_here>/jdk16/bin/:$PATH setenv CATALINA_HOME <your_path_here>/apache-tomcat-6.0.29 OR setenv CATALINA_HOME <your_path_here>/apache-tomcat-7.0.42
-
ojdbc6.jar
を${CATALINA_HOME}/lib
にコピーします。 -
tomcat-users.xml
を変更して、次のものを含めます。<tomcat-users> <role rolename="tomcat"/> <role rolename="role1"/> <user username="tomcat" password="<tomcat-password>" roles="tomcat,manager"/> <user username="both" password="<tomcat-password>" roles="tomcat,role1"/> <user username="role1" password="<tomcat-password>" roles="role1"/> </tomcat-users>
ただし、Apache Tomcatバージョン7.0.42を使用している場合は、前述のコードのroles="tomcat,manager"をroles="tomcat,manager-gui"に置き換えます。
-
Tomcatを起動します。
$CATALINA_HOME/bin/startup.sh
このファイルに実行権限がない場合は、次のコマンドを入力してから再度Tomcatを起動します。
chmod u+x $CATALINA_HOME/bin/startup.sh
-
ブラウザで、
http://hostname:8080/manager/html
に移動します。認証が必要な場合は、ユーザーに
tomcat
と入力し、Tomcatのパスワードを入力します。 -
TomcatにJosekiをデプロイします。
-
「Tomcat Manager」ページ(
http://
hostname
:8080/manager/html
)で、Deploy directory or WAR file located on server
を選択します。 -
Context Pathに/josekiと入力します。
-
WAR or Directory URLに、
joseki.war
へのパス(/tmp/jena_adapter/joseki_web_app/joseki.war
など)を入力します。 -
「デプロイ」をクリックします。
joseki
という名前のディレクトリが、apache-tomcat-6.0.29/webapps
下かapache-tomcat-7.0.42/webapps
下に作成されます。このディレクトリはJOSEKI_HOMEとして参照されます。 -
-
次に移動して、Josekiが正常にインストールされたことを確認します。
http://<hostname>:8080/joseki
-
OracleSemDSというJ2EEデータ・ソースを作成します。
データ・ソースの作成中に、SPARQL問合せの実行対象になる関連セマンティク・データを含むデータベース・スキーマのユーザーとパスワードを指定できます。Tomcatにデータ・ソースを作成するには、次の変更を行います。
-
グローバル
$CATALINA_HOME/conf/server.xml
ファイルに、次のGlobalNamingResourcesのリソースを追加します(必要に応じてカスタマイズします)。<Resource name="OracleSemDS" auth="Container" type="oracle.jdbc.pool.OracleDataSource" driverClassName="oracle.jdbc.OracleDriver" factory="oracle.jdbc.pool.OracleDataSourceFactory" url="jdbc:oracle:thin:@hostname:port:sid" user="username" password="password" maxActive="30" maxIdle="10" maxWait="-1"/>
-
グローバル
$CATALINA_HOME/conf/context.xml
ファイルに、次のリンクを追加します。<ResourceLink global="OracleSemDS" name="OracleSemDS" type="oracle.jdbc.pool.OracleDataSource"/>
データ・ソース設定の詳細は、Tomcatの文書を参照してください。
-
-
Tomcatをシャットダウンし、再起動します。
$CATALINA_HOME/bin/shutdown.sh $CATALINA_HOME/bin/startup.sh
-
次に移動してデプロイメントを確認します(Webアプリケーションはポート番号8080でデプロイされているとします):
http://<hostname>:8080/joseki/querymgt?abortqid=0
XMLレスポンスに、RDF Semantic Graph support for Apache Jena問合せ管理サーブレットによるJosekiのデプロイメントが成功したことが示されます。
6.20.2 JBoss 7.1.1におけるJosekiのデプロイ
JosekiをJBoss 7.1.1にデプロイするには、次のステップを実行します。(このステップも、必要な変更を加えた上でRed Hat JBoss Enterprise Application Platform 6.1.0に対してテストされたものです。)
-
JBoss Application Server 7.1.1をダウンロードしてインストールします。
この手順では、
jboss-as-7.1.1.Final/
がJBossインストールのトップレベル・ディレクトリであるとします。 -
JDBCドライバをインストールします。
create directory jboss-as-7.1.1.Final/modules/oracle/jdbc/main/
-
このディレクトリに
ojdbc6.jar
をコピーします。 -
このディレクトリに、次の内容で
module.xml
を作成します。<?xml version="1.0" encoding="UTF-8"?> <module xmlns="urn:jboss:module:1.0" name="oracle.jdbc"> <resources> <resource-root path="ojdbc6.jar"/> </resources> <dependencies> <module name="javax.api"/> <module name="javax.transaction.api"/> </dependencies> </module>
-
次の行を追加して
jboss-as-7.1.1.Final/standalone/configuration/standalone.xml
を変更します。<driver name="OracleJDBCDriver" module="oracle.jdbc"/>
変更した
standalone.xml
ファイルには次を含める必要があります。... <drivers> <driver name="OracleJDBCDriver" module="oracle.jdbc"/> <driver name="h2" module="com.h2database.h2"> <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class> </driver> </drivers> ...
-
必要なデータ・ソースを作成します。
-
JBoss AS管理コンソールにログインします。
http://<hostname>:9990/console/App.html#server-overview
-
Datasourceをクリックします。
-
Profileをクリックします。
-
Addをクリックし、次を入力します。
名前:
OracleSemDS
OracleSemDSJNDI名:
java:jboss/datasources/OracleSemDS
-
OracleJDBCDriverを選択します。
-
「次へ」をクリックします。
次の情報が表示されます:
Connection URL: jdbc:oracle:thin:@hostname:port:sid NOTE: customize Username: scott NOTE: customize Password: tiger NOTE: customize Security Domain: (Leave empty)
-
必要に応じてこの情報をカスタマイズし、Security Domainは空白のままで、Doneをクリックします。
-
-
新しいデータ・ソースを強調表示して、EnableをクリックしてからConfirmをクリックします。
-
JBoss管理コンソールを使用して
joseki.war
ファイルをデプロイします。-
次のページに移動します。
http://<hostname>:9990/console/App.html#deployments
-
「デプロイメント」をクリックします。
-
Manage Deploymentsをクリックします。
-
Addをクリックし、
joseki.war
ファイルを指定します。
-