7.5 SEM_MATCHまたはSQLベースの問合せ結果からのユーザーフレンドリJavaオブジェクトの取得

RDFグラフの問合せは、次のいずれかの方法を用いて行うことができます。

  • SPARQL (JavaメソッドまたはWebサービス・エンドポイントを使用)

  • SEM_MATCH (SPARQL問合せを埋め込んだ表関数)

  • SQL (<user>.<network_name>#RDFM<model>ビューを問い合せて、<user>.<network_name>#RDF_VALUE$などの表と結合)

Java開発者が使用しやすいのは、最初の方法の結果です。2番目と3番目の方法の結果はJava開発者にとっては使用しにくいかもしれません。型付きRDFリテラルとマッピングされた適切な型付きJavaオブジェクトを取得するために、様々な列を解析する必要があるためです。RDF Graph support for Apache Jenaは、JDBC結果セットから適切な型付きJavaオブジェクトを取得するタスクを簡略化できるように、いくつかのメソッドとヘルパー関数をサポートしています。これらのメソッドとヘルパー関数を次の例に示します。

これらの例では、次のコードのように、RDFグラフのRDFTビューへの挿入によって一連の型付きリテラルが追加されるRDFグラフTGRAPHを使用します。

exec sem_apis.create_rdf_graph('tgraph',null,null,network_owner=>'RDFUSR',network_name=>'LOCALNET');
exec sem_apis.truncate_rdf_graph('tgraph', network_owner=>'RDFUSR',network_name=>'LOCALNET');
 
-- Add some triples
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph','<urn:s1>','<urn:p1>', '<urn:o1>','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph','<urn:s2>','<urn:p2>', '"hello world"','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph','<urn:s3>','<urn:p3>', '"hello world"@en','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph','<urn:s4>','<urn:p4>', '" o1o "^^<http://www.w3.org/2001/XMLSchema#string>','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph','<urn:s4>','<urn:p4>', '"xyz"^^<http://mytype>','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph','<urn:s5>','<urn:p5>', '"123"^^<http://www.w3.org/2001/XMLSchema#integer>','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph','<urn:s5>','<urn:p5>', '"123.456"^^<http://www.w3.org/2001/XMLSchema#double>','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph','<urn:s6>','<urn:p6>', '_:bn1','RDFUSR','LOCALNET'));
 
-- Add some quads
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph:<urn:g1>','<urn:s1>','<urn:p1>', '<urn:o1>','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s1>','<urn:p1>', '<urn:o1>','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s2>','<urn:p2>', '"hello world"','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s3>','<urn:p3>', '"hello world"@en','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s4>','<urn:p4>', '" o1o "^^<http://www.w3.org/2001/XMLSchema#string>','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s4>','<urn:p4>', '"xyz"^^<http://mytype>','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s5>','<urn:p5>', '"123"^^<http://www.w3.org/2001/XMLSchema#integer>','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s5>','<urn:p5>', '"123.456"^^<http://www.w3.org/2001/XMLSchema#double>','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s6>','<urn:p6>', '_:bn1','RDFUSR','LOCALNET'));
insert into LOCALNET#RDFT_TGRAPH(TRIPLE) values(sdo_rdf_triple_s('tgraph:<urn:g2>','<urn:s7>','<urn:p7>', '"2002-10-10T12:00:00-05:00"^^<http://www.w3.org/2001/XMLSchema#dateTime>','RDFUSR','LOCALNET'));
commit;

例7-1 SQLベースのグラフ問合せ

例7-1は、純粋なSQLベースのグラフ問合せを実行して、Jenaオブジェクトを作成します。

iTimeout = 0; // no time out
iDOP = 1;     // degree of parallelism
iStartColPos = 2;

queryString = "select 'hello'||rownum as extra, o.VALUE_TYPE,o.LITERAL_TYPE,o.LANGUAGE_TYPE,o.LONG_VALUE,o.VALUE_NAME "
            + "  from rdfusr.localnet#rdfm_tgraph g, rdfusr.localnet#rdf_value$ o where g.canon_end_node_id = o.value_id";
 
rs = oracle.executeQuery(queryString, iTimeout, iDOP, bindValues);  
 
while (rs.next()) {
  node = OracleSemIterator.retrieveNodeFromRS(rs, iStartColPos, OracleSemQueryPlan.CONST_FIVE_COL, translator);
  System.out.println("Result " + node.getClass().getName() + " = " + node + " " + rs.getString(1));
}

例7-1では、次のような出力が生成されます。

Result org.apache.jena.graph.Node_Literal = "123"^^http://www.w3.org/2001/XMLSchema#decimal hello1
Result org.apache.jena.graph.Node_Literal = "123"^^http://www.w3.org/2001/XMLSchema#decimal hello2
Result org.apache.jena.graph.Node_URI = urn:o1 hello3
Result org.apache.jena.graph.Node_URI = urn:o1 hello4
Result org.apache.jena.graph.Node_URI = urn:o1 hello5
Result org.apache.jena.graph.Node_Literal = "hello world" hello6
Result org.apache.jena.graph.Node_Literal = "hello world" hello7
Result org.apache.jena.graph.Node_Literal = "hello world"@en hello8
Result org.apache.jena.graph.Node_Literal = "hello world"@en hello9
Result org.apache.jena.graph.Node_Literal = " o1o " hello10
Result org.apache.jena.graph.Node_Literal = " o1o " hello11
Result org.apache.jena.graph.Node_Literal = "xyz"^^http://mytype hello12
Result org.apache.jena.graph.Node_Literal = "xyz"^^http://mytype hello13
Result org.apache.jena.graph.Node_Literal = "1.23456E2"^^http://www.w3.org/2001/XMLSchema#double hello14
Result org.apache.jena.graph.Node_Literal = "1.23456E2"^^http://www.w3.org/2001/XMLSchema#double hello15
Result org.apache.jena.graph.Node_Blank = m15mbn1 hello16
Result org.apache.jena.graph.Node_Blank = m15g3C75726E3A67323Egmbn1 hello17
Result org.apache.jena.graph.Node_Literal = "2002-10-10T17:00:00Z"^^http://www.w3.org/2001/XMLSchema#dateTime hello18

例7-2 SEM_MATCHと標準SQL構成要素が混在するハイブリッド問合せ

例7-2は、OracleSemIterator.retrieveNodeFromRS APIを使用してJenaオブジェクトを作成します。連続した5個の列を(値タイプ、リテラル・タイプ、言語タイプ、ロング値、値名の順序どおりに)読み取り、必要なエスケープ解除とオブジェクトのインスタンス化を実行します。

iStartColPos = 1;
queryString = "select  g$RDFVTYP, g, count(1) as cnt " 
            + "  from table(sem_match('{ GRAPH ?g { ?s ?p ?o . } }',sem_models('tgraph'),null,null,null,null,null,null,null,'RDFUSR','LOCALNET')) "
            + " group by g$RDFVTYP, g";
 
rs = oracle.executeQuery(queryString, iTimeout, iDOP, bindValues);  
while (rs.next()) {
  node = OracleSemIterator.retrieveNodeFromRS(rs, iStartColPos, OracleSemQueryPlan.CONST_TWO_COL, translator);
  System.out.println("Result " + node.getClass().getName() + " = " + node + " " + rs.getInt(iStartColPos + 2));
}

例7-2では、次のような出力が生成されます。

Result org.apache.jena.graph.Node_URI = urn:g2 9
Result org.apache.jena.graph.Node_URI = urn:g1 1

次に、例7-2について説明します。

  • Oracleクラスのヘルパー関数executeQueryがSQL文の実行に使用され、OracleSemIterator.retrieveNodeFromRS API (例7-1でも使用されている)がJenaオブジェクトの作成に使用されます。

  • 出力では2つの列、値タイプ(g$RDFVTYP)と値名(g)のみが使用されます。このg変数は決してリテラルRDFリソースにはならないことが明らかです。

  • 列の順序は重要です。2列からなる変数の場合、最初の列が値タイプ、2番目の列が値名であることが必要です。

例7-3 SEM_MATCH問合せ

例7-3は、SEM_MATCH問合せを実行し、Jenaオブジェクトのリストを返すイテレータ(OracleSemIteratorのインスタンス)を返します。

queryString = "select  g$RDFVTYP, g, s$RDFVTYP, s, p$RDFVTYP, p, o$RDFVTYP,o$RDFLTYP,o$RDFLANG,o$RDFCLOB,o "
            + "  from table(sem_match('{ GRAPH ?g { ?s ?p ?o . } }',sem_models('tgraph'),null,null,null,null,null,null,null,'RDFUSR','LOCALNET'))";
guide = new ArrayList<String>();
guide.add(OracleSemQueryPlan.CONST_TWO_COL);
guide.add(OracleSemQueryPlan.CONST_TWO_COL);
guide.add(OracleSemQueryPlan.CONST_TWO_COL);
guide.add(OracleSemQueryPlan.CONST_FIVE_COL);
 
rs = oracle.executeQuery(queryString, iTimeout, iDOP, bindValues); 
osi = new OracleSemIterator(rs); 
osi.setGuide(guide); 
osi.setTranslator(translator);
 
while (osi.hasNext()) {
  result = osi.next();
  System.out.println("Result " + result.getClass().getName() + " = " + result);
}

例7-3では、次のような出力が生成されます。

Result oracle.spatial.rdf.client.jena.Domain = <domain 0:urn:g2 1:urn:s5 2:urn:p5 3:"123"^^http://www.w3.org/2001/XMLSchema#decimal>
Result oracle.spatial.rdf.client.jena.Domain = <domain 0:urn:g2 1:urn:s5 2:urn:p5 3:"1.23456E2"^^http://www.w3.org/2001/XMLSchema#double>
Result oracle.spatial.rdf.client.jena.Domain = <domain 0:urn:g2 1:urn:s7 2:urn:p7 3:"2002-10-10T17:00:00Z"^^http://www.w3.org/2001/XMLSchema#dateTime>
Result oracle.spatial.rdf.client.jena.Domain = <domain 0:urn:g2 1:urn:s2 2:urn:p2 3:"hello world">
Result oracle.spatial.rdf.client.jena.Domain = <domain 0:urn:g2 1:urn:s4 2:urn:p4 3:" o1o ">
Result oracle.spatial.rdf.client.jena.Domain = <domain 0:urn:g2 1:urn:s4 2:urn:p4 3:"xyz"^^http://mytype>
Result oracle.spatial.rdf.client.jena.Domain = <domain 0:urn:g2 1:urn:s6 2:urn:p6 3:m15g3C75726E3A67323Egmbn1>
Result oracle.spatial.rdf.client.jena.Domain = <domain 0:urn:g2 1:urn:s1 2:urn:p1 3:urn:o1>
Result oracle.spatial.rdf.client.jena.Domain = <domain 0:urn:g1 1:urn:s1 2:urn:p1 3:urn:o1>
Result oracle.spatial.rdf.client.jena.Domain = <domain 0:urn:g2 1:urn:s3 2:urn:p3 3:"hello world"@en>

例7-3の内容:

  • OracleSemIteratorがJDBC結果セットを取得します。OracleSemIteratorには、SPARQL変数のバインド値を表すすべての列を解析するためのガイダンスが必要です。ガイドは単純な文字列値のリストです。2列の変数(主語と述語の位置)と5列の変数(目的語の位置)を区別する2つの定数が定義されています。トランスレータも必要です。

  • 出力では4つの変数が使用されます。最初の3つの変数はRDFリテラル・リソースではないため、CONST_TWO_COLがガイドとして使用されます。最後の変数はRDFリテラル・リソースになることができます。したがって、CONST_FIVE_COLがガイドとして使用されます。

  • 列の順序が重要です。例のとおりにする必要があります。