1.15 RDFグラフでのSPARQL更新操作のサポート

Oracle Databaseリリース12.2では、RDFグラフに対するSPARQL更新操作が可能になりました。

ノート:

RDFグラフでのSPARQL更新操作は、Oracle Autonomous Databaseサーバーレス・デプロイメントでOracle JVMが有効になっている場合にのみサポートされます。Oracle JVMを有効にするには、Oracle Autonomous Databaseサーバーレスの使用Oracle Javaの使用で詳細を参照してください。

W3Cは、RDFグラフに対する更新言語であるSPARQL 1.1更新(https://www.w3.org/TR/2013/REC-sparql11-update-20130321/)を定めています。SPARQL 1.1更新は、SEM_APIS.UPDATE_RDF_GRAPHプロシージャを通じて、Oracle Databaseセマンティク・テクノロジでサポートされています。

RDFグラフでSPARQL更新操作を実行する前に、次の前提条件が適用されます。

  • SEM_APIS.CREATE_SPARQL_UPDATE_TABLESプロシージャは、SEM_APIS.UPDATE_RDF_GRAPHプロシージャを使用する各ユーザーのスキーマで実行する必要があります。
  • RDFグラフを更新するには、ネットワークおよびターゲットRDFグラフに対するSELECTINSERTDELETEUPDATEおよびQUERY権限が必要です。これらの権限は、ネットワーク所有者に自動的に存在することに注意してください。他のユーザーがRDFグラフを更新できるようにするには、「スキーマ-プライベートRDFネットワークの共有」を参照してください。
  • LOAD操作を実行するには、ユーザーにCREATE ANY DIRECTORY権限およびDROP ANY DIRECTORY権限があるか、optionsパラメータで名前が指定されている既存のディレクトリ・オブジェクトに対するREAD権限が付与されている必要があります。

次の例は、RDFグラフに対する更新操作を示しています。この例では、RDFUSERというデータベース・ユーザーが所有する、NET1という名前のスキーマプライベートRDFネットワークを想定しています。

例1-117 INSERT DATA操作

これは、デフォルトのelectronicsグラフに複数のトリプルを挿入するINSERT DATA操作の例を示しています。

-- Dataset before operation:
#Empty default graph
-- Update operation:
BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/> 
    INSERT DATA {
       :camera1 :name "Camera 1" .
       :camera1 :price 120 .
       :camera1 :cameraType :Camera .
       :camera2 :name "Camera 2" .
       :camera2 :price 150 .
       :camera2 :cameraType :Camera .
      } ', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

-- Dataset after operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera1 :name "Camera 1";
         :price 120;
         :cameraType :Camera .
:camera2 :name "Camera 2"; 
         :price 150;
         :cameraType :Camera .

例1-118 DELETE DATA操作

これは、デフォルトのelectronics RDFグラフからトリプルを1つ削除するDELETE DATA操作の例です。

-- Dataset before operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera1 :name "Camera 1";
         :price 120;
         :cameraType :Camera .
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
-- Update operation:
BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/> 
    DELETE DATA { :camera1 :price 120 . } ', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

-- Dataset after operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera1 :name "Camera 1";
         :cameraType :Camera .
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .

例1-119 デフォルト・グラフに対するDELETE操作およびINSERT操作

この例ではDELETE操作およびINSERT操作を行っています。:camera1:cameraTypeが、:digitalCameraに更新されています。

-- Dataset before operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera1 :name "Camera 1";
         :cameraType :Camera .
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .

-- Update operation:
BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/> 
    DELETE { :camera1 :cameraType ?type . } 
    INSERT { :camera1 :cameraType :digitalCamera . } 
    WHERE  { :camera1 :cameraType ?type . }', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

-- Dataset after operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera1 :name "Camera 1";
         :cameraType :digitalCamera .
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .

例1-120 デフォルト・グラフおよび名前付きグラフに対するDELETE操作およびINSERT操作

グラフは、DELETEおよびINSERTテンプレートで指定することも、WHERE句の中で指定することもできます。この例では、デジタル・カメラに対応するすべてのトリプルを、デフォルト・グラフから:digitalCamerasというグラフへ移動します。

-- Dataset before operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera1 :name "Camera 1";
         :cameraType :digitalCamera .
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Empty graph :digitalCameras

-- Update operation:
BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/> 
    DELETE { ?s ?p ?o } 
    INSERT { graph :digitalCameras { ?s ?p ?o } }
    WHERE  { ?s :cameraType :digitalCamera .
             ?s ?p ?o }', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

-- Dataset after operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Graph :digitalCameras
GRAPH :digitalCameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}

例1-121 INSERT WHERE操作とDELETE WHERE操作

DELETE操作またはINSERT操作から、DELETEテンプレートまたはINSERTテンプレートのいずれかを削除できます。さらに、DELETEに続くテンプレートは、WHEREパターンをDELETEテンプレートとして使用するためのショートカットとして省略できます。この例では、INSERT WHERE文を使用して、:digitalCamerasグラフのコンテンツを:camerasグラフに挿入しています。また、構文ショートカットを用いたDELETE WHERE文を使用して、:camerasグラフからすべてのコンテンツを削除しています。


-- INSERT WHERE
-- Dataset before operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Graph :digitalCameras
GRAPH :digitalCameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}
#Empty graph :cameras

-- Update operation:
BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/> 
    INSERT { graph :cameras { ?s ?p ?o } }
    WHERE  { graph :digitalCameras { ?s ?p ?o } }', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

-- Dataset after operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Graph :digitalCameras
GRAPH :digitalCameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}
#Graph :cameras
GRAPH :cameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}

-- DELETE WHERE
-- Dataset before operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Graph :digitalCameras
GRAPH :digitalCameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}
#Graph :cameras
GRAPH :cameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}

-- Update operation:
BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/> 
    DELETE WHERE { graph :cameras { ?s ?p ?o } }', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

-- Dataset after operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Graph :digitalCameras
GRAPH :digitalCameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}
#Empty graph :cameras

例1-122 COPY操作

この例ではCOPY操作を行っています。デフォルト・グラフから、すべてのデータが:camerasグラフに挿入されます。:camerasに既存データがある場合、そのデータは挿入前に削除されます。

-- Dataset before operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Graph :digitalCameras
GRAPH :digitalCameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}
#Graph :cameras
GRAPH :cameras {
  :camera3 :name "Camera 3" .
}

-- Update operation:
BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/>
    COPY DEFAULT TO GRAPH :cameras', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

-- Dataset after operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Graph :digitalCameras
GRAPH :digitalCameras {
  :camera1 :name "Camera 1"; 
           :cameraType :digitalCamera .
}
#Graph :cameras
GRAPH :cameras {
  :camera2 :name "Camera 2";
           :price 150;
           :cameraType :Camera .
}

例1-123 ADD操作

この例では、:digitalCamerasグラフのデータすべてを、:camerasグラフへ追加しています。

-- Dataset before operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Graph :digitalCameras
GRAPH :digitalCameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}
#Graph :cameras
GRAPH :cameras {
  :camera2 :name "Camera 2";
           :price 150;
           :cameraType :Camera .
}

-- Update operation:
BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/>
    ADD GRAPH :digitalCameras TO GRAPH :cameras', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

-- Dataset after operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Graph :digitalCameras
GRAPH :digitalCameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}
#Graph :cameras
GRAPH :cameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
  :camera2 :name "Camera 2";
           :price 150;
           :cameraType :Camera .
}

例1-124 MOVE操作

この例では、:digitalCamerasグラフのデータすべてを、:digCamグラフへ移動しています。

-- Dataset before operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Graph :digitalCameras
GRAPH :digitalCameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}
#Graph :cameras
GRAPH :cameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
  :camera2 :name "Camera 2";
           :price 150;
           :cameraType :Camera .
}
#Graph :digCam
GRAPH :digCam {
  :camera4 :cameraType :digCamera .
}

-- Update operation:
BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/>
    MOVE GRAPH :digitalCameras TO GRAPH :digCam', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

-- Dataset after operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2" .
         :camera2 :price 150 .
         :camera2 :cameraType :Camera .
#Empty graph :digitalCameras
#Graph :cameras
GRAPH :cameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
  :camera2 :name "Camera 2";
           :price 150;
           :cameraType :Camera .
}
#Graph :digCam
GRAPH :digCam {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}

例1-125 CLEAR操作

この例では、CLEAR操作を実行して、デフォルト・グラフのトリプルすべてを削除しています。RDFグラフには空のグラフは保存されないため、CLEAR操作はいつも成功します。また、この操作はDROP操作と等価です。(同じ理由で、CREATE操作はRDFグラフに何の影響も与えません。)

-- Dataset before operation:
@prefix : <http://www.example.org/electronics/> 
#Default graph
:camera2 :name "Camera 2";
         :price 150;
         :cameraType :Camera .
#Empty graph :digitalCameras
#Graph :cameras
GRAPH :cameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera 
  :camera2 :name "Camera 2";
           :price 150;
           :cameraType :Camera .
}
#Graph :digCam
GRAPH :digCam {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}

-- Update operation:
BEGIN
  sem_apis.update_rdf_graph('electronics',
   'CLEAR DEFAULT ', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

-- Dataset after operation:
@prefix : <http://www.example.org/electronics/> 
#Empty Default graph
#Empty graph :digitalCameras
#Graph :cameras
GRAPH :cameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
  :camera2 :name "Camera 2";
           :price 150;
           :cameraType :Camera .
}
#Graph :digCam
GRAPH :digCam {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}

例1-126 LOAD操作

N-Triple、N-Quad、TurtleおよびTrigのファイルを、ローカル・ファイル・システムから、LOAD操作によってロードできます。より単純なN-TripleおよびN-Quad形式の方が、TurtleおよびTrigより速くロードできることに注意してください。オプションのINTO句を使用して、特定の名前付きグラフにファイルをロードできます。LOAD操作を実行するには、ユーザーに(1) CREATE ANY DIRECTORY権限およびDROP ANY DIRECTORY権限があるか、(2) UPDATE_RDF_GRAPHのoptionsパラメータで、既存のディレクトリ・オブジェクトの名前を指定する必要があります。この例では、N-Quadファイル/home/oracle/example.nqをRDFグラフにロードしています。

なお、N-QuadまたはTrigファイルでINTO句を使用すると、そのファイルにある名前付きグラフの情報は、すべて上書きされます。この例では、INTO GRAPH :camerasにより、最初のクワッドに対して:myGraphが上書きされるため、代わりにこのクワッドのトリプル・コンポーネントである主語、プロパティ、目的語が、:camerasグラフに挿入されます。

-- Datafile: /home/oracle/example.nq
<http://www.example.org/electronics/camera3> <http://www.example.org/electronics/name> "Camera 3" <http://www.example.org/electronics/myGraph> .
<http://www.example.org/electronics/camera3> <http://www.example.org/electronics/price> "125"^^<http://www.w3.org/2001/XMLSchema#decimal> .

-- Dataset before operation:
#Graph :cameras
GRAPH :cameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
  :camera2 :name "Camera 2";
           :price 150;
           :cameraType :Camera .
}
#Graph :digCam
GRAPH :digCam {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}

-- Update operation:
CREATE OR REPLACE DIRECTORY MY_DIR AS '/home/oracle';

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/>
    LOAD <file:///example.nq> INTO GRAPH :cameras',
   options=>'LOAD_DIR={MY_DIR}', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
END;
/

-- Dataset after operation:
@prefix : <http://www.example.org/electronics/> 
#Graph :cameras
GRAPH :cameras {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
  :camera2 :name "Camera 2";
           :price 150;
           :cameraType :Camera .
  :camera3 :name "Camera 3";
           :price 125.
}
#Graph :digCam
GRAPH :digCam {
  :camera1 :name "Camera 1";
           :cameraType :digitalCamera .
}

1回のLOAD操作で、同じディレクトリのファイルを複数、並行してロードできます。追加のN-TripleまたはN-Quadのファイルをロードするために、LOAD_OPTIONSヒントを使用できます。ロードの並列度は、options文字列のPARALLEL(n)で指定できます。次の例では、ファイル/home/oracle/example1.nq/home/oracle/example2.nqおよび/home/oracle/example3.nqをRDFグラフにロードする方法を示します。この例では、並列度3が使用されています。

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/>
    LOAD <file:///example1.nq>',
   options=> ' PARALLEL(3) LOAD_OPTIONS={ example2.nq example3.nq } LOAD_DIR={MY_DIR} ', 
   network_owner=>'RDFUSER', network_name=>'NET1' );
END;
/

関連項目:

1.15.1 SPARQL更新操作の調整

場合によっては、SPARQL更新操作を調整しなければならないことがあります。SPARQL更新操作では、1つまたは複数のSPARQL問合せがUPDATE文のWHERE句に基づいて実行されるため、SPARQL更新操作には、「問合せパフォーマンスのベスト・プラクティス」もあてはまります。また、次の点にも留意する必要があります。

  • 削除操作のパフォーマンスを向上させるには、アプリケーション表に対する適切な索引(SEM_APIS.UPDATE_RDF_GRAPHapply_modelパラメータに関連付けられた索引)が必要です。TRIPLEという名前のSDO_RDF_TRIPLE_S列を持つAPP_TABという名前のアプリケーション表の場合、次のような索引を使用することをお薦めします(これは、「RDF Graph Support for Apache Jena」で使用されている索引と同じです)。

    -- Application table index for 
    --  (graph_id, subject_id, predicate_id, canonical_object_id)
    CREATE INDEX app_tab_idx ON app_tab app (
      BITAND(app.triple.rdf_m_id,79228162514264337589248983040)/4294967296,
      app.triple.rdf_s_id,
      app.triple.rdf_p_id,
      app.triple.rdf_c_id)
    COMPRESS;
    
  • パフォーマンスに関係するSEM_MATCHオプションを、SEM_APIS.UPDATE_RDF_GRAPHmatch_optionsパラメータに渡すことができます。また、そのプロシージャのoptionsパラメータで、PARALLELやDYNAMIC_SAMPLINGなどのパフォーマンスに関係するオプションを指定できます。次の例では、更新に対し、オプション・パラメータを使用して並列度を4に、またオプティマイザの動的サンプリング・レベルを6に設定しています。また、この例では、RDFグラフ・コレクションVM1に対する照合で、ALLOW_DUP=Tが照合オプションとして使用されています。

    BEGIN
      sem_apis.update_rdf_graph(
       'electronics',
       'PREFIX : <http://www.example.org/electronics/> 
        INSERT { graph :digitalCameras { ?s ?p ?o } }
        WHERE  { ?s :cameraType :digitalCamera .
                 ?s ?p ?o }',
       match_models=>sem_models('VM1'),
       match_models=>sem_models('VM1'),
       match_options=>' ALLOW_DUP=T ',
       options=>' PARALLEL(4) DYNAMIC_SAMPLING(6) ', 
       network_owner=>'RDFUSER', network_name=>'NET1');
    END;
    /
    
  • インライン問合せオプティマイザ・ヒントをWHERE句で指定できます。次の例では、先の例を拡張して、HINT0ヒントをWHERE句で、FINAL_VALUE_NLヒントをmatch_optionsパラメータで使用しています。

    BEGIN
      sem_apis.update_rdf_graph(
       'electronics',
       'PREFIX : <http://www.example.org/electronics/> 
        INSERT { graph :digitalCameras { ?s ?p ?o } }
        WHERE  { # HINT0={ LEADING(t0 t1) USE_NL(t0 t1)
                 ?s :cameraType :digitalCamera .
                 ?s ?p ?o }',
       match_models=>sem_models('VM1'),
       match_options=>' ALLOW_DUP=T FINAL_VALUE_NL ',
       options=>' PARALLEL(4) DYNAMIC_SAMPLING(6) ', 
       network_owner=>'RDFUSER', network_name=>'NET1');
    END;
    /
    

1.15.2 SPARQL更新操作でのトランザクション管理

SEM_APIS.UPDATE_RDF_GRAPH操作で使用されるトランザクションの数、およびそれらが自動的にコミットされるのかを、ある程度制御することができます。

デフォルトでは、SEM_APIS.UPDATE_RDF_GRAPHプロシージャは、正常終了後にコミットされたか、エラーが発生した場合にロール・バックされた単一のトランザクションで実行されます。たとえば、次に示す呼出しでは、3つの更新操作(セミコロンで分離)が、1つのトランザクションで実行されています。

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX elec: <http://www.example.org/electronics/>
    PREFIX ecom: <http://www.example.org/ecommerce/> 
    # insert camera data
    INSERT DATA {
      elec:camera1 elec:name "Camera 1" .
      elec:camera1 elec:price 120 .
      elec:camera1 elec:cameraType elec:DigitalCamera .
      elec:camera2 elec:name "Camera 2" .
      elec:camera2 elec:price 150 .
      elec:camera2 elec:cameraType elec:DigitalCamera . }; 
    # insert ecom:price triples
    INSERT { ?c  ecom:price ?p }
    WHERE  { ?c  elec:price ?p };
    # delete elec:price triples
    DELETE WHERE { ?c elec:price ?p }', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

PL/SQL procedure successfully completed.

一方、次の例では、3つの個別のSEM_APIS.UPDATE_RDF_GRAPHコールを使用して、3つの異なるトランザクションで3つの同じ更新操作を実行しています。

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX elec: <http://www.example.org/electronics/>
    PREFIX ecom: <http://www.example.org/ecommerce/> 
    # insert camera data
    INSERT DATA {
      elec:camera1 elec:name "Camera 1" .
      elec:camera1 elec:price 120 .
      elec:camera1 elec:cameraType elec:DigitalCamera .
      elec:camera2 elec:name "Camera 2" .
      elec:camera2 elec:price 150 .
      elec:camera2 elec:cameraType elec:DigitalCamera . }', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;

PL/SQL procedure successfully completed.

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX elec: <http://www.example.org/electronics/>
    PREFIX ecom: <http://www.example.org/ecommerce/> 
    # insert ecom:price triples
    INSERT { ?c  ecom:price ?p }
    WHERE  { ?c  elec:price ?p }', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

PL/SQL procedure successfully completed.

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX elec: <http://www.example.org/electronics/>
    PREFIX ecom: <http://www.example.org/ecommerce/> 
    # insert elec:price triples
    DELETE WHERE { ?c elec:price ?p }', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

PL/SQL procedure successfully completed.

AUTOCOMMIT=Fオプションを使用して、SEM_APIS.UPDATE_RDF_GRAPH呼出しごとに別々のトランザクションが行われるのを防ぐことができます。このオプションでは、トランザクションの管理は、呼出し側の責任です。更新操作を、先の例で3つの分離したトランザクションではなく、単一のトランザクションとして実行する方法を、次の例に示します。

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX elec: <http://www.example.org/electronics/>
    PREFIX ecom: <http://www.example.org/ecommerce/> 
    # insert camera data
    INSERT DATA {
      elec:camera1 elec:name "Camera 1" .
      elec:camera1 elec:price 120 .
      elec:camera1 elec:cameraType elec:DigitalCamera .
      elec:camera2 elec:name "Camera 2" .
      elec:camera2 elec:price 150 .
      elec:camera2 elec:cameraType elec:DigitalCamera . }',
   options=>' AUTOCOMMIT=F ',
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

PL/SQL procedure successfully completed.

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX elec: <http://www.example.org/electronics/>
    PREFIX ecom: <http://www.example.org/ecommerce/> 
    # insert ecom:price triples
    INSERT { ?c  ecom:price ?p }
    WHERE  { ?c  elec:price ?p }',
   options=>' AUTOCOMMIT=F ',
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

PL/SQL procedure successfully completed.

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX elec: <http://www.example.org/electronics/>
    PREFIX ecom: <http://www.example.org/ecommerce/> 
    # insert elec:price triples
    DELETE WHERE { ?c elec:price ?p }',
   options=>' AUTOCOMMIT=F ',
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

PL/SQL procedure successfully completed.

COMMIT;

Commit complete.

ただし、AUTOCOMMIT=Fオプションでは、次のことはできません。

  • バルク操作(FORCE_BULK=TDEL_AS_INS=T)

  • LOAD操作

  • 中間データの実体化(STREAMING=F)

1.15.2.1 トランザクション分離レベル

Oracle Databaseは3つのトランザクション分離レベル(読取りコミット、シリアライズ可能、読取り専用)に対応しています。

読取りコミット分離レベルがデフォルトです。この分離レベルを使用したトランザクションでは、問合せ(そのトランザクションではなく)の開始前にコミットされたデータ、またはトランザクション自体により行われた変更のみが問合せの対象になります。この分離レベルを用いることで、同時実効性を最も高くすることができます。

シリアライズ可能分離レベルを使用したトランザクションでは、問合せの開始前にコミットされたデータ、またはトランザクション自体により行われた変更のみが問合せの対象になります。

読取り専用分離レベルは、シリアライズ可能分離レベルと動作が似ていますが、トランザクションによってデータを修正することはできません。

SEM_APIS.UPDATE_RDF_GRAPHは、読取りコミットおよびシリアライズ可能なトランザクション分離レベルをサポートし、読取りコミットがデフォルトです。SPARQL UPDATE操作は、次の基本的ステップに従って処理されます。

  1. 削除するトリプルのセットを取得する問合せが実行されます。

  2. 挿入するトリプルのセットを取得する問合せが実行されます。

  3. ステップ1で取得されたトリプルが削除されます。

  4. ステップ2で取得されたトリプルが挿入されます。

デフォルトの読取りコミット分離レベルでは、同時実行されるトランザクションにより基礎となるトリプル・データに変更が加えられることがあるため、各ステップで異なるデータが対象となる可能性があります。さらに、同じSEM_APIS.UPDATE_RDF_GRAPHコール内の後続の更新操作では、同時トランザクションによって加えられる変更も表示されます。なお、中間データの実体化を使用すると(STREAMING=F)、ステップ1とステップ2は1つのステップとして実行されるため、このオプションでは、ステップ1とステップ2の間で、基礎となるトリプル・データに変更を加えることはできません。中間データの実体化に関する詳細は、「バルク操作のサポート」を参照してください。

シリアライズ可能分離レベルは、オプションSERIALIZABLE=Tを指定することで使用できます。この場合、各ステップでは、RDFグラフの更新操作が始まる前にコミットされたデータのみが表示され、1つのSEM_APIS.UPDATE_RDF_GRAPH呼出しで複数の更新操作が実行されても、他のトランザクションでの同時更新操作によって加えられた変更は表示されません。ただし、SEM_APIS.UPDATE_RDF_GRAPHの実行によって、並行するトランザクションで変更されたトリプルを更新しようとすると、ORA-08177エラーが発生します。SERIALIZABLE=Tを使用する場合、ORA-08177エラーがアプリケーションにより検知され、処理される必要があります(たとえば、最初の試行でシリアル化できなかった場合の更新コマンド再試行)。

次の操作を、SERIALIZABLE=Tオプションとともに使用することはできません。

  • バルク操作(FORCE_BULK=TDEL_AS_INS=T)

  • LOAD操作

  • 中間データの実体化(STREAMING=F)

1.15.3 バルク操作のサポート

SEM_APIS.UPDATE_RDF_GRAPHは、大量の更新を効率的に実行するバルク操作に対応しています。次のオプションが利用可能です。ただし、そうしたバルク操作を実行する場合には、シリアル化可能分離(SERIALIZABLE=T)および自動コミットの抑制(AUTOCOMMMIT=F)は使用できません。

1.15.3.1 中間データの実体化(STREAMING=F)(STREAMING=F)

デフォルトでは、SEM_APIS.UPDATE_RDF_GRAPHは、基本的なDELETE INSERT SPARQL更新操作に対して2つの問合せ(削除するトリプルの検索問合せと、挿入するトリプルの検索問合せ)を実行します。評価に時間のかかるWHERE句を含む更新操作を行う場合、2つの問合せを実行することは最も良いパフォーマンスにつながらないことがあります。そうした場合、WHERE句に対して1回の問合せを実行し、結果を実体化した後、実体化した結果を用いて、削除するトリプルおよび挿入するトリプルの構築を行う方が、より良いパフォーマンスを得られることがあります。この方法ではDDL操作によるオーバーヘッドが生じますが、複雑な更新文の場合には、全体としてパフォーマンスの向上が期待できます。

次に示す更新の例では、このオプション(STREAMING=F)が使用されています。なお、STREAMING=Fは、シリアル化可能分離(SERIALIZABLE=T)あるいは自動コミット抑制(AUTOCOMMIT=F)と同時には使用できません。

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/> 
    DELETE { ?s ?p ?o } 
    INSERT { graph :digitalCameras { ?s ?p ?o } }
    WHERE  { ?s :cameraType :digitalCamera .
             ?s ?p ?o }',
  options=>' STREAMING=F ', 
  network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

1.15.3.2 SEM_APIS.BULK_LOAD_RDF_GRAPHの使用

大量のトリプル(万単位のような)を挿入する更新の場合、アプリケーション表に対する増分DMLというデフォルトの方法では、十分なパフォーマンスを得られないことがあります。その場合、FORCE_BULK=Tオプションを指定して、増分DMLではなくSEM_APIS.BULK_LOAD_RDF_GRAPHを使用できます。

ただし、すべての更新操作でこの最適化を使用できるわけではありません。FORCE_BULK=Tオプションは、単一のADD操作または単一のINSERT WHERE操作を含むSEM_APIS.UPDATE_RDF_GRAPH呼出しに対してのみ使用できます。SEM_APIS.BULK_LOAD_RDF_GRAPHを使用すると、一連のコミットおよび自律的なトランザクションが強制されるため、AUTOCOMMIT=FおよびSERIALIZABLE=Tオプションは、FORCE_BULK=Tでは許可されません。さらに、バルク・ロードはCLOB_UPDATE_SUPPORT=Tと同時に使用できません。

SEM_APIS.BULK_LOAD_RDF_GRAPHは、そのflagsパラメータを使用して、様々なカスタマイズを可能にします。SEM_APIS.UPDATE_RDF_GRAPHは、BULK_OPTIONS={ OPTIONS_STRING }フラグをサポートしているため、OPTIONS_STRINGSEM_APIS.BULK_LOAD_RDF_GRAPHflags入力に渡して、バルク・ロードのオプションをカスタマイズできます。次の例で、FORCE_BULK=TオプションおよびBULK_OPTIONSフラグを使用したSEM_APIS.UPDATE_RDF_GRAPHの呼出しを示します。

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX elec: <http://www.example.org/electronics/>
    PREFIX ecom: <http://www.example.org/ecommerce/> 
    INSERT { ?c  ecom:price ?p }
    WHERE  { ?c  elec:price ?p }',
   options=>' FORCE_BULK=T BULK_OPTIONS={  parallel=4 parallel_create_index }', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

1.15.3.3 挿入としての削除の使用(DEL_AS_INS=T)

大量のトリプル(何万もの)を削除する更新の場合、アプリケーション表に対する増分DMLというデフォルトの方法では、十分なパフォーマンスを得られないことがあります。その場合、DEL_AS_INS=Tを指定できます。このオプションを使用すると、大規模な削除の操作が、INSERT、TRUNCATE、そしてEXCHANGE PARTITIONの操作として実行されます。

DEL_AS_INS=Tを使用すると一連のコミットおよび自律的なトランザクションが発生するため、このオプションは、SERIALIZABLE=Tまたは AUTOCOMMIT=Fと同時に使用できません。さらに、このオプションは、単一のDELETE WHERE操作、単一のDROP操作、または単一のCLEAR操作を含むSEM_APIS.UPDATE_RDF_GRAPH呼出しと組合せた場合にのみ使用することができます。

挿入としての削除では、中間操作でSEM_APIS.MERGE_RDF_GRAPHSが内部的に使用されています。OPTIONS_STRINGの文字列を、MM_OPTIONS={ OPTIONS_STRING }フラグから指定して、マージのオプションをカスタマイズすることができます。次の例で、DEL_AS_INS=TオプションおよびMM_OPTIONSフラグを使用したSEM_APIS.UPDATE_RDF_GRAPHの呼出しを示します。

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'CLEAR NAMED',
   options=>' DEL_AS_INS=T MM_OPTIONS={  dop=4 } ', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

1.15.4 セッション・レベルでのUPDATE_RDF_GRAPHオプションの設定

SEM_APIS.UPDATE_RDF_GRAPHプロシージャの動作に影響する設定の中には、特殊なMDSYS.SDO_SEM_UPDATE_CTX.SET_PARAMプロシージャを使用して、セッション・レベルで変更できるものがあります。autocommitstreamingstrict_bnodeおよびclob_supportの各オプションは、セッション・レベルでtrueまたはfalseに設定できます。

MDSYS.SDO_SEM_UPDATE_CTXには、SEM_APIS.UPDATE_RDF_GRAPHパラメータをセッション・レベルで取得し、設定する次のサブプログラムが含まれています。

SQL> describe mdsys.sdo_sem_update_ctx
FUNCTION GET_PARAM RETURNS VARCHAR2
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 NAME                           VARCHAR2                IN
PROCEDURE SET_PARAM
 Argument Name                  Type                    In/Out Default?
 ------------------------------ ----------------------- ------ --------
 NAME                           VARCHAR2                IN
 VALUE                          VARCHAR2                IN

次の例では、AUTOCOMMIT=F設定を使用するSEM_APIS.UPDATE_RDF_GRAPHプロシージャに対するすべての呼出しを、セッションの終わりまで、または別のautocommit値を指定する次のSEM_APIS.UPDATE_RDF_GRAPH呼出しまで発生させます。

begin
  mdsys.sdo_sem_update_ctx.set_param('autocommit','false');
end;
/

1.15.5 ロード操作: SPARQL更新で特に留意する点

ロードするファイルの形式は、ロード・プロセス中に使用できる並列度に影響します。ロード操作には、次の2つのフェーズがあります。

  1. ファイル・システムからステージング表へのロード

  2. ステージング表からRDFグラフにロードするためのSEM_APIS.BULK_LOAD_RDF_GRAPHのコール

フェーズ2では、サポートされているすべてのデータ形式がパラレル実行を使用できますが、フェーズ1でパラレル実行を使用できるのはN-TripleおよびN-Quad形式のみです。さらに、ステージング表にデータが完全にロードされた後で、フェーズ2でのロード操作が中断された場合、optionsパラメータでRESUME_LOAD=Tキーワードを指定しておくことで、ロードを再開できます。

NETWORK_MAX_STRING_SIZEのバイト数より長いオブジェクト値を含むRDFドキュメントのロード操作では、さらに操作が必要な場合があります。TurtleおよびTrigドキュメントのロード操作では、オブジェクト値のサイズにかかわらず、すべてのトリプルおよびクワッドが自動的にロードされます。一方、N-TripleおよびN-Quadドキュメントのロード操作では、長さがNETWORK_MAX_STRING_SIZEのバイト数未満のオブジェクト値があるトリプルおよびクワッドのみがロードされます。N-TripleおよびN-Quadデータの場合は、オブジェクト値がNETWORK_MAX_STRING_SIZEのバイト数より大きいトリプルおよびクワッドもロードするために、LOAD_CLOB_ONLY=Tオプションを指定して2つ目のロード操作を発行する必要があります。

UNIX名前付きパイプからのロードは、N-TripleおよびN-Quad形式についてのみサポートされます。TurtleおよびTrigファイルは、圧縮されていない物理ファイルである必要があります。

Unicode文字の処理は、ロードするRDFファイルの形式によって異なります。N-TripleおよびN-QuadファイルのUnicode文字は、Unicodeコードポイント値の16進値を使用して、\u<HEX><HEX><HEX><HEX>または\U<HEX><HEX><HEX><HEX><HEX><HEX><HEX><HEX>としてエスケープする必要があります。TurtleおよびTrigファイルにはUnicodeのエスケープは必要なく、エスケープしていないUnicode値を使用して直接ロードできます。

例1-127 N-Quadデータの短いリテラルと長いリテラルのロード

BEGIN
  -- short literal load
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/>
    LOAD <file:///example1.nq>',
   options=> ' LOAD_DIR={MY_DIR} ', 
   network_owner=>'RDFUSER', network_name=>'NET1');

  -- long literal load
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/>
    LOAD <file:///example1.nq>',
   options=> ' LOAD_DIR={MY_DIR} LOAD_CLOB_ONLY=T ',
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

1.15.6 ロング・リテラル: SPARQL更新で特に留意する点

デフォルトでは、SPARQL更新でNETWORK_MAX_STRING_SIZEのバイト数よりも長い値が操作されることはありません。ロング・リテラルのサポートを有効にするには、SEM_APIS.UPDATE_RDF_GRAPHプロシージャのオプション・パラメータで、CLOB_UPDATE_SUPPORT=Tを指定します。

ロング・リテラルのバルク・ロードはできません。CLOB_UPDATE_SUPPORT=Tオプションが同時に指定されている場合には、FORCE_BULK=Tオプションは無視されます。

1.15.7 空白のノード: SPARQL更新で特に留意する点

更新操作の中には、1セットのRDFトリプルからなるグラフに影響を与えるだけのものがあります。具体的には、ADD、COPYおよびMOVEといった操作です。たとえば、「RDFグラフでのSPARQL更新操作のサポート」に示されているMOVE操作の例では、:digitalCamerasをグラフとして持っている更新トリプルのみを実行できます。ただし、このような操作のパフォーマンスは、IDのみの操作をRDFグラフに対して行うことで向上します。大規模なADD、COPYまたはMOVE操作をIDのみの操作として実行するために、SEM_APIS.UPDATE_RDF_GRAPHプロシージャのoptionsパラメータで、STRICT_BNODE=Fヒントを指定できます。

しかし、ID限定操作の結果、正しくない空白ノードが生ずることがあります。これは、2つのグラフで同じ空白ノードが共有されることがないためです。RDFグラフでは、モデル(RDFグラフ)および空白ノードを含む名前付きグラフの組合せに基づく空白ノード接頭辞スキームが使用されています。これらの接頭辞によって、モデル(RDFグラフ)および名前付きグラフ全体でノード識別子が一意であることが保証されます。ADD、COPYおよびUPDATE操作をID限定で行うという方法では、空白ノード接頭辞が更新されません。

例1-128 ID限定更新による誤った空白ノード値の発生

次の例に示す更新では、グラフ:camerasおよび:cameras2のトリプル両方に対して、同じ空白ノードの主語が生じます。このことは、ここで示されているSEM_MATCH問合せを実行することで確かめられます。

BEGIN
  sem_apis.update_rdf_graph('electronics',
   'PREFIX : <http://www.example.org/electronics/> 
    INSERT DATA { 
       GRAPH :cameras { :camera2 :owner _:bn1 .
                        _:bn1 :name "Axel" }
    };
    COPY :cameras TO :cameras2',
   options=>' STRICT_BNODE=F ', 
   network_owner=>'RDFUSER', network_name=>'NET1');
END;
/

SELECT count(s)
FROM TABLE( SEM_MATCH('
  PREFIX : <http://www.example.org/electronics/> 
  SELECT * 
  WHERE { { graph :cameras  {?s :name "Axel"  } }
          { graph :cameras2 {?s :name "Axel"  } } }
', sem_models('electronics'),null,null,null,null,' STRICT_DEFAULT=T ',
null, null, 'RDFUSER', 'NET1'));

このような誤りを回避するには、SEM_APIS.UPDATE_RDF_GRAPHプロシージャのoptionsパラメータのSTRICT_BNODE=Fヒントは、ADD、COPYまたはMOVE更新操作に空白ノードが含まれていないことが確実な場合にのみ指定してください。

ただし、大規模なグラフに対するADD、COPYおよびMOVEの操作では、デフォルトの方法よりも、STRICT_BNODE=Fオプションを用いた方が、実行速度が大幅に早くなります。ID限定の更新を行う必要がある場合、もう1つの方法は、STRICT_BNODE=Fオプションを使用してから、最後にSEM_APIS.CLEANUP_BNODESプロシージャを実行することです。この方法では、指定されたRDFグラフ内のすべての空白ノードの接頭辞がリセットされ、誤った空白ノード・ラベルがすべて効果的に修正(「クリーン・アップ」)されます。

なお、ADD、COPYまたはMOVE操作の回数が少ない場合には、この2段階からなる方法は用いないでください。少数の操作をデフォルトの方法を用いて実行する方が、少数のID限定操作を実行してからSEM_APIS.CLEANUP_BNODESプロシージャを実行するよりも高速です。

次の例では、electronicsという名前のRDFグラフの空白ノードを修正しています。

EXECUTE sem_apis.cleanup_bnodes('electronics');