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がガイドとして使用されます。
-
列の順序が重要です。例のとおりにする必要があります。