8 RDF Semantic Graph Support for Eclipse RDF4J

Oracle RDF Graph Adapter for Eclipse RDF4Jは、一般的なEclipse RDF4Jフレームワークを使用して、Oracle DatabaseのRDFセマンティク・グラフ機能を使用するためのJava開発者サポートを提供します。

ノート:

  • この機能は、以前はSesame Adapter for Oracle DatabaseまたはSesame Adapterと呼ばれていました。
  • 共有デプロイメントでAutonomous Databaseインスタンスを使用している場合、RDF Semantic Graph Support for Eclipse RDF4Jには、Oracle JVMの有効化が必要です。Autonomous DatabaseインスタンスでOracle JVMを有効にするには、共有ExadataインフラストラクチャでのOracle Autonomous Databaseの使用Oracle Javaの使用を参照してください。

Eclipse RDF4Jは、RDFデータの処理とハンドリングのための強力なJavaフレームワークです。これには、RDFおよびリンクされたデータを使用した作成、解析、スケーラブルな格納、推論および問合せが含まれます。詳細は、https://rdf4j.orgを参照してください。

「RDFセマンティク・グラフの概要」「OWLの概要」で説明されている主要な概念について十分に理解していることが前提です。Eclipse RDF4J Javaフレームワークの性能全体および使用についても十分に理解していることを前提とします。詳細は、https://rdf4j.orgを参照してください。

Oracle RDF Graph Adapter for Eclipse RDF4Jは、Java開発者に一般的な標準ベースのAPIを提供することで、Oracle Database RDF/OWLのセマンティク・データ管理機能を拡張します。

8.1 Oracle RDF Graph Support for Eclipse RDF4Jの概要

Oracle RDF Graph Adapter for Eclipse RDF4J APIは、Eclipse RDF4J SAIL APIに準拠するAPIフレームワークおよびツールを介して、Oracleセマンティク・データへのJavaベース・インタフェースを提供します。

RDF Semantic Graph support for Eclipse RDF4Jは、RDF Semantic Graph Support for Apache Jenaで説明されているRDF Semantic Graph support for Apache Jenaに似ています。

Eclipse RDF4J用のアダプタでは、Oracle Databaseに格納されているセマンティク・データと対話するためのJava APIが提供されています。また、次のとおりEclipse RDF4Jツールを包括的に提供します。

  • Eclipse RDF4J Server。HTTP SPARQLエンドポイントを提供します。
  • Eclipse RDF4J Workbench。WebベースのクライアントUIで、データベースを管理し、問合せを実行します。

Eclispe RDF4J用のアダプタによって提供される機能を次に示します。

  • (コンテキスト付きおよびコンテキストなしの)文のロード(バルクおよび増分)、エクスポートおよび削除
  • データの問合せ(コンテキストがある場合とない場合)
  • データの更新(コンテキストがある場合とない場合)

Oracle RDF Graph Adapter for Eclipse RDF4Jでは、Eclipse RDF4J Storage and Inference Layer (SAIL) APIの様々なインタフェースを実装しています。

たとえばクラスOracleSailConnectionは、Eclipse RDF4J SailConnectionインタフェースのOracle実装で、クラスOracleSailStoreAbstractSailを拡張した、Eclipse RDF4J SailインタフェースのOracle実装です。

次の例に、RDF Semantic Graph support for Eclipse RDF4Jの一般的な使用フローを示します。

例8-1 スキーマプライベート・セマンティク・ネットワークを使用した、Eclipse RDF4J用RDFセマンティク・グラフ・サポートのサンプル使用フロー

String networkOwner = "SCOTT";
String networkName = "NET1";
String modelName = "UsageFlow";
OraclePool oraclePool = new OraclePool(jdbcurl, user, password);
SailRepository sr = new SailRepository(new OracleSailStore(oraclePool, modelName, networkOwner, networkName));
SailRepositoryConnection conn = sr.getConnection();

//A ValueFactory factory for creating IRIs, blank nodes, literals and statements
ValueFactory vf = conn.getValueFactory();
IRI alice = vf.createIRI("http://example.org/Alice");
IRI friendOf = vf.createIRI("http://example.org/friendOf");
IRI bob = vf.createIRI("http://example.org/Bob");
Resource context1 = vf.createIRI("http://example.org/");

// Data loading can happen here.
conn.add(alice, friendOf, bob, context1);
String query =
  " PREFIX foaf: <http://xmlns.com/foaf/0.1/> " +
  " PREFIX dc: <http://purl.org/dc/elements/1.1/> " +
  " select ?s ?p ?o ?name WHERE {?s ?p ?o . OPTIONAL {?o foaf:name ?name .} } ";
TupleQuery tq = conn.prepareTupleQuery(QueryLanguage.SPARQL, query);
TupleQueryResult tqr = tq.evaluate();
while (tqr.hasNext()) {
    System.out.println((tqr.next().toString()));
}
tqr.close();
conn.close();
sr.shutDown();

8.2 Oracle RDF Graph Adapter for Eclipse RDF4Jを使用するための前提条件

Oracle RDF Graph Adapter for Eclipse RDF4Jの使用を開始する前に、システム環境が特定の前提条件を満たしていることを確認する必要があります。

次に、Eclipse RDF4J用のアダプタを使用するために必要な前提条件を示します。

  • バージョン18c以降のOracle Database Standard Edition 2 (SE2)またはEnterprise Edition (EE) (クラウドまたはオンプレミスのユーザー管理データベース)
  • Eclipse RDF4Jバージョン4.2.1
  • JDK 11

さらに、バグ修正およびパフォーマンスの改善のために、次のデータベース・パッチをお薦めします。

  • Patch 32562595: TRACKING BUG FOR RDF GRAPH PATCH KIT Q2 2021

    現在、My Oracle Supportでリリース19.11で使用できます。

    Oracle Databaseリリース19.15以降にはすでにこれらの変更が含まれており、追加のパッチは必要ないことに注意してください。

8.3 Oracle RDF Graph Adapter for Eclipse RDF4Jを使用するための設定および構成

Oracle RDF Graph Adapter for Eclipse RDF4Jを使用するには、最初にシステム環境を設定および構成する必要があります。

アダプタは、次の3つの環境で使用できます。

  • Javaコードを使用したプログラムで
  • SPARQLサービスとしてHTTPを介したアクセスで
  • Eclipse RDF4J Workbench環境内で使用

次の項では、前述の環境でEclipse RDF4J用のアダプタを使用するためのアクションについて説明します。

8.3.1 Javaで使用するためのOracle RDF Graph Adapter for Eclipse RDF4Jの設定

Javaコードを介してOracle RDF Graph Adapter for Eclipse RDF4Jをプログラムで使用するには、Oracle RDF Graph Adapter for Eclipse RDF4Jを使用するための前提条件の説明に従って、システム環境がすべての前提条件を満たしていることを最初に確認する必要があります。

アダプタを使用してRDFグラフの格納、管理および問合せをOracleデータベースで開始する前に、セマンティク・ネットワークを作成する必要があります。セマンティク・ネットワークは、データベース・ユーザーが作成した複数のRDFグラフ(セマンティク(RDF)モデルと呼ばれる)を保持できるフォルダのように機能します。セマンティク・ネットワークは、MDSYSシステム・スキーマ(MDSYSネットワークと呼ばれます)で、またはバージョン19cからはユーザー・スキーマ(スキーマプライベート・ネットワークと呼ばれます)で作成できます。

ネットワークを作成するには、次のコマンドを実行します。

  • MDSYSセマンティク・ネットワーク

    sem_apis.create_sem_network(<tablespace_name>)

  • スキーマプライベート・セマンティク・ネットワーク

    sem_apis.create_sem_network(<tablespace_name>, network_owner=><network_owner>, network_name=><network_name>)

詳細は、セマンティク・ネットワークを参照してください。

ノート:

RDF4Jサーバー、ワークベンチおよびSPARQLサービスでは、Oracle RDF Graph Adapter for Eclipse RDF4Jの現在のバージョンのMDSYS所有セマンティク・ネットワークのみがサポートされます。

MDSYS所有セマンティク・ネットワークの作成

MDSYS所有セマンティク・ネットワークを作成するには、SQL Developer、SQLPLUSなどのSQLベースのインタフェースから、またはJDBCを使用してJavaプログラムから次のアクションを実行します。
  1. DBA権限を持つSYSTEMユーザーとしてOracle Databaseに接続します。
    CONNECT system/<password-for-system-user>
  2. RDFグラフを格納するための表領域を作成します。適切なオペレーティング・システム・フォルダおよびファイル名を使用します。
    CREATE TABLESPACE rdftbs 
      DATAFILE 'rdftbs.dat'
      SIZE 128M REUSE 
      AUTOEXTEND ON NEXT 64M
      MAXSIZE UNLIMITED 
      SEGMENT SPACE MANAGEMENT AUTO;
  3. rdftbsの割当て制限をMDSYSに付与します。
    ALTER USER MDSYS QUOTA UNLIMITED ON rdftbs;
  4. ユーザー・データを格納するための表領域を作成します。適切なオペレーティング・システム・フォルダおよびファイル名を使用します。
    CREATE TABLESPACE usertbs 
      DATAFILE 'usertbs.dat'
      SIZE 128M REUSE 
      AUTOEXTEND ON NEXT 64M
      MAXSIZE UNLIMITED 
      SEGMENT SPACE MANAGEMENT AUTO;
  5. アダプタを使用してRDFグラフを作成または使用する、あるいはその両方を実行するデータベース・ユーザーを作成します。
    CREATE USER rdfuser 
           IDENTIFIED BY <password-for-rdfuser>
           DEFAULT TABLESPACE usertbs
           QUOTA 5G ON usertbs;
  6. rdftbsの割当て制限をRDFUSERに付与します。
    ALTER USER RDFUSER QUOTA 5G ON rdftbs;
  7. 必要な権限を新しいデータベース・ユーザーに付与します。
    GRANT CONNECT, RESOURCE TO rdfuser;
  8. MDSYS所有セマンティク・ネットワークを作成します。
    EXECUTE SEM_APIS.CREATE_SEM_NETWORK(tablespace_name =>'rdftbs');
  9. MDSYS所有セマンティク・ネットワークが正常に作成されていることを確認します。
    SELECT table_name 
      FROM sys.all_tables 
      WHERE table_name = 'RDF_VALUE$' AND owner='MDSYS';

    MDSYSスキーマにRDF_VALUE$表が存在する場合は、MDSYS所有セマンティク・ネットワークが正常に作成されています。

    TABLE_NAME
    -----------
    RDF_VALUE$

スキーマプライベート・セマンティク・ネットワークの作成

スキーマプライベート・セマンティク・ネットワークを作成するには、SQL Developer、SQLPLUSなどのSQLベースのインタフェースから、またはJDBCを使用したJavaプログラムから次のアクションを実行します。
  1. DBA権限を持つSYSTEMユーザーとしてOracle Databaseに接続します。
    CONNECT system/<password-for-system-user>
  2. ユーザー・データを格納するための表領域を作成します。適切なオペレーティング・システム・フォルダおよびファイル名を使用します。
    CREATE TABLESPACE usertbs 
      DATAFILE 'usertbs.dat'
      SIZE 128M REUSE 
      AUTOEXTEND ON NEXT 64M
      MAXSIZE UNLIMITED 
      SEGMENT SPACE MANAGEMENT AUTO;
  3. データベース・ユーザーを作成して、セマンティク・ネットワークを作成および所有します。このユーザーは、このスキーマ・プライベート・ネットワーク内でアダプタを使用して、RDFグラフを作成または使用するか、あるいはその両方を実行できます。
    CREATE USER rdfuser 
           IDENTIFIED BY <password-for-rdfuser>
           DEFAULT TABLESPACE usertbs
           QUOTA 5G ON usertbs;
  4. 必要な権限を新しいデータベース・ユーザーに付与します。
    GRANT CONNECT, RESOURCE, CREATE VIEW TO rdfuser;
  5. rdfuserとしてOracle Databaseに接続します。
    CONNECT rdfuser/<password-for-rdf-user>
  6. NET1という名前のスキーマ・プライベート・セマンティク・ネットワークを作成します。
    EXECUTE SEM_APIS.CREATE_SEM_NETWORK(tablespace_name =>'usertbs', network_owner=>'RDFUSER', network_name=>'NET1');
  7. スキーマプライベート・セマンティク・ネットワークが正常に作成されていることを確認します。
    SELECT table_name 
      FROM sys.all_tables 
      WHERE table_name = 'NET1#RDF_VALUE$' AND owner='RDFUSER';

    ネットワーク所有者のスキーマに<NETWORK_NAME>#RDF_VALUE$表が存在することは、スキーマ・プライベート・セマンティク・ネットワークが正常に作成されていることを示しています。

    TABLE_NAME
    -----------
    NET1#RDF_VALUE$

これで、次のアクションを実行して、Javaコードで使用するOracle RDF Graph Adapter for Eclipse RDF4Jを設定できます。

  1. RDF4Jのダウンロード・ページからEclipse RDF4Jリリース4.2.1をダウンロードして構成します。
  2. Oracle Software Delivery Cloudから、Eclipse RDF4J (Oracle Adapter for Eclipse RDF4J)用のアダプタをダウンロードします。
  3. ダウンロードしたキット(V1033016-01.zip)を、Linuxシステム上の/tmp/oracle_adapterなどの一時ディレクトリに解凍します。この一時ディレクトリがまだ作成されていない場合は、解凍操作の前に作成します。
  4. IDEを介してJavaコードを実行するために、次の3つのサポート・ライブラリをCLASSPATHに指定します。
    • eclipse-rdf4j-4.2.1-onejar.jar: このEclipse RDF4J jarライブラリを、RDF4Jのダウンロード・ページからダウンロードします。
    • ojdbc8.jar: 使用しているデータベース・バージョンに対応したこのJDBC Thinドライバを、JDBCダウンロード・ページからダウンロードします。
    • ucp.jar: 使用しているデータベース・バージョンに対応したこのユニバーサル接続プールjarファイルを、JDBCダウンロード・ページからダウンロードします。
    • log4j-api-2.17.2.jarlog4j-core-2.17.2.jarlog4j-slf4j-impl-2.17.2.jarslf4j-api-1.7.36.jarおよびcommons-io-2.11.0.jar: Apache Software Foundationからダウンロードします。
  5. JDK 11がまだインストールされていない場合はインストールします。
  6. JAVA_HOME環境変数を、JDK 11のインストールを参照するように設定します。次のコマンドを実行して、設定を定義および確認します。
    echo $JAVA_HOME

8.3.2 RDF4J ServerおよびWorkbenchで使用するためのOracle RDF Graph Adapter for Eclipse RDF4Jの設定

この項では、RDF4J ServerおよびRDF4J WorkbenchでのOracle RDF Graph Adapter for Eclipse RDF4Jのインストールおよび構成について説明します。

RDF4J Serverは、RDF4JリポジトリへのHTTPアクセスを提供し、SPARQLエンドポイントとして公開するデータベース管理アプリケーションです。RDF4J Workbenchには、RDF4J Serverのリポジトリを作成、問合せ、更新および検索するためのWebインタフェースが用意されています。

ノート:

RDF4Jサーバー、ワークベンチおよびSPARQLサービスでは、Oracle RDF Graph Adapter for Eclipse RDF4Jの現在のバージョンのMDSYS所有セマンティク・ネットワークのみがサポートされます。

前提条件

次の前提条件が、RDF4J ServerおよびWorkbenchでEclipse RDF4J用のアダプタを使用するように構成されていることを確認します。

  1. Java 11 Runtime Environment
  2. 含めるサポート・ライブラリとして説明したサポート・ライブラリをダウンロードします。
  3. Java Servlet API 3.1およびJava Server Pages (JSP) 2.2以上をサポートするJavaサーブレット・コンテナ。

    ノート:

    この章の例はすべて、最新の安定バージョンのApache Tomcat (9.0.78)で実行されます。
  4. RDF4J Server、RDF4J WorkbenchおよびRDF4J Consoleの標準インストール。詳細は、RDF4J Server and Workbench InstallationおよびRDF4J Console installationを参照してください。
  5. 次の図8-1のドロップダウンに、Oracleがデフォルトのリポジトリとして表示されていないことを確認します。

    図8-1 RDF4J Workbenchのデータ・ソース・リポジトリ

    図8-1の説明が続きます
    「図8-1 RDF4J Workbenchのデータ・ソース・リポジトリ」の説明

    ノート:

    Oracleデータ・ソース・リポジトリがRDF4J Workbenchリポジトリにすでに設定されている場合は、上のドロップダウン・リストに表示されます。

RDF4J WorkbenchでのOracleデータ・ソース・リポジトリの追加

RDF4J WorkbenchでOracleデータ・ソース・リポジトリを追加するには、次のステップを実行する必要があります。

  1. 強調表示されている次のフィールドを更新して、Tomcatメイン$CATALINA_HOME/conf/context.xmlディレクトリのcontext.xmlデータ・ソースを追加します。

    - Using JDBC driver
        <Resource name="jdbc/OracleSemDS" auth="Container"
           driverClassName="oracle.jdbc.OracleDriver"
           factory="oracle.jdbc.pool.OracleDataSourceFactory"
           scope="Shareable"
           type="oracle.jdbc.pool.OracleDataSource"
           user="<<username>>" 
           password="<<pwd>>" 
           url="jdbc:oracle:thin:@<< host:port:sid >>"
           maxActive="100"
           minIdle="15"
           maxIdel="15"
           initialSize="15"
           removeAbandonedTimeout="30"
           validationQuery="select 1 from dual"
        />
    
    - Using UCP
       <Resource name="jdbc/OracleSemDS" auth="Container"
           factory="oracle.ucp.jdbc.PoolDataSourceImpl" 
           type="oracle.ucp.jdbc.PoolDataSource"
           connectionFactoryClassName="oracle.jdbc.pool.OracleDataSource"  
           minPoolSize="15"
           maxPoolSize="100"
           inactiveConnectionTimeout="60"
           abandonedConnectionTimeout="30"
           initialPoolSize="15"
           user="<<username>>" 
           password="<<pwd>>"
           url="jdbc:oracle:thin:@<< host:port:sid >>"   
        />
    
  2. Oracle jdbcおよびucpドライバをTomcatのlibフォルダにコピーします。
    cp -f ojdbc8.jar $CATALINA_HOME/lib
    cp -f ucp.jar $CATALINA_HOME/lib
  3. oracle-rdf4j-adapter-4.2.1.jarをRDF4Jサーバーのlibフォルダにコピーします。
    cp -f oracle-rdf4j-adapter-4.2.1.jar $CATALINA_HOME/webapps/rdf4j-server/WEB-INF/lib
  4. oracle-rdf4j-adapter-4.2.1.jarをRDF4J Workbenchのlibフォルダにコピーします。
    cp -f oracle-rdf4j-adapter-4.2.1.jar $CATALINA_HOME/webapps/rdf4j-workbench/WEB-INF/lib
  5. Tomcatの$CATALINA_HOME/webapps/rdf4j-workbench/transformationsフォルダ内に構成ファイルcreate-oracle.xslを作成します。
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [
       <!ENTITY xsd  "http://www.w3.org/2001/XMLSchema#" >
     ]>
    <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sparql="http://www.w3.org/2005/sparql-results#"
      xmlns="http://www.w3.org/1999/xhtml">
    
      <xsl:include href="../locale/messages.xsl" />
      <xsl:variable name="title">
      <xsl:value-of select="$repository-create.title" />
      </xsl:variable>
      <xsl:include href="template.xsl" />
      <xsl:template match="sparql:sparql">
      <form action="create">
        <table class="dataentry">
          <tbody>
            <tr>
              <th>
                <xsl:value-of select="$repository-type.label" />
              </th>
              <td>
                <select id="type" name="type">
                  <option value="memory">
                    Memory Store
                  </option>
                  <option value="memory-lucene">
                    Memory Store + Lucene 
                  </option>
                  <option value="memory-rdfs">
                    Memory Store + RDFS
                  </option>
                  <option value="memory-rdfs-dt">
                    Memory Store + RDFS and Direct Type
                  </option>
                  <option value="memory-rdfs-lucene">
                    Memory Store + RDFS and Lucene
                  </option>
                  <option value="memory-customrule">
                    Memory Store + Custom Graph Query Inference
                  </option>
                  <option value="memory-spin">
                    Memory Store + SPIN support
                  </option>
                  <option value="memory-spin-rdfs">
                    Memory Store + RDFS and SPIN support
                  </option>
                  <option value="memory-shacl">
                    Memory Store + SHACL
                  </option>
                  <!-- disabled pending GH-1304  option value="memory-spin-rdfs-lucene">
                    In Memory Store with RDFS+SPIN+Lucene support
                  </option -->
                  <option value="native">
                    Native Store
                  </option>
                  <option value="native-lucene">
                    Native Store + Lucene
                  </option>
                  <option value="native-rdfs">
                    Native Store + RDFS
                  </option>
                  <option value="native-rdfs-dt">
                    Native Store + RDFS and Direct Type
                  </option>
                  <option value="memory-rdfs-lucene">
                    Native Store + RDFS and Lucene
                  </option>
                  <option value="native-customrule">
                    Native Store + Custom Graph Query Inference
                  </option>
                  <option value="native-spin">
                    Native Store + SPIN support
                  </option>
                  <option value="native-spin-rdfs">
                    Native Store + RDFS and SPIN support
                  </option>
                  <option value="native-shacl">
                    Native Store + SHACL
                  </option>
                  <!-- disabled pending GH-1304  option value="native-spin-rdfs-lucene">
                    Native Java Store with RDFS+SPIN+Lucene support
                  </option -->
                  <option value="remote">
                    Remote RDF Store
                  </option>
                  <option value="sparql">
                    SPARQL endpoint proxy
                  </option>
                  <option value="federate">Federation</option>
                  <option value="lmdb">LMDB Store</option>
                  <option value="oracle">Oracle</option>
                </select>
              </td>
              <td></td>
            </tr>
            <tr>
              <th>
                <xsl:value-of select="$repository-id.label" />
              </th>
              <td>
                <input type="text" id="id" name="id" size="16" />
              </td>
              <td></td>
            </tr>
            <tr>
              <th>
                <xsl:value-of select="$repository-title.label" />
              </th>
              <td>
                <input type="text" id="title" name="title" size="48" />
              </td>
              <td></td>
            </tr>
            <tr>
              <td></td>
              <td>
                <input type="button" value="{$cancel.label}" style="float:right"
    	           data-href="repositories"
    	           onclick="document.location.href=this.getAttribute('data-href')" />
                <input type="submit" name="next" value="{$next.label}" />
              </td>
            </tr>
          </tbody>
        </table>
      </form>
      </xsl:template>
    </xsl:stylesheet>
  6. Tomcatの$CATALINA_HOME/webapps/rdf4j-workbench/transformations変換フォルダ内に構成ファイルcreate.xslを作成します。
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE xsl:stylesheet [
       <!ENTITY xsd  "http://www.w3.org/2001/XMLSchema#" >
     ]>
    <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:sparql="http://www.w3.org/2005/sparql-results#"
      xmlns="http://www.w3.org/1999/xhtml">
    
      <xsl:include href="../locale/messages.xsl" />
      <xsl:variable name="title">
      <xsl:value-of select="$repository-create.title" />
      </xsl:variable>
      <xsl:include href="template.xsl" />
      <xsl:template match="sparql:sparql">
      <form action="create">
        <table class="dataentry">
          <tbody>
            <tr>
              <th>
                <xsl:value-of select="$repository-type.label" />
              </th>
              <td>
                <select id="type" name="type">
                  <option value="memory">
                    Memory Store
                  </option>
                  <option value="memory-lucene">
                    Memory Store + Lucene 
                  </option>
                  <option value="memory-rdfs">
                    Memory Store + RDFS
                  </option>
                  <option value="memory-rdfs-dt">
                    Memory Store + RDFS and Direct Type
                  </option>
                  <option value="memory-rdfs-lucene">
                    Memory Store + RDFS and Lucene
                  </option>
                  <option value="memory-customrule">
                    Memory Store + Custom Graph Query Inference
                  </option>
                  <option value="memory-spin">
                    Memory Store + SPIN support
                  </option>
                  <option value="memory-spin-rdfs">
                    Memory Store + RDFS and SPIN support
                  </option>
                  <option value="memory-shacl">
                    Memory Store + SHACL
                  </option>
                  <!-- disabled pending GH-1304  option value="memory-spin-rdfs-lucene">
                    In Memory Store with RDFS+SPIN+Lucene support
                  </option -->
                  <option value="native">
                    Native Store
                  </option>
                  <option value="native-lucene">
                    Native Store + Lucene
                  </option>
                  <option value="native-rdfs">
                    Native Store + RDFS
                  </option>
                  <option value="native-rdfs-dt">
                    Native Store + RDFS and Direct Type
                  </option>
                  <option value="memory-rdfs-lucene">
                    Native Store + RDFS and Lucene
                  </option>
                  <option value="native-customrule">
                    Native Store + Custom Graph Query Inference
                  </option>
                  <option value="native-spin">
                    Native Store + SPIN support
                  </option>
                  <option value="native-spin-rdfs">
                    Native Store + RDFS and SPIN support
                  </option>
                  <option value="native-shacl">
                    Native Store + SHACL
                  </option>
                  <!-- disabled pending GH-1304  option value="native-spin-rdfs-lucene">
                    Native Java Store with RDFS+SPIN+Lucene support
                  </option -->
                  <option value="remote">
                    Remote RDF Store
                  </option>
                  <option value="sparql">
                    SPARQL endpoint proxy
                  </option>
                  <option value="federate">Federation</option>
                  <option value="lmdb">LMDB Store</option>
                  <option value="oracle">Oracle</option>
                </select>
              </td>
              <td></td>
            </tr>
            <tr>
              <th>
                <xsl:value-of select="$repository-id.label" />
              </th>
              <td>
                <input type="text" id="id" name="id" size="16" />
              </td>
              <td></td>
            </tr>
            <tr>
              <th>
                <xsl:value-of select="$repository-title.label" />
              </th>
              <td>
                <input type="text" id="title" name="title" size="48" />
              </td>
              <td></td>
            </tr>
            <tr>
              <td></td>
              <td>
                <input type="button" value="{$cancel.label}" style="float:right"
                    data-href="repositories"
                    onclick="document.location.href=this.getAttribute('data-href')" />
                <input type="submit" name="next" value="{$next.label}" />
              </td>
            </tr>
          </tbody>
        </table>
      </form>
      </xsl:template>
    </xsl:stylesheet>
  7. Tomcatを再起動し、https://localhost:8080/rdf4j-workbenchに移動します。

ノート:

構成ファイルcreate-oracle.xslおよびcreate.xslには、「Oracle」という語が含まれています。これは、図8-2のドロップダウンに示されています。

Oracle」は、RDF4J Workbenchのドロップダウン・リストにオプションとして表示されます。

図8-2 RDF4J Workbenchリポジトリ

図8-2の説明が続きます
「図8-2 RDF4J Workbenchリポジトリ」の説明
8.3.2.1 RDF4J Workbenchを介したAdapter for Eclipse RFD4Jの使用

リポジトリの作成および問合せには、RDF4J Workbenchを使用できます。

RDF4J Workbenchには、RDF4J Serverのリポジトリを作成、問合せ、更新および検索するためのWebインタフェースが用意されています。

RDF4J Workbenchを使用した新規リポジトリの作成

  1. ブラウザにURL https://localhost:8080/rdf4j-workbenchを入力して、RDF4J Workbenchを起動します。
  2. サイドバー・メニューで「新規リポジトリ」をクリックし、新規リポジトリの「タイプ」として「Oracle」を選択します。
  3. 次の図に示すように、新しいリポジトリの「ID」「タイトル」を入力し、「次」をクリックします。

    図8-3 RDF4J Workbenchの新規リポジトリ



  4. モデルの詳細を入力し、「作成」をクリックして新規リポジトリを作成します。

    図8-4 RDF4J Workbenchでの新規リポジトリの作成



    新しく作成されたリポジトリのサマリーが次のように表示されます。

    図8-5 RDF4J Workbenchの新規リポジトリのサマリー



    新しく作成したリポジトリは、RDF4J Workbenchのリポジトリのリスト・ページで表示することもできます。



8.3.3 SPARQLサービスとして使用するためのOracle RDF Graph Adapter for Eclipse RDF4Jの設定

RDF4J Workbenchを介してSPARQLサービスを使用するには、RDF4J ServerおよびWorkbenchで使用するためのOracle RDF Graph Adapter for Eclipse RDF4Jの設定の説明に従って、Eclipse RDF4Jサーバーがインストールされ、Oracleデータ・ソース・リポジトリが構成されていることを確認します。

Eclipse RDF4Jサーバー・インストールで提供されるREST APIは、HTTPプロトコルを使用し、SPARQL 1.1プロトコルのW3C勧告に完全準拠した実装をカバーします。これにより、RDF4Jサーバーは標準に完全準拠したSPARQLエンドポイントとして機能します。この機能の詳細は、The RDF4J REST APIを参照してください。

ノート:

RDF4Jサーバー、ワークベンチおよびSPARQLサービスでは、Oracle RDF Graph Adapter for Eclipse RDF4Jの現在のバージョンのMDSYS所有セマンティク・ネットワークのみがサポートされます。

次の項では、使用例を示します。

8.3.3.1 Eclipse RDF4J WorkbenchでのAdapter Over SPARQLエンドポイントの使用

この項では、Eclipse RDF4J Workbenchで提供されるSPARQLエンドポイントを介してEclipse RDF4J用のアダプタを使用する例をいくつか説明します。

例8-2 SPARQL更新を実行するリクエスト

次の例では、HTTP POSTを使用していくつかの単純なトリプルを挿入します。ファイルsparql_update.rqの内容は次のようになっているとします。

PREFIX ex: <http://example.oracle.com/>
INSERT DATA {
  ex:a ex:value "A" .
  ex:b ex:value "B" .
}

その後、次のようにcurlコマンドライン・ツールを使用して、前述のSPARQL更新を実行できます。

curl -X POST --data-binary "@sparql_update.rq" \
-H "Content-Type: application/sparql-update" \
"http://localhost:8080/rdf4j-server/repositories/MyRDFRepo/statements"

例8-3 HTTP GETを使用したSPARQL問合せの実行リクエスト

このcurlの例は、HTTP GETを使用してSPARQL問合せを実行します。

curl -X GET -H "Accept: application/sparql-results+json" \
"http://localhost:8080/rdf4j-server/repositories/MyRDFRepo?query=SELECT%20%3Fs%20%3Fp%20%3Fo%0AWHERE%20%7B%20%3Fs%20%3Fp%20%3Fo%20%7D%0ALIMIT%2010"

前のSPARQL更新の例が空のリポジトリで実行された場合、このRESTリクエストは次のレスポンスを返すはずです。

{
  "head" : {
    "vars" : [
      "s",
      "p",
      "o"
    ]
  },
  "results" : {
    "bindings" : [
      {
        "p" : {
          "type" : "uri",
          "value" : "http://example.oracle.com/value"
        },
        "s" : {
          "type" : "uri",
          "value" : "http://example.oracle.com/b"
        },
        "o" : {
          "type" : "literal",
          "value" : "B"
        }
      },
      {
        "p" : {
          "type" : "uri",
          "value" : "http://example.oracle.com/value"
        },
        "s" : {
          "type" : "uri",
          "value" : "http://example.oracle.com/a"
        },
        "o" : {
          "type" : "literal",
          "value" : "A"
        }
      }
    ]
  }
}

8.4 データベース接続の管理

Oracle RDF Graph Adapter for Eclipse RDF4Jでは、Oracle Databaseの接続プーリングがサポートされています。

OracleSailStoreのインスタンスは、接続プールを使用してOracleデータベースへの接続を管理します。Oracle Databaseの接続プーリングは、OraclePoolクラスを介して利用できます。通常、OraclePoolOraclePool (DataSource ods)コンストラクタを使用してDataSourceで初期化されています。この場合、OraclePoolはデータソースの接続プーリング機能を使用しながらDataSourceの拡張ラッパーとして動作します。OracleSailStoreオブジェクトを作成するときには、storeコンストラクタ内にOraclePoolオブジェクトを指定するだけで十分です。続けて、Eclipse RDF4J用のアダプタによりデータベース接続が自動的に制御されるようになります。OraclePoolには、他にもいくつかのコンストラクタが用意されています。このコンストラクタを使用すると、たとえば、JDBC URLとデータベースusernameおよびpasswordを使用してOraclePoolインスタンスを作成できます。詳細は、Oracle RDF Graph Adapter for Eclipse RDF4Jのダウンロードに含まれるJavadocを参照してください。

明示的にOracle接続オブジェクト(基本的にデータベース接続ラッパーである)を取得する必要がある場合は、OraclePool.getOracleメソッドを起動します。接続を終了した後は、OraclePool.returnOracleDBtoPoolメソッドを起動して、接続プールにオブジェクトを戻します。

OracleSailStoreからOracleSailConnection、またはOracleRepositoryからOracleSailRepositoryConnectionを取得すると、OraclePoolから新しいOracleDBオブジェクトが取得され、RDF4J接続オブジェクトの作成に使用されます。READ_COMMITTEDトランザクション分離は、異なるRDF4J接続オブジェクト間で維持されます。

この動作の例外の1つは、OracleSailConnectionの既存のインスタンスでasRepositoryConnectionメソッドをコールしてOracleSailRepositoryConnectionを取得したときに発生します。この場合、元のOracleSailConnectionと新しく取得されたOracleSailRepositoryConnectionは、同じOracleDBオブジェクトを使用します。OracleSailConnectionまたはOracleSailRepositoryConnectionオブジェクトの使用が終了したら、そのcloseメソッドをコールしてOracleDBオブジェクトをOraclePoolに戻す必要があります。そうしないと、アプリケーションで接続リークが発生します。

8.5 SPARQL問合せの実行モデル

Oracle RDF Graph Adapter for Eclipse RDF4J APIを介して実行されるSPARQL問合せは、RDFデータを格納するためのOracleのリレーショナル・スキーマに対するSQL問合せとして実行されます。

OracleのSQLエンジンを使用すると、SPARQL問合せの実行で、パラレル問合せ実行、インメモリー列表現、Exadataスマート・スキャンなどの多くのパフォーマンス機能を利用できます。

SPARQL問合せを実行するには、次の2つの方法があります。

  • Queryまたはそのサブインタフェースのいずれかの実装を、基礎となるOracleSailConnectionを持つRepositoryConnectionprepareQuery関数から取得できます。

  • TupleExprのOracle固有の実装をOracleSPARQLParserから取得し、OracleSailConnectionevaluateメソッドをコールできます。

次のコード・スニペットは、最初の方法を示しています。

//run a query against the repository
String queryString = 
  "PREFIX ex: <http://example.org/ontology/>\n" + 
  "SELECT * WHERE {?x ex:name ?y} LIMIT 1 ";
TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);

try (TupleQueryResult result = tupleQuery.evaluate()) {
  while (result.hasNext()) {
    BindingSet bindingSet = result.next();
    psOut.println("value of x: " + bindingSet.getValue("x"));
    psOut.println("value of y: " + bindingSet.getValue("y"));
  }
}

OracleSailConnectionは、問合せを評価するときに、SPARQL問合せ文字列を使用してデータベース・サーバー上のSEM_APIS.SPARQL_TO_SQLストアド・プロシージャをコールし、同等のSQL問合せを取得して、データベース・サーバー上で実行します。SQL問合せの結果は、標準のRDF4J問合せ結果インタフェースのいずれかを介して処理され、戻されます。

8.5.1 BIND値の使用

Oracle RDF Graph Adapter for Eclipse RDF4Jでは、Queryインタフェースで定義されたsetBindingプロシージャなど、標準のRDF4Jバインド値APIを介してバインド値がサポートされます。Oracleでは、元のSPARQL問合せ文字列にSPARQL BIND句を追加することでバインド値を実装します。

たとえば、次のSPARQL問合せについて考えます。
SELECT * WHERE { ?s <urn:fname> ?fname }
前述の問合せでは、問合せ変数?sに値<urn:john>を設定できます。この場合、変換後の問合せは次のようになります。
SELECT * WHERE { BIND (<urn:john> AS ?s) ?s <urn:fname> ?fname }

ノート:

このアプローチは、SPARQLの標準の変数スコープ・ルールに従います。したがって、最も外側のグラフ・パターンで認識されない問合せ変数(副問合せから投影されない変数など)は、バインド値に置換できません。

8.5.2 JDBC BIND値の使用

Oracle RDF Graph Adapter for Eclipse RDF4Jを使用すると、SPARQL問合せに対して実行される基礎となるSQL文でJDBCバインド値を使用できます。JDBCバインド値の実装は、前の項で説明した標準のRDF4Jバインド値のサポートよりもはるかに高性能です。

JDBCバインド値のサポートでは、標準のRDF4J setBinding APIが使用されますが、バインド変数は特定の方法で宣言する必要があり、特別な問合せオプションをORACLE_SEM_SM_NSネームスペース接頭辞とともに渡す必要があります。問合せに対してJDBCバインド変数を有効にするには、ORACLE_SEM_SM_NSネームスペース接頭辞(PREFIX ORACLE_SEM_SM_NS: <http://oracle.com/semtech#USE_BIND_VAR=JDBC>など)にUSE_BIND_VAR=JDBCを含める必要があります。SPARQL問合せにこの問合せオプションが含まれる場合、単純なSPARQL BIND句に表示されるすべての問合せ変数が、対応するSQL問合せでJDBCバインド値として処理されます。単純なSPARQL BIND句が、BIND (<constant> as ?var)の形式(BIND("dummy" AS ?bindVar1など)を持つものです。

次のコード・スニペットは、JDBCバインド値の使用方法を示しています。

例8-4 JDBCバインド値の使用

// query that uses USE_BIND_VAR=JDBC option and declares ?name as a JDBC bind variable
String queryStr = 
  "PREFIX ex: <http://example.org/>\n"+
  "PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n"+
  "PREFIX ORACLE_SEM_SM_NS: <http://oracle.com/semtech#USE_BIND_VAR=JDBC>\n"+
  "SELECT ?friend\n" +
  "WHERE {\n" +
  "  BIND(\"\" AS ?name)\n" +
  "  ?x foaf:name ?name\n" +
  "  ?x foaf:knows ?y\n" +
  "  ?y foaf:name ?friend\n" +
  "}";

// prepare the TupleQuery with JDBC bind var option
TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryStr);

// find friends for Jack
tupleQuery.setBinding("name", vf.createLiteral("Jack");

try (TupleQueryResult result = tupleQuery.evaluate()) {
  while (result.hasNext()) {
    BindingSet bindingSet = result.next();
    System.out.println(bindingSet.getValue("friend").stringValue());
  }
}

// find friends for Jill
tupleQuery.setBinding("name", vf.createLiteral("Jill");

try (TupleQueryResult result = tupleQuery.evaluate()) {
  while (result.hasNext()) {
    BindingSet bindingSet = result.next();
    System.out.println(bindingSet.getValue("friend").stringValue());
  }
}

ノート:

Oracle RDF Graph Adapter for Eclipse RDF4JのJDBCバインド値機能は、SEM_APIS.SPARQL_TO_SQLのバインド変数機能を使用します(SEM_APIS.SPARQL_TO_SQLによるバインド変数の使用を参照)。
8.5.2.1 JDBCバインド値のサポートの制限

JDBCバインド値をサポートしているのは、SPARQL SELECTおよびASK問合せのみです。

JDBCバインド値のサポートには、次の制限があります。

  • JDBCバインド値は次ではサポートされていません。
    • SPARQL CONSTRUCT問合せ
    • DESCRIBE問合せ
    • SPARQL更新文
  • 4000文字を超える長さのRDFロング・リテラル値は、JDBCバインド値として使用できません。
  • 空白のノードは、JDBCバインド値として使用できません。

8.5.3 他の機能をサポートするためのSPARQL問合せ構文への追加

Oracle RDF Graph Adapter for Eclipse RDF4Jでは、問合せを生成および実行するためのオプションを渡すことができます。問合せオプションを含むOracle固有の名前空間を使用してSPARQL名前空間接頭辞の構文をオーバーロードすることで、これらの機能を実装できます。名前空間の形式はPREFIX ORACLE_SEM_xx_NSで、xxは機能のタイプ(SM - SEM_MATCHなど)を示します。

8.5.3.1 問合せの実行オプション
次の形式のSPARQL PREFIXを含めることで、問合せの実行オプションをデータベース・サーバーに渡すことができます。
PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#option>
前述のSPARQL PREFIXoptionは、問合せの実行時に使用される問合せオプション(またはカンマで区切られた複数のオプション)を反映します。

次のオプションがサポートされています。

  • DOP=n: 問合せに対する並列度(n)を指定します。
  • ODS=n: 実行計画の生成時に使用するオプティマイザ動的サンプリングのレベルを指定します。

次の問合せ例では、ORACLE_SEM_FS_NS接頭辞を使用して、問合せの実行に並列度4を使用することを指定しています。

PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#dop=4>
PREFIX ex: <http://www.example.com/>
SELECT *
WHERE {?s ex:fname ?fname ;                     
          ex:lname ?lname ;                     
          ex:dob ?dob}
8.5.3.2 SPARQL_TO_SQL (SEM_MATCH)のオプション

次の形式のSPARQL PREFIXを含めることで、SPARQL_TO_SQLオプションをデータベース・サーバーに渡し、SPARQL問合せに対して生成されるSQLに影響を与えることができます。

PREFIX ORACLE_SEM_SM_NS: <http://oracle.com/semtech#option>

前述のPREFIXoptionは、問合せの実行時に使用されるSPARQL_TO_SQLオプション(またはカンマで区切られた複数のオプション)を反映します。

使用可能なオプションの詳細は、SEM_MATCH表関数を使用したセマンティク・データの問合せを参照してください。この接頭辞では、SEM_MATCHまたはSEM_APIS.SPARQL_TO_SQLのオプション引数に有効としてリストされている任意の有効なキーワードまたはキーワード値ペアを使用できます。

次の問合せ例では、ORACLE_SEM_SM_NS接頭辞を使用して、問合せ内のすべてのトリプル・パターンを結合するためにHASH結合を使用するように指定します。

PREFIX ORACLE_SEM_SM_NS: <http://oracle.com/semtech#all_link_hash>
PREFIX ex: <http://www.example.org/>
SELECT *
WHERE {?s ex:fname ?fname ;
          ex:lname ?lname ;
          ex:dob ?dob}

8.5.4 SPARQL問合せのサポートで特に留意する点

この項では、SPARQL問合せのサポートで特に留意する点について説明します。

無制限のプロパティ・パス問合せ

デフォルトでは、Oracle RDF Graph Adapter for Eclipse RDF4Jは、無制限のSPARQLプロパティ・パス演算子+および*の評価を最大10回の繰返しに制限します。これは、all_max_pp_depth(n) SPARQL_TO_SQLオプションを使用して制御できます。nは、+または*と一致する場合に許可される最大反復回数です。値をゼロに指定すると、最大反復回数は無制限になります。

次の例では、完全に無制限の検索にall_max_pp_depth(0)を使用します。
PREFIX ORACLE_SEM_SM_NS: <http://oracle.com/semtech#all_max_pp_depth(0)>
PREFIX ex: <http://www.example.org/>
SELECT (COUNT(*) AS ?cnt)
WHERE {ex:a ex:p1* ?y}

SPARQLデータセットの指定

Eclipse RDF4J用のアダプタでは、SPARQL問合せ文字列の外部でデータセットを指定できません。OperationsetDataset()メソッドとそのサブインタフェースによるデータセットの指定はサポートされておらず、SailConnectionevaluateメソッドへのデータセット・オブジェクトの受渡しもサポートされていません。かわりに、SPARQL句FROMおよびFROM NAMEDを使用して、SPARQL問合せ文字列自体で問合せデータセットを指定します。

問合せタイムアウト

OperationおよびそのサブインタフェースでのsetMaxExecutionTimeメソッドによる問合せタイムアウトはサポートされていません。

ロングRDFリテラル

長さが4000バイトを超えるラージRDFリテラル値は、一部のSPARQL問合せ関数ではサポートされていません。詳細は、SEM_MATCH使用時の特別な考慮事項を参照してください。

8.6 SPARQL更新の実行モデル

この項では、Oracle RDF Graph Adapter for Eclipse RDF4JのSPARQL更新の実行モデルについて説明します。

Eclipse RDF4J用のアダプタでは、データベース・サーバーでSEM_APIS.UPDATE_MODELストアド・プロシージャを実行することでSPARQL更新操作を実装します。SPARQL更新操作を実行するには、OracleSailRepositoryConnectionのインスタンスのprepareUpdate関数からUpdateオブジェクトを取得します。

ノート:

OracleSailRepositoryConnectionインスタンスが必要です。OracleSailStoreから作成されたプレーンなSailRepositoryインスタンスでは、更新が正しく実行されません。

次の例は、RDF4J APIを使用してOracle RDFモデルを更新する方法を示します。

String updString =
   "PREFIX people: <http://www.example.org/people/>\n"+
   "PREFIX    ont: <http://www.example.org/ontology/>\n"+        
   "INSERT DATA { GRAPH <urn:g1> { \n"+        
   "                people:Sue a ont:Person; \n"+        
   "                             ont:name \"Sue\" . } }";      
   Update upd = conn.prepareUpdate(QueryLanguage.SPARQL, updString);      
   upd.execute();

8.6.1 SPARQL更新のトランザクション管理

RDF4J APIを介して実行されるSPARQL更新操作は、標準のRDF4Jトランザクション管理規則に従います。SPARQL更新は、デフォルトで自動的にコミットされます。ただし、明示的なトランザクションがbeginを使用してSailRepositoryConnectionで開始された場合、アクティブなトランザクションがcommitを使用して明示的にコミットされるまで、後続のSPARQL更新操作はコミットされません。未コミット状態の更新操作は、rollbackを使用してロールバックできます。

8.6.2 他の機能をサポートするためのSPARQL構文への追加

SPARQL問合せの場合と同様に、Oracle RDF Graph Adapter for Eclipse RDF4JではSPARQL更新を実行するためのオプションを渡すことができます。SEM_APIS.UPDATE_MODELオプションを含むOracle固有の名前空間を使用してSPARQL名前空間接頭辞の構文をオーバーロードすることで、これらの機能を実装できます。

8.6.2.1 UPDATE_MODELオプション
次の形式でPREFIX宣言を含めることで、SEM_APIS.UPDATE_MODELにオプションを渡すことができます。
PREFIX ORACLE_SEM_UM_NS: <http://oracle.com/semtech#option>
前述のPREFIXoptionは、更新の実行時に使用されるUPDATE_MODELオプション(またはカンマで区切られた複数のオプション)を反映します。

使用可能なオプションの詳細は、SEM_APIS.UPDATE_MODELを参照してください。このPREFIXでは、UPDATE_MODELのオプション引数に有効としてリストされている任意の有効なキーワードまたはキーワード値ペアを使用できます。

次の問合せ例では、ORACLE_SEM_UM_NS接頭辞を使用して、更新の並列度2を指定します。

PREFIX ORACLE_SEM_UM_NS: <http://oracle.com/semtech#parallel(2)>
PREFIX ex: <http://www.example.org/>
INSERT {GRAPH ex:g1 {ex:a ex:reachable ?y}}
WHERE {ex:a ex:p1* ?y}
8.6.2.2 UPDATE_MODELの一致オプション

次の形式でPREFIX宣言を含めることで、SEM_APIS.UPDATE_MODELに一致オプションを渡すことができます。

PREFIX ORACLE_SEM_SM_NS: <http://oracle.com/semtech#option>

optionは、SPARQL更新の実行中に使用されるUPDATE_MODEL一致オプション(またはカンマで区切られた複数の一致オプション)を反映します。

使用可能なオプションの詳細は、SEM_APIS.UPDATE_MODELを参照してください。このPREFIXでは、UPDATE_MODEL match_options引数に有効としてリストされている任意の有効なキーワードまたはキーワード値ペアを使用できます。

次の例では、ORACLE_SEM_SM_NS接頭辞を使用して、最大の無制限のプロパティ・パス深度5を指定します。

PREFIX ORACLE_SEM_SM_NS: <http://oracle.com/semtech#all_max_pp_depth(5)>
PREFIX ex: <http://www.example.org/>
INSERT {GRAPH ex:g1 {ex:a ex:reachable ?y}}
WHERE {ex:a ex:p1* ?y}

8.6.3 SPARQL更新のサポートで特に留意する点

更新操作での無制限のプロパティ・パス

前の項で説明したように、Oracle RDF Graph Adapter for Eclipse RDF4Jは、無制限のSPARQLプロパティ・パス演算子+および*の評価を最大10回の繰返しに制限します。このデフォルト設定は、WHERE句でプロパティ・パスを使用するSPARQL更新操作に影響します。最大反復回数の設定は、all_max_pp_depth(n)オプションを使用して制御できます。nは、+または*と一致する場合に許可される最大反復回数です。値をゼロに指定すると、最大反復回数は無制限になります。

次の例では、完全に無制限の検索でSEM_APIS.UPDATE_MODELの一致オプションとしてall_max_pp_depth(0)を使用します。

PREFIX ORACLE_SEM_SM_NS: <http://oracle.com/semtech#all_max_pp_depth(0)>
PREFIX ex: <http://www.example.org/>
INSERT { GRAPH ex:g1 { ex:a ex:reachable ?y}}
WHERE { ex:a ex:p1* ?y}

SPARQLデータセットの指定

Oracle RDF Graph Adapter for Eclipse RDF4Jでは、SPARQL更新文字列の外部でデータセットを指定できません。OperationおよびそのサブインタフェースでのsetDatasetメソッドによるデータセット指定はサポートされていません。かわりに、WITHUSINGおよびUSING NAMED SPARQL句を使用して、SPARQL更新文字列自体でデータセットを指定します。

バインド値

SPARQL更新操作では、バインド値はサポートされていません。

ロングRDFリテラル

前の項で説明したように、長さが4000バイトを超えるラージRDFリテラル値は、一部のSPARQL問合せ関数ではサポートされていません。この制限は、ロング・リテラル・データに対してこれらの関数のいずれかを使用するSPARQL更新操作に影響します。詳細は、SEM_MATCH使用時の特別な考慮事項を参照してください。

更新タイムアウト

OperationおよびそのサブインタフェースでのsetMaxExecutionTimeメソッドによる更新タイムアウトはサポートされていません。

8.7 RDFデータの効率的なロード

Oracle RDF Graph Adapter for Eclipse RDF4Jには、ファイルまたはコレクションから大量のRDFデータを効率的にロードするための追加または改善されたJavaメソッドが用意されています。

RDFデータのバルク・ロード

アダプタのバルク・ロード機能には、次の2つのステップが含まれます。

  1. ファイルまたは文のコレクションからステージング表へのRDFデータのロード。
  2. ステージング表からRDF記憶域表へのRDFデータのロード。

アダプタのOracleBulkUpdateHandlerクラスには、バルク・ロードを実装する2種類の方法を可能にするメソッドが用意されています。

  1. addInBulk: これらのメソッドを使用すると、RDFデータのバルク・ロードで説明されている両方のステップを1回の起動で実行できます。この方法は、ロード元のファイルまたはコレクションが1つのみの場合に適しています。
  2. prepareBulkおよびcompleteBulk: prepareBulkを1回以上起動できます。各コールでは、RDFデータのバルク・ロードのステップ1を実装します。

    後で、completeBulkを1回起動してRDFデータのバルク・ロードのステップ2を実行し、これら複数のprepareBulkコールから取得したステージング表データをロードできます。この方法は、ロード元のファイルが複数ある場合に適しています。

また、アダプタの OracleSailRepositoryConnectionクラスは、SailRepositoryConnectionクラスの次のメソッドについてバルク・ロード実装を提供します。

public void add(InputStream in,
                     String baseURI,
                     RDFFormat dataFormat,
                     Resource... contexts)

圧縮ファイルからのバルク・ロードもサポートされていますが、現在はgzipファイルのみに制限されています。

8.8 Oracle RDF Graph Adapter for Eclipse RDF4Jのベスト・プラクティス

この項では、Oracle RDF Graph Adapter for Eclipse RDF4Jのパフォーマンスのベスト・プラクティスについて説明します。

リソースのクローズ

アプリケーション・プログラマは、リソース・リークを避けるように注意する必要があります。Oracle RDF Graph Adapter for Eclipse RDF4Jで回避すべき2つの最も重要なタイプのリソース・リークは、JDBC接続リークとデータベース・カーソル・リークです。

JDBC接続リークの回避

OracleRepositoryまたはOracleSailStoregetConnectionをコールしてOracleSailConnectionまたはOracleSailRepositoryConnectionオブジェクトを作成するたびに、OraclePoolから新しいJDBC接続が取得されます。作成したOracleSailConnectionまたはOracleSailRepositoryConnectionオブジェクトでcloseメソッドを明示的にコールして、これらのJDBC接続がOraclePoolに返されることを確認する必要があります。

データベース・カーソル・リークの回避

いくつかのRDF4J APIコールはイテレータを戻します。Eclipse RDF4J用のアダプタを使用する場合、これらのイテレータの多くには、イテレータの作成時にオープンし、データベース・カーソル・リークを回避するためにクローズする必要がある、基になるJDBC ResultSetがあります。

Oracleのイテレータは、次の2通りの方法でクローズできます。

  1. これらをtry-with-resources文で作成し、Java Autoclosableに依存してイテレータをクローズします。
    
    String queryString = 
       "PREFIX ex: <http://example.org/ontology/>\n"+
       "SELECT * WHERE {?x ex:name ?y}\n" +
       "ORDER BY ASC(STR(?y)) LIMIT 1 ";
    
    TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
    
    try (TupleQueryResult result = tupleQuery.evaluate()) {
      while (result.hasNext()) {
        BindingSet bindingSet = result.next();
        System.out.println("value of x: " + bindingSet.getValue("x"));
        System.out..println("value of y: " + bindingSet.getValue("y"))
      }
    }
  2. イテレータでcloseメソッドを明示的にコールします。
    
    String queryString =
      "PREFIX ex: <http://example.org/ontology/>\n"+
      "SELECT * WHERE {?x ex:name ?y}\n" +        
      "ORDER BY ASC(STR(?y)) LIMIT 1 ";      
    TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);      
    TupleQueryResult result = tupleQuery.evaluate();      
    try {        
      while (result.hasNext()) {          
        BindingSet bindingSet = result.next();          
        System.out.println("value of x: " + bindingSet.getValue("x"));          
        System.out..println("value of y: " + bindingSet.getValue("y"))        
      }      
    }      
    finally {        
      result.close();      
    }

統計の収集

大量のセマンティク・データをデータベースにロードした後、推論を実行する前に、アプリケーション表、セマンティク・モデルおよび推論されたグラフ(存在する場合)を分析することをお薦めします。分析操作を実行することで統計情報が収集され、問合せの応答時にOracleオプティマイザが効率的な実行計画を選択しやすくなります。

関連する統計を収集するには、OracleSailConnectionで、次のメソッドを使用します。

  • OracleSailConnection.analyze
  • OracleSailConnection.analyzeApplicationTable

パラメータを含むこれらのメソッドの詳細は、RDF Semantic Graph Support for Eclipse RDF4JのJavadocを参照してください。

JDBCバインド値

定数値のみが異なる一連のSPARQLクエリを実行する場合は、常に、JDBCバインド値を使用することをお薦めします。バインド値を使用すると、大量の問合せコンパイル・オーバーヘッドが節約され、問合せワークロードのスループットが大幅に向上します。

JDBCバインド値の詳細は、JDBCバインド値の使用および例13: JDBCバインド値の使用を参照してください。

8.9 Oracle RDF Graph Adapter for Eclipse RDF4Jでの空白ノードのサポート

SPARQL問合せにおいて、<>で囲まれていない空白ノードは、問合せがEclipse RDF4J用のアダプタのサポートを介して実行されるときに変数とみなされます。これは、SPARQL標準セマンティクと一致します。

ただし、<>で囲まれた空白ノードは、問合せが実行されるときに定数とみなされ、空白ノード・ラベルには、基礎となるデータのモデル化で必要とされる適切な接頭辞が、support for Eclipse RDF4Jによって追加されます。アプリケーション表のCONTEXT列には、空白ノードを使用しません。2つの異なるセマンティク・モデルの名前付きグラフの空白ノードが同じラベルを持つ場合、これらが同じリソースとみなされてしまうためです。これは、トリプル内の空白ノードには該当せず、異なるモデルのものは別々に格納されます。

Oracleデータベースに格納されている場合、空白ノードには、モデルIDおよびグラフ名に基づく接頭辞が埋め込まれます。したがって、RDF4J APIおよびOracle Databaseで使用される空白ノード間の変換が必要です。これは次のメソッドを使用して行います。

  • OracleUtils.addOracleBNodePrefix
  • OracleUtils.removeOracleBNodePrefix

8.10 Oracle RDF Graph Adapter for Eclipse RDF4Jでサポートされていない機能

この項では、現在のバージョンのOracle RDF Graph Adapter for Eclipse RDF4Jでサポートされていない機能について説明します。

Oracle RDF Graphの次の機能は、Eclipse RDF4J用のアダプタのこのバージョンではサポートされません。

  • RDFビュー・モデル
  • ネイティブのUnicodeの記憶域(Oracle Databaseバージョン21c以降で使用可能)
  • Oracle Autonomous DatabaseでのRDFグラフの管理
Eclipse RDF4J APIの次の機能は、Eclipse RDF4J用のアダプタのこのバージョンではサポートされません。
  • OperationおよびそのサブインタフェースでのsetDatasetメソッドを使用したSPARQLデータセット指定はサポートされていません。データセットはSPARQL問合せまたは更新文字列自体で指定する必要があります。
  • OperationおよびそのサブインタフェースでのsetMaxExecutionTimeメソッドによる問合せおよび更新タイムアウトの指定はサポートされていません。
  • OracleTupleを実装していないTupleExprOracleSailConnectionevaluateメソッドに渡すことはできません。
  • OracleSailRepositoryConnection以外のRepositoryConnection実装から作成されたUpdateオブジェクトは、Oracle RDFに対して実行できません。

8.11 Oracle RDF Graph Adapter for Eclipse RDF4Jを使用した問合せの例

この項では、Oracle RDF Graph Adapter for Eclipse RDF4Jを使用するための問合せの例を示します。

これらの例を実行するには、Javaコードでアダプタを使用するためのサポート・ライブラリで説明されているすべてのサポート・ライブラリがCLASSPATH定義に含まれていることを確認します。

問合せを実行するには、次のアクションを実行する必要があります。
  1. コード例をJavaソース・ファイルに含めます。
  2. CPという名前のCLASSPATH環境変数を定義して、関連するjarファイルを含めます。たとえば、次のように定義できます。
    setenv CP .:ojdbc8.jar:ucp.jar:oracle-rdf4j-adapter-4.2.1.jar:log4j-api-2.17.2.jar:log4j-core-2.17.2.jar:log4j-slf4j-impl-2.17.2.jar:slf4j-api-1.7.36.jar:eclipse-rdf4j-4.2.1-onejar.jar:commons-io-2.11.0.jar

    ノート:

    前述のsetenvコマンドは、jarファイルが現在のディレクトリにあることを前提としています。コマンドを変更して、これらのjarファイルの環境内の場所を示す必要がある場合があります。
  3. Javaソース・ファイルをコンパイルします。たとえば、ソース・ファイルTest.javaをコンパイルするには、次のコマンドを実行します。
    javac -classpath $CP Test.java
  4. 特定のJavaプログラムに必要なコマンドライン引数を渡して、コンパイルされたファイルを実行します。
    • この項の例では、既存のMDSYSネットワークに対してコンパイルされたファイルを実行できます。たとえば、既存のMDSYSネットワークで、コンパイルされたファイルをTestModelという名前のRDFグラフ(モデル)で実行するには、次のコマンドを実行します。
      java -classpath $CP Test jdbc:oracle:thin:@localhost:1521:orcl scott <password-for-scott> TestModel
    • この例では、スキーマプライベート・ネットワークをオプションで使用することもできます。したがって、この項の例のコンパイルされたファイルを、既存のスキーマプライベートネットワークに対して実行できます。たとえば、コンパイルされたファイルを、所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークのTestModelという名前のRDFグラフ(モデル)で実行するには、次のコマンドを実行します。
      java -classpath $CP Test jdbc:oracle:thin:@localhost:1521:orcl scott  <password-for-scott> TestModel scott net1

8.11.1 例1: 基本操作

例8-5に、add文やremove文などの基本操作を実行するBasicOper.javaファイルを示します。

例8-5 基本操作

import java.io.IOException;
import java.io.PrintStream;
import java.sql.SQLException;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailConnection;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.common.iteration.CloseableIteration;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.sail.SailException;

public class BasicOper {
  public static void main(String[] args) throws ConnectionSetupException, SQLException, IOException {
    PrintStream psOut = System.out;
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String networkOwner = (args.length > 5) ? args[4] : null;
    String networkName = (args.length > 5) ? args[5] : null;
    OraclePool op = null;
    OracleSailStore store = null;
    Repository sr = null;
    OracleSailConnection conn = null;

    try {
      op = new OraclePool(jdbcUrl, user, password);
      store = new OracleSailStore(op, model, networkOwner, networkName);
      sr = new OracleRepository(store);

      ValueFactory f = sr.getValueFactory();
      conn = store.getConnection();

      // create some resources and literals to make statements out of
      IRI p = f.createIRI("http://p");
      IRI domain = f.createIRI("http://www.w3.org/2000/01/rdf-schema#domain");
      IRI cls = f.createIRI("http://cls");
      IRI a = f.createIRI("http://a");
      IRI b = f.createIRI("http://b");
      IRI ng1 = f.createIRI("http://ng1");

      conn.addStatement(p, domain, cls);
      conn.addStatement(p, domain, cls, ng1);
      conn.addStatement(a, p, b, ng1);
      psOut.println("size for given contexts " + ng1 + ": " + conn.size(ng1));
      
      // returns OracleStatements
      CloseableIteration < ?extends Statement, SailException > it;
      int cnt;
      
      // retrieves all statements that appear in the repository(regardless of context)
      cnt = 0;
      it = conn.getStatements(null, null, null, false);
      while (it.hasNext()) {
        Statement stmt = it.next();
        psOut.println("getStatements: stmt#" + (++cnt) + ":" + stmt.toString());
      }
      it.close();
      conn.removeStatements(null, null, null, ng1);
      psOut.println("size of context " + ng1 + ":" + conn.size(ng1));
      conn.removeAll();
      psOut.println("size of store: " + conn.size());
    }
    
    finally {
      if (conn != null && conn.isOpen()) {
        conn.close();
      }
      if (op != null && op.getOracleDB() != null)

      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
      if (sr != null) sr.shutDown();
      if (store != null) store.shutDown();
      if (op != null) op.close();
    }
  }
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP BasicOper.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP BasicOper jdbc:oracle:thin:@localhost:1521:ORCL scott <password-for-scott> TestModel

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP BasicOper jdbc:oracle:thin:@localhost:1521:ORCL scott <password-for-scott> TestModel scott net1

javaコマンドの出力は、次のようになります。

size for given contexts http://ng1: 2
getStatements: stmt#1: (http://a, http://p, http://b) [http://ng1]
getStatements: stmt#2: (http://p, http://www.w3.org/2000/01/rdf-schema#domain, http://cls) [http://ng1]
getStatements: stmt#3: (http://p, http://www.w3.org/2000/01/rdf-schema#domain, http://cls) [null]
size of context http://ng1:0
size of store: 0

8.11.2 例2: TRIG形式のデータ・ファイルを追加する

例8-6に、TRIG形式でファイルをロードする方法を示すLoadFile.javaファイルを示します。

例8-6 TRIG形式のデータ・ファイルの追加

import java.io. * ;
import java.sql.SQLException;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.eclipse.rdf4j.rio.RDFParseException;
import org.eclipse.rdf4j.sail.SailException;
import org.eclipse.rdf4j.rio.RDFFormat;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailConnection;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;

public class LoadFile {
  public static void main(String[] args) throws ConnectionSetupException,
    SQLException, SailException, RDFParseException, RepositoryException,
    IOException {
    
      PrintStream psOut = System.out;
      String jdbcUrl = args[0];
      String user = args[1];
      String password = args[2];
      String model = args[3];
      String trigFile = args[4];
      String networkOwner = (args.length > 6) ? args[5] : null;
      String networkName = (args.length > 6) ? args[6] : null;

 
      OraclePool op = null;
      OracleSailStore store = null;
      Repository sr = null;
      RepositoryConnection repConn = null;
 
      try {
        op = new OraclePool(jdbcUrl, user, password);
        store = new OracleSailStore(op, model, networkOwner, networkName);
        sr = new OracleRepository(store);
        repConn = sr.getConnection();
        psOut.println("testBulkLoad: start: before-load Size=" + repConn.size());
        repConn.add(new File(trigFile), "http://my.com/", RDFFormat.TRIG);
        repConn.commit();
        psOut.println("size " + Long.toString(repConn.size()));
      }
      finally {
        if (repConn != null) {
          repConn.close();
        }
        if (op != null) OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
        if (sr != null) sr.shutDown();
        if (store != null) store.shutDown();
        if (op != null) op.close();
      }
  }
}

この例を実行するため、次のようなサンプルのTriGデータ・ファイルがtest.trigという名前で作成されているとします。


@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
@prefix swp: <http://www.w3.org/2004/03/trix/swp-1/>.
@prefix dc: <http://purl.org/dc/elements/1.1/>.
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
@prefix ex: <http://example.org/>.
@prefix : <http://example.org/>.
# default graph
{
  <http://example.org/bob>   dc:publisher "Bob Hacker".
  <http://example.org/alice> dc:publisher "Alice Hacker".
} 
:bob{
    _:a foaf:mbox <mailto:bob@oldcorp.example.org>.
    } 
:alice{
      _:a foaf:name "Alice".
      _:a foaf:mbox <mailto:alice@work.example.org>.
      } 
:jack {
      _:a foaf:name "Jack".
      _:a foaf:mbox <mailto:jack@oracle.example.org>.
      }

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP LoadFile.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP LoadFile jdbc:oracle:thin:@localhost:1521:ORCL scott <password>  TestModel ./test.trig

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP LoadFile jdbc:oracle:thin:@localhost:1521:ORCL scott <password>  TestModel ./test.trig scott net1

javaコマンドの出力は、次のようになります。

testBulkLoad: start: before-load Size=0
size 7

8.11.3 例3: 単純な問合せ

例3: 単純な問合せに、単純な問合せの実行方法を示すSimpleQuery.javaファイルを示します。

例8-7 単純な問合せ


import java.io.IOException;
import java.io.PrintStream;
import java.sql.SQLException;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;

public class SimpleQuery {
  public static void main(String[] args) throws ConnectionSetupException, SQLException, IOException {
    PrintStream psOut = System.out;
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String networkOwner = (args.length > 5) ? args[4] : null;
    String networkName = (args.length > 5) ? args[5] : null;


    OraclePool op = null;
    OracleSailStore store = null;
    Repository sr = null;
    RepositoryConnection conn = null;

    try {
      op = new OraclePool(jdbcUrl, user, password);
      store = new OracleSailStore(op, model, networkOwner, networkName);
      sr = new OracleRepository(store);

      ValueFactory f = sr.getValueFactory();
      conn = sr.getConnection();

      // create some resources and literals to make statements out of
      IRI alice = f.createIRI("http://example.org/people/alice");
      IRI name = f.createIRI("http://example.org/ontology/name");
      IRI person = f.createIRI("http://example.org/ontology/Person");
      Literal alicesName = f.createLiteral("Alice");

      conn.clear(); // to start from scratch
      conn.add(alice, RDF.TYPE, person);
      conn.add(alice, name, alicesName);
      conn.commit();
      
      //run a query against the repository
      String queryString = 
        "PREFIX ex: <http://example.org/ontology/>\n" + 
        "SELECT * WHERE {?x ex:name ?y}\n" + 
        "ORDER BY ASC(STR(?y)) LIMIT 1 ";
      TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);

      try (TupleQueryResult result = tupleQuery.evaluate()) {
        while (result.hasNext()) {
          BindingSet bindingSet = result.next();
          psOut.println("value of x: " + bindingSet.getValue("x"));
          psOut.println("value of y: " + bindingSet.getValue("y"));
        }
      }
    }
    finally {
      if (conn != null && conn.isOpen()) {
        conn.clear();
        conn.close();
      }
      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
      sr.shutDown();
      store.shutDown();
      op.close();
    }
  }
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP SimpleQuery.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SimpleQuery jdbc:oracle:thin:@localhost:1521:ORCL scott <password-for-scott> TestModel

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SimpleQuery jdbc:oracle:thin:@localhost:1521:ORCL scott <password-for-scott> TestModel scott net1

javaコマンドの出力は、次のようになります。


value of x: http://example.org/people/alice
value of y: "Alice"

8.11.4 例4: 単純なバルク・ロード

例8-8に、NTriplesデータからバルク・ロードする方法を示すSimpleBulkload.javaファイルを示します。

例8-8 単純なバルク・ロード


import java.io. * ;
import java.sql.SQLException;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.eclipse.rdf4j.rio.RDFParseException;
import org.eclipse.rdf4j.sail.SailException;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.eclipse.rdf4j.repository.Repository;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailConnection;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;

public class SimpleBulkLoad {
  public static void main(String[] args) throws ConnectionSetupException, SQLException,
    SailException, RDFParseException, RepositoryException, IOException {
      PrintStream psOut = System.out;
      String jdbcUrl = args[0];
      String user = args[1];
      String password = args[2];
      String model = args[3];
      String filename = args[4]; // N-TRIPLES file
      String networkOwner = (args.length > 6) ? args[5] : null;
      String networkName = (args.length > 6) ? args[6] : null;


      OraclePool op = new OraclePool(jdbcUrl, user, password);
      OracleSailStore store = new OracleSailStore(op, model, networkOwner, networkName);
      OracleSailConnection osc = store.getConnection();
      Repository sr = new OracleRepository(store);
      ValueFactory f = sr.getValueFactory();

      try {
        psOut.println("testBulkLoad: start");

        FileInputStream fis = new
        FileInputStream(filename);

        long loadBegin = System.currentTimeMillis();
        IRI ng1 = f.createIRI("http://QuadFromTriple");
        osc.getBulkUpdateHandler().addInBulk(
        fis, "http://abc",  // baseURI
        RDFFormat.NTRIPLES, // dataFormat
        null,               // tablespaceName
        50,                 // batchSize
        null,               // flags
        ng1                 // Resource... for contexts
        );

        long loadEnd = System.currentTimeMillis();
        long size_no_contexts = osc.size((Resource) null);
        long size_all_contexts = osc.size();

        psOut.println("testBulkLoad: " + (loadEnd - loadBegin) +
         "ms. Size:" + " NO_CONTEXTS=" + size_no_contexts + " ALL_CONTEXTS=" + size_all_contexts);
        // cleanup
        osc.removeAll();
        psOut.println("size of store: " + osc.size());

      }
      finally {
        if (osc != null && osc.isOpen()) osc.close();
        if (op != null) OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
        if (sr != null) sr.shutDown();
        if (store != null) store.shutDown();
        if (op != null) op.close();
      }
  }
}

この例を実行するため、次のようなサンプルのntripleデータ・ファイルがtest.ntriplesという名前で作成されているとします。


<urn:JohnFrench> <urn:name> "John".
<urn:JohnFrench> <urn:speaks> "French".
<urn:JohnFrench> <urn:height> <urn:InchValue>.
<urn:InchValue> <urn:value> "63".
<urn:InchValue> <urn:unit> "inch".
<http://data.linkedmdb.org/movie/onto/genreNameChainElem1> <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://data.linkedmdb.org/movie/genre>.

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP SimpleBulkLoad.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SimpleBulkLoad jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel ./test.ntriples

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SimpleBulkLoad jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel ./test.ntriples scott net1

javaコマンドの出力は、次のようになります。

testBulkLoad: start
testBulkLoad: 8222ms. 
Size: NO_CONTEXTS=0 ALL_CONTEXTS=6
size of store: 0

8.11.5 例5: RDF/XMLのバルク・ロード

例5: RDF/XMLのバルク・ロードに、RDF/XMLファイルからバルク・ロードする方法を示すBulkLoadRDFXML.javaファイルを示します。

例8-9 RDF/XMLのバルク・ロード


import java.io. * ;
import java.sql.SQLException;
import org.eclipse.rdf4j.model.Resource;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.RepositoryException;
import org.eclipse.rdf4j.rio.RDFParseException;
import org.eclipse.rdf4j.sail.SailException;
import org.eclipse.rdf4j.rio.RDFFormat;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailConnection;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;

public class BulkLoadRDFXML {
  public static void main(String[] args) throws
    ConnectionSetupException, SQLException, SailException,
    RDFParseException, RepositoryException, IOException {
      PrintStream psOut = System.out;
      String jdbcUrl = args[0];
      String user = args[1];
      String password = args[2];
      String model = args[3];
      String rdfxmlFile = args[4]; // RDF/XML-format data file
      String networkOwner = (args.length > 6) ? args[5] : null;
      String networkName = (args.length > 6) ? args[6] : null;


      OraclePool op = null;
      OracleSailStore store = null;
      Repository sr = null;
      OracleSailConnection conn = null;
            
      try {
        op = new OraclePool(jdbcUrl, user, password);
        store = new OracleSailStore(op, model, networkOwner, networkName);
        sr = new OracleRepository(store);
        conn = store.getConnection();
        
        FileInputStream fis = new FileInputStream(rdfxmlFile);
        psOut.println("testBulkLoad: start: before-load Size=" + conn.size());
        long loadBegin = System.currentTimeMillis();
        conn.getBulkUpdateHandler().addInBulk(
          fis, 
          "http://abc",      // baseURI
          RDFFormat.RDFXML,  // dataFormat
          null,              // tablespaceName
          null,              // flags
          null,             //  StatusListener
          (Resource[]) null //  Resource...for contexts
        );

        long loadEnd = System.currentTimeMillis();
        psOut.println("testBulkLoad: " + (loadEnd - loadBegin) + "ms. Size=" + conn.size() + "\n");
      }
      finally {
        if (conn != null && conn.isOpen()) {
          conn.close();
        }
        if (op != null) OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
        if (sr != null) sr.shutDown();
        if (store != null) store.shutDown();
        if (op != null) op.close();
      }
  }
}

この例を実行するため、次のようなサンプル・ファイルがRdfXmlData.rdfxmlという名前で作成されているとします。


<?xml version="1.0"?>
<!DOCTYPE owl [     
  <!ENTITY owl  "http://www.w3.org/2002/07/owl#" >     
  <!ENTITY xsd  "http://www.w3.org/2001/XMLSchema#" >   
]> 
<rdf:RDF  
  xmlns     = "http://a/b#" xml:base  = "http://a/b#" xmlns:my  = "http://a/b#"  
  xmlns:owl = "http://www.w3.org/2002/07/owl#"  
  xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"  
  xmlns:rdfs= "http://www.w3.org/2000/01/rdf-schema#"  
  xmlns:xsd = "http://www.w3.org/2001/XMLSchema#">  
  <owl:Class rdf:ID="Color">    
    <owl:oneOf rdf:parseType="Collection">      
      <owl:Thing rdf:ID="Red"/>      
      <owl:Thing rdf:ID="Blue"/>    
    </owl:oneOf>  
  </owl:Class>
</rdf:RDF>

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP BulkLoadRDFXML.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP BulkLoadRDFXML jdbc:oracle:thin:@localhost:1521:ORCL scott <password>  TestModel ./RdfXmlData.rdfxml

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP BulkLoadRDFXML jdbc:oracle:thin:@localhost:1521:ORCL scott <password>  TestModel ./RdfXmlData.rdfxml scott net1

javaコマンドの出力は、次のようになります。

testBulkLoad: start: before-load Size=0
testBulkLoad: 6732ms. Size=8

8.11.6 例6: SPARQL ASK問合せ

例6: SPARQL ASK問合せに、SPARQL ASK問合せの実行方法を示すSparqlASK.javaファイルを示します。

例8-10 SPARQL ASK問合せ

import java.io.PrintStream;
import java.sql.SQLException;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailConnection;
import oracle.rdf4j.adapter.OracleSailRepositoryConnection;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.vocabulary.RDFS;
import org.eclipse.rdf4j.query.BooleanQuery;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;

public class SparqlASK {
  public static void main(String[] args) throws ConnectionSetupException, SQLException {
    PrintStream psOut = System.out;
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String networkOwner = (args.length > 5) ? args[4] : null;
    String networkName = (args.length > 5) ? args[5] : null;


    OraclePool op = null;
    OracleSailStore store = null;
    Repository sr = null;
    RepositoryConnection conn = null;

    try {
      op = new OraclePool(jdbcUrl, user, password);
      store = new OracleSailStore(op, model, networkOwner, networkName);
      sr = new OracleRepository(store);
      conn = sr.getConnection();
      OracleSailConnection osc = 
        (OracleSailConnection)((OracleSailRepositoryConnection) conn).getSailConnection();

      ValueFactory vf = sr.getValueFactory();
      IRI p = vf.createIRI("http://p");
      IRI cls = vf.createIRI("http://cls");

      conn.clear();
      conn.add(p, RDFS.DOMAIN, cls);
      conn.commit();

      osc.analyze();                 // analyze the semantic model
      osc.analyzeApplicationTable(); // and then the application table
      BooleanQuery tq = null;
      tq = conn.prepareBooleanQuery(QueryLanguage.SPARQL, "ASK { ?x ?p <http://cls> }");
      boolean b = tq.evaluate();
      psOut.println("\nAnswer is " + Boolean.toString(b));
    }
    finally {
      if (conn != null && conn.isOpen()) {
        conn.clear();
        conn.close();
      }
      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
      sr.shutDown();
      store.shutDown();
      op.close();
    }
  }
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP SparqlASK.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SparqlASK jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SparqlASK jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel scott net1

javaコマンドの出力は、次のようになります。

Answer is true

8.11.7 例7: SPARQL CONSTRUCT問合せ

例8-11に、SPARQLのCONSTRUCT問合せの実行方法を示すSparqlConstruct.javaファイルを示します。

例8-11 SPARQL CONSTRUCT問合せ


import java.io.PrintStream;
import java.sql.SQLException;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailConnection;
import oracle.rdf4j.adapter.OracleSailRepositoryConnection;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Statement;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.vocabulary.RDFS;
import org.eclipse.rdf4j.query.GraphQuery;
import org.eclipse.rdf4j.query.GraphQueryResult;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;

public class SparqlConstruct {
  public static void main(String[] args) throws ConnectionSetupException, SQLException {
    PrintStream psOut = System.out;
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String networkOwner = (args.length > 5) ? args[4] : null;
    String networkName = (args.length > 5) ? args[5] : null;


    OraclePool op = null;
    OracleSailStore store = null;
    Repository sr = null;
    RepositoryConnection conn = null;

    try {
      op = new OraclePool(jdbcUrl, user, password);
      store = new OracleSailStore(op, model, networkOwner, networkName);
      sr = new OracleRepository(store);
      conn = sr.getConnection();

      ValueFactory vf = sr.getValueFactory();
      IRI p = vf.createIRI("http://p");
      IRI cls = vf.createIRI("http://cls");

      conn.clear();
      conn.add(p, RDFS.DOMAIN, cls);
      conn.commit();
      OracleSailConnection osc = 
        (OracleSailConnection)((OracleSailRepositoryConnection) conn).getSailConnection();
      osc.analyze();                 // analyze the semantic model
      osc.analyzeApplicationTable(); // and then the application table
                                     
      GraphQuery tq = null;          // Construct Query
      tq = conn.prepareGraphQuery(QueryLanguage.SPARQL, 
        "CONSTRUCT {?x <http://new_eq_p> ?o } WHERE { ?x ?p ?o }");
      psOut.println("Start construct query");

      try (GraphQueryResult result = tq.evaluate()) {
        while (result.hasNext()) {
          Statement stmt = (Statement) result.next();
          psOut.println(stmt.toString());
        }
      }
    }
    finally {
      if (conn != null && conn.isOpen()) {
        conn.clear();
        conn.close();
      }
      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
      sr.shutDown();
      store.shutDown();
      op.close();
    }
  }
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP SparqlConstruct.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SparqlConstruct jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SparqlConstruct jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel scott net1

javaコマンドの出力は、次のようになります。

Start construct query
(http://p, http://new_eq_p, http://cls)

8.11.8 例8: 名前付きグラフ問合せ

例8-12に、名前付きグラフ問合せの実行方法を示すNamedGraph.javaファイルを示します。

例8-12 名前付きグラフ問合せ


import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.sql.SQLException;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailConnection;
import oracle.rdf4j.adapter.OracleSailRepositoryConnection;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.rio.RDFFormat;

public class NamedGraph {
  public static void main(String[] args) throws ConnectionSetupException, SQLException, IOException {
    PrintStream psOut = System.out;
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String trigFile = args[4]; // TRIG-format data file
    String networkOwner = (args.length > 6) ? args[5] : null;
    String networkName = (args.length > 6) ? args[6] : null;

    
    OraclePool op = null;
    OracleSailStore store = null;
    Repository sr = null;
    RepositoryConnection conn = null;
    
    try {
      op = new OraclePool(jdbcUrl, user, password);
      store = new OracleSailStore(op, model, networkOwner, networkName);
      sr = new OracleRepository(store);
      conn = sr.getConnection();

      conn.begin();
      conn.clear();

      // load the data incrementally since it is very small file
      conn.add(new File(trigFile), "http://my.com/", RDFFormat.TRIG);
      conn.commit();

      OracleSailConnection osc = (OracleSailConnection)((OracleSailRepositoryConnection) conn).getSailConnection();

      osc.analyze(); // analyze the semantic model
      osc.analyzeApplicationTable(); // and then the application table
      TupleQuery tq = null;
      tq = conn.prepareTupleQuery(QueryLanguage.SPARQL,
             "PREFIX : <http://purl.org/dc/elements/1.1/>\n" +
             "SELECT ?g ?s ?p ?o\n" +
             "WHERE {?g :publisher ?o1 . GRAPH ?g {?s ?p ?o}}\n" +
             "ORDER BY ?g ?s ?p ?o");
      try (TupleQueryResult result = tq.evaluate()) {
        int idx = 0;
        while (result.hasNext()) {
          idx++;
          BindingSet bindingSet = result.next();
          psOut.print("\nsolution " + bindingSet.toString());
        }
        psOut.println("\ntotal # of solution " + Integer.toString(idx));
      }
    }
    finally {
      if (conn != null && conn.isOpen()) {
        conn.clear();
        conn.close();
      }
      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null,  networkOwner, networkName);
      sr.shutDown();
      store.shutDown();
      op.close();
    }
  }
}

この例を実行するため、TRIG形式のtest.trigファイルが次のように作成されているとします。


@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
@prefix swp: <http://www.w3.org/2004/03/trix/swp-1/>.
@prefix dc: <http://purl.org/dc/elements/1.1/>.
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
@prefix : <http://example.org/>.
# default graph
{
  :bobGraph    dc:publisher  "Bob Hacker" .
  :aliceGraph  dc:publisher  "Alice Hacker" .
}
 
:bobGraph {
  :bob foaf:mbox <mailto:bob@oldcorp.example.org> .
}
 
:aliceGraph {
  :alice foaf:name "Alice" .
  :alice foaf:mbox <mailto:alice@work.example.org> .
}
 
:jackGraph {
  :jack foaf:name "Jack" .
  :jack foaf:mbox <mailto:jack@oracle.example.org> .
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP NamedGraph.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP NamedGraph jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel ./test.trig

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP NamedGraph jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel ./test.trig scott net1

javaコマンドの出力は、次のようになります。


solution 
[p=http://xmlns.com/foaf/0.1/mbox;s=http://example.org/alice;g=http://example.org/aliceGraph;o=mailto:alice@work.example.org]
solution 
[p=http://xmlns.com/foaf/0.1/name;s=http://example.org/alice;g=http://example.org/aliceGraph;o="Alice"]
solution 
[p=http://xmlns.com/foaf/0.1/mbox;s=http://example.org/bob;g=http://example.org/bobGraph;o=mailto:bob@oldcorp.example.org]
total # of solution 3

8.11.9 例9: 一致件数の取得

例8-13に、一致の合計件数(COUNT)を返す問合せの実行方法を示すCountQuery.javaファイルを示します。

例8-13 一致件数の取得

import java.io.PrintStream;
import java.sql.SQLException;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailConnection;
import oracle.rdf4j.adapter.OracleSailRepositoryConnection;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;

public class CountQuery {
  public static void main(String[] args) throws
    ConnectionSetupException, SQLException 
  {
    PrintStream psOut = System.out;
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String networkOwner = (args.length > 5) ? args[4] : null;
    String networkName = (args.length > 5) ? args[5] : null;


    OraclePool op = null;
    OracleSailStore store = null;
    Repository sr = null;
    RepositoryConnection conn = null;
    
    try {
      op = new OraclePool(jdbcUrl, user, password);
      store = new OracleSailStore(op, model, networkOwner, networkName);
      sr = new OracleRepository(store);
      conn = sr.getConnection();

      ValueFactory f = conn.getValueFactory();

      // create some resources and literals to make statements out of
      IRI alice = f.createIRI("http://example.org/people/alice");
      IRI name = f.createIRI("http://example.org/ontology/name");
      IRI person = f.createIRI("http://example.org/ontology/Person");
      Literal alicesName = f.createLiteral("Alice");

      conn.begin();
      // clear model to start fresh
      conn.clear();
      conn.add(alice, RDF.TYPE, person);
      conn.add(alice, name, alicesName);
      conn.commit();

      OracleSailConnection osc = 
        (OracleSailConnection)((OracleSailRepositoryConnection) conn).getSailConnection();
      osc.analyze();
      osc.analyzeApplicationTable();

      // Run a query and only return the number of matches (the count ! )
      String queryString = " SELECT (COUNT(*) AS ?totalCount) WHERE {?s ?p ?y} ";

      TupleQuery tupleQuery = conn.prepareTupleQuery(
      QueryLanguage.SPARQL, queryString);

      try (TupleQueryResult result = tupleQuery.evaluate()) {
        if (result.hasNext()) {
          BindingSet bindingSet = result.next();
          String totalCount = bindingSet.getValue("totalCount").stringValue();
          psOut.println("number of matches: " + totalCount);
        }
      }
    }
    finally {
      if (conn != null && conn.isOpen()) {
        conn.clear();
        conn.close();
      }
      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
      sr.shutDown();
      store.shutDown();
      op.close();
    }
  }
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP CountQuery.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP CountQuery jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP CountQuery jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel scott net1

javaコマンドの出力は、次のようになります。


number of matches: 2

8.11.10 例10: 問合せパターンの定数に対するバインド変数の指定

例8-13に、SPARQL問合せパターンの定数に対するバインド変数を指定する問合せの実行方法を示すBindVar.javaファイルを示します。

例8-14 問合せパターンの定数に対するバインド変数の指定


import java.io.PrintStream;
import java.sql.SQLException;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;

public class BindVar {
  public static void main(String[] args) throws ConnectionSetupException, SQLException {
    PrintStream psOut = System.out;
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String networkOwner = (args.length > 5) ? args[4] : null;
    String networkName = (args.length > 5) ? args[5] : null;


    OraclePool op = null;
    OracleSailStore store = null;
    Repository sr = null;
    RepositoryConnection conn = null;
    
    try {
      op = new OraclePool(jdbcUrl, user, password);
      store = new OracleSailStore(op, model, networkOwner, networkName);
      sr = new OracleRepository(store);
      conn = sr.getConnection();
      ValueFactory f = conn.getValueFactory();

      conn.begin();
      conn.clear();

      // create some resources and literals to make statements out of
      
      // Alice
      IRI alice = f.createIRI("http://example.org/people/alice");
      IRI name = f.createIRI("http://example.org/ontology/name");
      IRI person = f.createIRI("http://example.org/ontology/Person");
      Literal alicesName = f.createLiteral("Alice");
      conn.add(alice, RDF.TYPE, person);
      conn.add(alice, name, alicesName);

      //Bob
      IRI bob = f.createIRI("http://example.org/people/bob");
      Literal bobsName = f.createLiteral("Bob");
      conn.add(bob, RDF.TYPE, person);
      conn.add(bob, name, bobsName);

      conn.commit();

      String queryString = 
        " PREFIX ex: <http://example.org/ontology/> " + 
        " Select ?name \n" + " WHERE \n" + " { SELECT * WHERE { ?person ex:name ?name} }\n" + 
        " ORDER BY ?name";

      TupleQuery tupleQuery = conn.prepareTupleQuery(
      QueryLanguage.SPARQL, queryString);

      // set binding for ?person = Alice
      tupleQuery.setBinding("person", alice);
      try (TupleQueryResult result = tupleQuery.evaluate()) {
        if (result.hasNext()) {
          BindingSet bindingSet = result.next();
          psOut.println("solution " + bindingSet.toString());
        }
      }

      // re-run with ?person = Bob
      tupleQuery.setBinding("person", bob);
      try (TupleQueryResult result = tupleQuery.evaluate()) {
        if (result.hasNext()) {
          BindingSet bindingSet = result.next();
          psOut.println("solution " + bindingSet.toString());
        }
      }
    }
    finally {
      if (conn != null && conn.isOpen()) {
        conn.clear();
        conn.close();
      }
      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
      sr.shutDown();
      store.shutDown();
      op.close();
    }
  }
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP BindVar.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP BindVar jdbc:oracle:thin:@localhost:1521:ORCL scott  <password> TestModel

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP BindVar jdbc:oracle:thin:@localhost:1521:ORCL scott  <password> TestModel scott net1

javaコマンドの出力は、次のようになります。


solution [name="Alice";person=http://example.org/people/alice]
solution [name="Bob";person=http://example.org/people/bob]

8.11.11 例11: SPARQLの更新

例8-15に、SPARQL更新文の実行方法を示すSparqlUpdate.javaファイルを示します。

例8-15 SPARQLの更新

import java.io.PrintStream;
import java.sql.SQLException;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.query.Update;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;

public class SparqlUpdate {
  private static final String DATA_1 =
    "[p=http://example.org/ontology/name;g=urn:g1;x=http://example.org/people/Sue;y=\"Sue\"]" +
    "[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g1;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]";

  private static final String DATA_2 =
    "[p=http://example.org/ontology/name;g=urn:g1;x=http://example.org/people/Sue;y=\"Susan\"]" +
    "[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g1;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]";

  private static final String DATA_3 =
    "[p=http://example.org/ontology/name;g=urn:g1;x=http://example.org/people/Sue;y=\"Susan\"]" +
    "[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g1;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]" +
    "[p=http://example.org/ontology/name;g=urn:g2;x=http://example.org/people/Sue;y=\"Susan\"]" +
    "[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g2;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]";

  private static final String DATA_4 = 
    "[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g1;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]" +
    "[p=http://example.org/ontology/name;g=urn:g2;x=http://example.org/people/Sue;y=\"Susan\"]" +
    "[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g2;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]";

  private static final String DATA_5 =
    "[p=http://example.org/ontology/name;g=urn:g1;x=http://example.org/people/Sue;y=\"Susan\"]" +
    "[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g1;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]" +
    "[p=http://example.org/ontology/name;g=urn:g2;x=http://example.org/people/Sue;y=\"Susan\"]" +
    "[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g2;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]";
  
  private static String getRepositoryData(RepositoryConnection conn, PrintStream out) 
  {
    String dataStr = "";
    String queryString = "SELECT * WHERE { GRAPH ?g { ?x ?p ?y } } ORDER BY ?g ?x ?p ?y";
    TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);
    try (TupleQueryResult result = tupleQuery.evaluate()) {
      while (result.hasNext()) {
        BindingSet bindingSet = result.next();
        out.println(bindingSet.toString());
        dataStr += bindingSet.toString();
      }
    }
    return dataStr;
  }
  public static void main(String[] args) throws
    ConnectionSetupException, SQLException 
  {
    PrintStream out = new PrintStream(System.out);
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String networkOwner = (args.length > 5) ? args[4] : null;
    String networkName = (args.length > 5) ? args[5] : null;


    OraclePool op = null;
    OracleSailStore store = null;
    Repository sr = null;
    RepositoryConnection conn = null;
    try {
      op = new OraclePool(jdbcUrl, user, password);
      store = new OracleSailStore(op, model, networkOwner, networkName);
      sr = new OracleRepository(store);
      conn = sr.getConnection();

      conn.clear(); // to start from scratch
      
      // Insert some initial data
      String updString = "PREFIX people: <http://example.org/people/>\n" +
                         "PREFIX    ont: <http://example.org/ontology/>\n" +
                         "INSERT DATA { GRAPH <urn:g1> { \n" + 
                         "              people:Sue a ont:Person; \n" + 
                         "                ont:name \"Sue\" . } }";
      Update upd = conn.prepareUpdate(QueryLanguage.SPARQL, updString);
      upd.execute();
      conn.commit();
      String repositoryData = getRepositoryData(conn, out);
      if (! (DATA_1.equals(repositoryData)) ) out.println("DATA_1 mismatch");
      // Change Sue's name to Susan
      updString = "PREFIX people: <http://example.org/people/>\n" +
                  "PREFIX    ont: <http://example.org/ontology/>\n" +
                  "DELETE { GRAPH ?g { ?s ont:name ?n } }\n" +
                  "INSERT { GRAPH ?g { ?s ont:name \"Susan\" } }\n" +
                  "WHERE  { GRAPH ?g { ?s ont:name ?n FILTER (?n = \"Sue\") }}";
      upd = conn.prepareUpdate(QueryLanguage.SPARQL, updString);
      upd.execute();
      conn.commit();
      repositoryData = getRepositoryData(conn, out);
      if (! (DATA_2.equals(repositoryData)) ) out.println("DATA_2 mismatch");

      // Copy to contents of g1 to a new graph g2
      updString = "PREFIX people: <http://example.org/people/>\n" +
                  "PREFIX ont: <http://example.org/ontology/>\n" +
                  "COPY <urn:g1> TO <urn:g2>";
      upd = conn.prepareUpdate(QueryLanguage.SPARQL, updString);
      upd.execute();
      conn.commit();

      repositoryData = getRepositoryData(conn, out);
      if (! (DATA_3.equals(repositoryData)) ) out.println("DATA_3 mismatch");

      // Delete ont:name triple from graph g1
      updString = "PREFIX people: <http://example.org/people/>\n" + 
                  "PREFIX  ont: <http://example.org/ontology/>\n" +
                  "DELETE DATA { GRAPH <urn:g1> { people:Sue ont:name \"Susan\" } }";
      upd = conn.prepareUpdate(QueryLanguage.SPARQL, updString);
      upd.execute();
      conn.commit();
      repositoryData = getRepositoryData(conn, out);
      if (! (DATA_4.equals(repositoryData)) ) out.println("DATA_4 mismatch");

      // Add contents of g2 to g1
      updString = "PREFIX people: <http://example.org/people/>\n" +
                  "PREFIX    ont: <http://example.org/ontology/>\n" +
                  "ADD <urn:g2> TO <urn:g1>";
      upd = conn.prepareUpdate(QueryLanguage.SPARQL, updString);
      upd.execute();
      conn.commit();
      repositoryData = getRepositoryData(conn, out);
      if (! (DATA_5.equals(repositoryData)) ) out.println("DATA_5 mismatch");
    }
    finally {
      if (conn != null && conn.isOpen()) {
        conn.clear();
        conn.close();
      }
      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
      sr.shutDown();
      store.shutDown();
      op.close();
    }
  }
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP SparqlUpdate.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SparqlUpdate jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SparqlUpdate jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel scott net1

javaコマンドの出力は、次のようになります。

[p=http://example.org/ontology/name;g=urn:g1;x=http://example.org/people/Sue;y="Sue"]
[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g1;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]
[p=http://example.org/ontology/name;g=urn:g1;x=http://example.org/people/Sue;y="Susan"]
[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g1;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]
[p=http://example.org/ontology/name;g=urn:g1;x=http://example.org/people/Sue;y="Susan"]
[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g1;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]
[p=http://example.org/ontology/name;g=urn:g2;x=http://example.org/people/Sue;y="Susan"]
[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g2;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]
[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g1;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]
[p=http://example.org/ontology/name;g=urn:g2;x=http://example.org/people/Sue;y="Susan"]
[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g2;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]
[p=http://example.org/ontology/name;g=urn:g1;x=http://example.org/people/Sue;y="Susan"]
[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g1;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]
[p=http://example.org/ontology/name;g=urn:g2;x=http://example.org/people/Sue;y="Susan"]
[p=http://www.w3.org/1999/02/22-rdf-syntax-ns#type;g=urn:g2;x=http://example.org/people/Sue;y=http://example.org/ontology/Person]

8.11.12 例12: Oracleヒント

例8-16に、SPARQL問合せまたはSPARQL更新でOracleヒントを使用する方法を示すOracleHint.javaファイルを示します。

例8-16 Oracleヒント

import java.sql.SQLException;
import oracle.rdf4j.adapter.OracleDB;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.query.Update;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;

public class OracleHint {
  public static void main(String[] args) throws ConnectionSetupException, SQLException {
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String networkOwner = (args.length > 5) ? args[4] : null;
    String networkName = (args.length > 5) ? args[5] : null;


    OraclePool op = null;
    OracleSailStore store = null;
    Repository sr = null;
    RepositoryConnection conn = null;
    
    try {
      op = new OraclePool(jdbcUrl, user, password);
      store = new OracleSailStore(op, model, networkOwner, networkName);
      sr = new OracleRepository(store);
      conn = sr.getConnection();

      conn.clear(); // to start from scratch
      
      // Insert some initial data
      String updString = 
        "PREFIX ex: <http://example.org/>\n" +
        "INSERT DATA {  " +
        "  ex:a ex:p1 ex:b . " +
        "  ex:b ex:p1 ex:c . " + 
        "  ex:c ex:p1 ex:d . " +
        "  ex:d ex:p1 ex:e . " +
        "  ex:e ex:p1 ex:f . " + 
        "  ex:f ex:p1 ex:g . " + 
        "  ex:g ex:p1 ex:h . " + 
        "  ex:h ex:p1 ex:i . " + 
        "  ex:i ex:p1 ex:j . " + 
        "  ex:j ex:p1 ex:k . " + 
        "}";
      Update upd = conn.prepareUpdate(QueryLanguage.SPARQL, updString);
      upd.execute();
      conn.commit();
      
      // default behavior for property path is 10 hop max, so we get 11 results
      String sparql = 
        "PREFIX ex: <http://example.org/>\n" + 
        "SELECT (COUNT(*) AS ?cnt)\n" + 
        "WHERE { ex:a ex:p1* ?y }";
      
      TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, sparql);

      try (TupleQueryResult result = tupleQuery.evaluate()) {
        while (result.hasNext()) {
          BindingSet bindingSet = result.next();
          if (11 != Integer.parseInt(bindingSet.getValue("cnt").stringValue())) System.out.println("cnt mismatch: expecting 11");
        }
      }

      // ORACLE_SEM_FS_NS prefix hint to use parallel(2) and dynamic_sampling(6)
      // ORACLE_SEM_SM_NS prefix hint to use a 5 hop max and to use CONNECT BY instead of simple join
      sparql = 
        "PREFIX ORACLE_SEM_FS_NS: <http://oracle.com/semtech#dop=2,ods=6>\n" +
        "PREFIX ORACLE_SEM_SM_NS: <http://oracle.com/semtech#all_max_pp_depth(5),all_disable_pp_sj>\n" +
        "PREFIX ex: <http://example.org/>\n" + 
        "SELECT (COUNT(*) AS ?cnt)\n" + 
        "WHERE { ex:a ex:p1* ?y }";
      
      tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, sparql, "http://example.org/");

      try (TupleQueryResult result = tupleQuery.evaluate()) {
        while (result.hasNext()) {
          BindingSet bindingSet = result.next();
          if (6 != Integer.parseInt(bindingSet.getValue("cnt").stringValue())) System.out.println("cnt mismatch: expecting 6");
        }
      }

      // query options for SPARQL Update      
      sparql = 
        "PREFIX ORACLE_SEM_UM_NS: <http://oracle.com/semtech#parallel(2)>\n" +
        "PREFIX ORACLE_SEM_SM_NS: <http://oracle.com/semtech#all_max_pp_depth(5),all_disable_pp_sj>\n" +
        "PREFIX ex: <http://example.org/>\n" + 
        "INSERT { GRAPH ex:g1 { ex:a ex:reachable ?y } }\n" + 
        "WHERE { ex:a ex:p1* ?y }";

      Update u = conn.prepareUpdate(sparql);
      u.execute();

      // graph ex:g1 should have 6 results because of all_max_pp_depth(5)
      sparql = 
        "PREFIX ex: <http://example.org/>\n" + 
        "SELECT (COUNT(*) AS ?cnt)\n" + 
        "WHERE { GRAPH ex:g1 { ?s ?p ?o } }";
      
      tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, sparql, "http://example.org/");

      try (TupleQueryResult result = tupleQuery.evaluate()) {
        while (result.hasNext()) {
          BindingSet bindingSet = result.next();
          if (6 != Integer.parseInt(bindingSet.getValue("cnt").stringValue())) System.out.println("cnt mismatch: expecting 6");
        }
      }
    }
    finally {
      if (conn != null && conn.isOpen()) {
        conn.clear();
        conn.close();
      }
      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
      sr.shutDown();
      store.shutDown();
      op.close();
    }
  }
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP OracleHint.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP OracleHint jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP OracleHint jdbc:oracle:thin:@localhost:1521:ORCL scott <password> TestModel scott net1

8.11.13 例13: JDBCバインド値の使用

例8-17に、JDBCバインド値の使用方法を示すJDBCBindVar.javaファイルを示します。

例8-17 JDBCバインド値の使用

import java.io.PrintStream;
import java.sql.SQLException;
import oracle.rdf4j.adapter.OracleDB;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;

public class JDBCBindVar {

  public static void main(String[] args) throws ConnectionSetupException, SQLException {
    PrintStream psOut = System.out;
    
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String networkOwner = (args.length > 5) ? args[4] : null;
    String networkName = (args.length > 5) ? args[5] : null;
    OraclePool op = null;
    OracleSailStore store = null;
    Repository sr = null;
    RepositoryConnection conn = null; 

    try {
      op = new OraclePool(jdbcUrl, user, password);
      store = (networkName == null) ? new OracleSailStore(op, model) : new OracleSailStore(op, model, networkOwner, networkName);   
      sr = new OracleRepository(store);
      conn = sr.getConnection();

      ValueFactory f = conn.getValueFactory();
      
      conn.begin();
      conn.clear();
  
      // create some resources and literals to make statements out of
      // Alice
      IRI alice = f.createIRI("http://example.org/people/alice");
      IRI name = f.createIRI("http://example.org/ontology/name");
      IRI person = f.createIRI("http://example.org/ontology/Person");
      Literal alicesName = f.createLiteral("Alice");   
      conn.add(alice, RDF.TYPE, person);
      conn.add(alice, name, alicesName);
      
      //Bob
      IRI bob = f.createIRI("http://example.org/people/bob");
      Literal bobsName = f.createLiteral("Bob");   
      conn.add(bob, RDF.TYPE, person);
      conn.add(bob, name, bobsName);
      
      conn.commit();
      
      // Query using USE_BIND_VAR=JDBC option for JDBC bind values
      // Simple BIND clause for ?person marks ?person as a bind variable
      String queryString =
        " PREFIX ORACLE_SEM_SM_NS: <http://oracle.com/semtech#USE_BIND_VAR=JDBC>\n" +
        " PREFIX ex: <http://example.org/ontology/>\n" +
        " Select ?name \n" +
        " WHERE \n" +
        " { SELECT * WHERE { \n" +
        "     BIND (\"\" AS ?person) \n" +
        "     ?person ex:name ?name } \n" +
        " }\n" +
        " ORDER BY ?name";      
      TupleQuery tupleQuery = conn.prepareTupleQuery(
          QueryLanguage.SPARQL, queryString);
      
      // set binding for ?person = Alice
      tupleQuery.setBinding("person", alice);
      try (TupleQueryResult result = tupleQuery.evaluate()) {
        if (result.hasNext()) {
          BindingSet bindingSet = result.next();
          psOut.println("solution " + bindingSet.toString());
        }
      }
      
      // re-run with ?person = Bob
      tupleQuery.setBinding("person", bob);
      try (TupleQueryResult result = tupleQuery.evaluate()) {
        if (result.hasNext()) {
          BindingSet bindingSet = result.next();
          psOut.println("solution " + bindingSet.toString());        
        }
      }
    }
    finally {
      if (conn != null && conn.isOpen()) {
        conn.clear();
        conn.close();
      }
      if (op != null) {
        OracleDB oracleDB = op.getOracleDB();
        if (networkName == null)
          OracleUtils.dropSemanticModelAndTables(oracleDB, model);
        else
          OracleUtils.dropSemanticModelAndTables(oracleDB, model, null, null, networkOwner, networkName);
        op.returnOracleDBtoPool(oracleDB);
      }
      sr.shutDown();
      store.shutDown();
      op.close();    
      }
  }
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP JDBCBindVar.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP JDBCBindVar jdbc:oracle:thin:@localhost:1521:ORCL scott <password-for-scott> TestModel

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP JDBCBindVar jdbc:oracle:thin:@localhost:1521:ORCL scott <password-for-scott> TestModel scott net1

Javaコマンドの出力は、次のようになります。

solution [name="Alice";person=http://example.org/people/alice]
solution [name="Bob";person=http://example.org/people/bob]

8.11.14 例14: 単純な推論

例8-18に、SimpleInference.javaファイルを示します。このファイルは、OWL2RLルール・ベースを使用する単一のRDFグラフ(モデル)の推論を示します。

例8-18 単純な推論

import java.io.IOException;
import java.io.PrintStream;
import java.sql.SQLException;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.OracleSailConnection;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.model.vocabulary.RDFS;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import oracle.rdf4j.adapter.Attachment;
import oracle.rdf4j.adapter.OracleSailConnection;
import oracle.rdf4j.adapter.OracleSailRepositoryConnection;

public class SimpleInference {
  public static void main(String[] args) throws ConnectionSetupException, SQLException, IOException {
    PrintStream psOut = System.out;
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String networkOwner = (args.length > 5) ? args[4] : null;
    String networkName = (args.length > 5) ? args[5] : null;

    OraclePool op = null;
    OracleSailStore store = null;
    Repository sr = null;
    RepositoryConnection conn = null;

    try {
      op = new OraclePool(jdbcUrl, user, password);

      // create a single-model, single-rulebase OracleSailStore object
      Attachment attachment = Attachment.createInstance(Attachment.NO_ADDITIONAL_MODELS, new String[] {"OWL2RL"});
      store = new OracleSailStore(op, model, attachment, networkOwner, networkName);
      sr = new OracleRepository(store);

      ValueFactory f = sr.getValueFactory();
      conn = sr.getConnection();

      // create some resources and literals to make statements out of
      IRI alice = f.createIRI("http://example.org/people/alice");
      IRI bob = f.createIRI("http://example.org/people/bob");
      IRI friendOf = f.createIRI("http://example.org/ontology/friendOf");
      IRI Person = f.createIRI("http://example.org/ontology/Person");
      IRI Woman = f.createIRI("http://example.org/ontology/Woman");
      IRI Man = f.createIRI("http://example.org/ontology/Man");

      conn.clear(); // to start from scratch

      // add some statements to the RDF graph (model)
      conn.add(alice, RDF.TYPE, Woman);
      conn.add(bob, RDF.TYPE, Man);
      conn.add(alice, friendOf, bob);
      conn.commit();

      OracleSailConnection osc = (OracleSailConnection)((OracleSailRepositoryConnection)conn).getSailConnection();

      // perform inference (this will not generate any inferred triples)
      osc.performInference();   

      // prepare a query to run against the repository
      String queryString = 
        "PREFIX ex: <http://example.org/ontology/>\n" + 
        "SELECT * WHERE {?x ex:friendOf ?y . ?x a ex:Person . ?y a ex:Person}\n" ;
      TupleQuery tupleQuery = conn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);

      // run the query: no results will be returned because nobody is a Person
      try (TupleQueryResult result = tupleQuery.evaluate()) {
        int resultCount = 0;
        while (result.hasNext()) {
          resultCount++;
          BindingSet bindingSet = result.next();
          psOut.println("value of x: " + bindingSet.getValue("x"));
          psOut.println("value of y: " + bindingSet.getValue("y"));
        }
        psOut.println("number of results: " + resultCount);
      }

      // add class hierarchy
      conn.add(Man, RDFS.SUBCLASSOF, Person);
      conn.add(Woman, RDFS.SUBCLASSOF, Person);
      conn.commit();

      // perform inference again
      osc.performInference();   

      // run the same query again: returns some results because alice and bob now belong to superclass Person
      try (TupleQueryResult result = tupleQuery.evaluate()) {
        while (result.hasNext()) {
          BindingSet bindingSet = result.next();
          psOut.println("value of x: " + bindingSet.getValue("x"));
          psOut.println("value of y: " + bindingSet.getValue("y"));
        }
      }
    }
    finally {
      if (conn != null && conn.isOpen()) {
        conn.clear();
        conn.close();
      }
      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
      sr.shutDown();
      store.shutDown();
      op.close();
    }
  }
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP SimpleInference.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SimpleInference jdbc:oracle:thin:@localhost:1521:ORCL scott <password-for-scott> TestModel

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SimpleInference jdbc:oracle:thin:@localhost:1521:ORCL scott <password-for-scott> TestModel scott net1

Javaコマンドの出力は、次のようになります。

number of results: 0
value of x: http://example.org/people/alice
value of y: http://example.org/people/bob

8.11.15 例15: 単純な仮想モデル

例8-19に、2つのRDFグラフ(モデル)で構成される仮想モデルの作成と使用を示すSimpleVirtualModel.javaファイルを示します。

例8-19 単純な仮想モデル

import java.io.IOException;
import java.io.PrintStream;
import java.sql.SQLException;
import oracle.rdf4j.adapter.OraclePool;
import oracle.rdf4j.adapter.OracleRepository;
import oracle.rdf4j.adapter.OracleSailStore;
import oracle.rdf4j.adapter.exception.ConnectionSetupException;
import oracle.rdf4j.adapter.utils.OracleUtils;
import org.eclipse.rdf4j.model.IRI;
import org.eclipse.rdf4j.model.ValueFactory;
import org.eclipse.rdf4j.model.vocabulary.RDF;
import org.eclipse.rdf4j.model.vocabulary.RDFS;
import org.eclipse.rdf4j.query.BindingSet;
import org.eclipse.rdf4j.query.QueryLanguage;
import org.eclipse.rdf4j.query.TupleQuery;
import org.eclipse.rdf4j.query.TupleQueryResult;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import oracle.rdf4j.adapter.Attachment;

public class SimpleVirtualModel {
  public static void main(String[] args) throws ConnectionSetupException, SQLException, IOException {
    PrintStream psOut = System.out;
    String jdbcUrl = args[0];
    String user = args[1];
    String password = args[2];
    String model = args[3];
    String model2 = args[4];
    String virtualModelName = args[5];
    String networkOwner = (args.length > 7) ? args[6] : null;
    String networkName = (args.length > 7) ? args[7] : null;

    OraclePool op = null;

    OracleSailStore store = null;
    Repository sr = null;
    RepositoryConnection conn = null;

    OracleSailStore store2 = null;
    Repository sr2 = null;
    RepositoryConnection conn2 = null;

    OracleSailStore vmStore = null;
    Repository vmSr = null;
    RepositoryConnection vmConn = null;

    try {
      op = new OraclePool(jdbcUrl, user, password);

      // create two models and then a virtual model that uses those two models

      // create the first model
      store = new OracleSailStore(op, model, networkOwner, networkName);
      sr = new OracleRepository(store);
      ValueFactory f = sr.getValueFactory();
      conn = sr.getConnection();
	  
      // create the second model (this one will be used as an additional model in the attachment object)
      store2 = new OracleSailStore(op, model2, networkOwner, networkName);
      sr2 = new OracleRepository(store2);
      conn2 = sr2.getConnection();

      // create a two-model virtual model OracleSailStore object
      Attachment attachment = Attachment.createInstance(model2);
      vmStore = new OracleSailStore(op, model, /*ignored*/true, /*useVirtualModel*/true, virtualModelName, attachment, networkOwner, networkName);
      vmSr = new OracleRepository(vmStore);
      vmConn = vmSr.getConnection();

      // create some resources and literals to make statements out of
      IRI alice = f.createIRI("http://example.org/people/alice");
      IRI bob = f.createIRI("http://example.org/people/bob");
      IRI friendOf = f.createIRI("http://example.org/ontology/friendOf");
      IRI Person = f.createIRI("http://example.org/ontology/Person");
      IRI Woman = f.createIRI("http://example.org/ontology/Woman");
      IRI Man = f.createIRI("http://example.org/ontology/Man");

      // clear any data (in case any of the two non-virtual models were already present)
      conn.clear();
      conn2.clear();

      // add some statements to the first RDF model
      conn.add(alice, RDF.TYPE, Woman);
      conn.add(bob, RDF.TYPE, Man);
      conn.add(alice, friendOf, bob);
      conn.commit();

      // prepare a query to run against the virtual model repository
      String queryString = 
        "PREFIX ex: <http://example.org/ontology/>\n" + 
        "SELECT * WHERE {" + 
        "?x ex:friendOf ?y . ?x rdf:type/rdfs:subClassOf* ?xC . ?y rdf:type/rdfs:subClassOf* ?yC" + 
        "} ORDER BY ?x ?xC ?y ?yC\n" ;
        ;
      TupleQuery tupleQuery = vmConn.prepareTupleQuery(QueryLanguage.SPARQL, queryString);

      // run the query: no results will be returned because nobody is a Person
      try (TupleQueryResult result = tupleQuery.evaluate()) {
        int resultCount = 0;
        while (result.hasNext()) {
          resultCount++;
          BindingSet bindingSet = result.next();
          psOut.println("values of x | xC | y | yC: " + 
        		  bindingSet.getValue("x") + " | " + bindingSet.getValue("xC") + " | " + 
        		  bindingSet.getValue("y") + " | " + bindingSet.getValue("yC"));
        }
        psOut.println("number of results: " + resultCount);
      }

      // add class hierarchy info to the second model
      conn2.add(Man, RDFS.SUBCLASSOF, Person);
      conn2.add(Woman, RDFS.SUBCLASSOF, Person);
      conn2.commit();

      // run the same query again: returns some additional info in the results
      try (TupleQueryResult result = tupleQuery.evaluate()) {
    	int resultCount = 0;
        while (result.hasNext()) {
          resultCount++;
          BindingSet bindingSet = result.next();
          psOut.println("values of x | xC | y | yC: " + 
        		  bindingSet.getValue("x") + " | " + bindingSet.getValue("xC") + " | " + 
        		  bindingSet.getValue("y") + " | " + bindingSet.getValue("yC"));
        }
        psOut.println("number of results: " + resultCount);
      }
    }
    finally {
      if (conn != null && conn.isOpen()) {
        conn.clear();
        conn.close();
      }
      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model, null, null, networkOwner, networkName);
      sr.shutDown();
      store.shutDown();

      if (conn2 != null && conn2.isOpen()) {
          conn2.clear();
          conn2.close();
      }
      OracleUtils.dropSemanticModelAndTables(op.getOracleDB(), model2, null, null, networkOwner, networkName);
      sr2.shutDown();
      store2.shutDown();
      
      vmSr.shutDown();
      vmStore.shutDown();

      op.close();
    }
  }
}

この例をコンパイルするには、次のコマンドを実行します。

javac -classpath $CP SimpleVirtualModel.java

既存のMDSYSネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SimpleVirtualModel jdbc:oracle:thin:@localhost:1521:ORCL scott <password-for-scott> TestModel TestOntology TestVM

所有者がSCOTTで名前がNET1である既存のスキーマプライベート・ネットワークに対してこの例を実行するには、次のコマンドを実行します。

java -classpath $CP SimpleVirtualModel jdbc:oracle:thin:@localhost:1521:ORCL scott <password-for-scott> TestModel TestOntology TestVM scott net1

Javaコマンドの出力は、次のようになります。

values of x | xC | y | yC: http://example.org/people/alice | http://example.org/ontology/Woman | http://example.org/people/bob | http://example.org/ontology/Man
number of results: 1
values of x | xC | y | yC: http://example.org/people/alice | http://example.org/ontology/Person | http://example.org/people/bob | http://example.org/ontology/Man
values of x | xC | y | yC: http://example.org/people/alice | http://example.org/ontology/Person | http://example.org/people/bob | http://example.org/ontology/Person
values of x | xC | y | yC: http://example.org/people/alice | http://example.org/ontology/Woman | http://example.org/people/bob | http://example.org/ontology/Man
values of x | xC | y | yC: http://example.org/people/alice | http://example.org/ontology/Woman | http://example.org/people/bob | http://example.org/ontology/Person
number of results: 4