この章では、Oracle Spatial and Graph RDFセマンティク・グラフのリレーショナル・データ上にRDFビューを作成し、使用する方法を説明します。リレーショナル・データは、W3Cドキュメントに説明のあるRDB2RDFマッピングの2つのフォームのうちの1つを使用して、直接マッピングとR2RMLマッピングで仮想RDFトリプルとして表示されます。
R2RML: RDB to RDF Mapping Language、W3C勧告(http://www.w3.org/TR/r2rml/)
A Direct Mapping of Relational Data to RDF、W3C勧告(http://www.w3.org/TR/rdb-direct-mapping/)
この章には次の項が含まれます。
リレーショナル・データでRDFビューを使用すると、異なるソースから入手可能なデータを統合することができます。リレーショナル・データと一致するRDFトリプルを物理的に格納しなくても、リレーショナル・データの長所を利用することができます。Oracle Database 12cリリース1 (12.1)でRDFビューがRDFセマンティク・グラフに含められる前は、カスタムSQL問合せを書き込むか、非標準のマッピングを使用して、生成されたRDFトリプルを物理的にRDFモデルに格納する必要がありました。
RDFデータにリレーショナル・データのマッピングを作成する最も単純な方法は、SEM_APIS.CREATE_RDFVIEW_MODELプロシージャをコールしてRDFビューを作成することと、RDFとして表示したい内容の表またはビューのリストを指定することです。これが、それらのリレーショナル表またはビューの直接マッピングになります。
よりカスタマイズされたマッピングを行うには、R2RMLマッピング・ドキュメントを(たとえばTurtleを使用したRDFで)記述し、必要なマッピングを指定して、マッピング・ドキュメントを(N-Triple形式に変換した後で)ステージング表にロードし(表の定義は、「ステージング表を使用したセマンティク・データのバルク・ロード」を参照)、さらにSEM_APIS.CREATE_RDFVIEW_MODELプロシージャをコールして、ステージング表の名前を指定することでRDFビューを作成する方法があります。
SEM_APISパッケージ(「SEM_APISパッケージのサブプログラム」を参照) には、RDFビューを作成、削除、エクスポート(ビューのコンテンツをマテリアライズ)するためのサブプログラムが含まれています。RDFビューはRDFモデルとして作成されますが、物理的にはメタデータのみが含まれています。実際のデータは、RDFビューが作成されたリレーショナル表に引き続き格納されます。
この項の残りの例では、起動元のスキーマに次のリレーショナル表が存在することを前提としています。
CREATE TABLE dept ( deptno NUMBER CONSTRAINT pk_DeptTab_deptno PRIMARY KEY, dname VARCHAR2(30), loc VARCHAR2(30) ); CREATE TABLE emp ( empno NUMBER PRIMARY KEY, ename VARCHAR2(30), job VARCHAR2(20), deptno NUMBER REFERENCES dept (deptno) );
これらの表が起動元とは異なるスキーマ(たとえば、SCOTT)にある場合、これらの表の名前を指定する際に、スキーマ修飾された表名("SCOTT"."DEPT"および"SCOTT"."EMP")を使用する必要があることに注意してください。
例10-1では、2つの表EMPとDEPTの直接マッピングに、ベース接頭辞http://empdb/を使用してRDFビュー・モデルを作成します。(仮想)RDF語句は、A Direct Mapping of Relational Data to RDF、W3C勧告(http://www.w3.org/TR/rdb-direct-mapping/)に従って作成されます。
例10-1 直接マッピングを使用したRDFビューの作成
BEGIN
sem_apis.create_rdfview_model(
model_name => 'empdb_model',
tables => SYS.ODCIVarchar2List('EMP', 'DEPT'),
prefix => 'http://empdb/',
options => 'KEY_BASED_REF_PROPERTY=T'
);
END;
/
生成されるプロパティを表示するには、次の文を入力します(オブジェクトは、TESTUSERというユーザーのスキーマに作成されるとします)。
SELECT DISTINCT p
FROM TABLE(SEM_MATCH(
'{?s ?p ?o}',
SEM_Models('empdb_model'),
NULL,
NULL,
NULL));
P
--------------------------------------------------------------------------------
http://empdb/TESTUSER.EMP#DEPTNO
http://empdb/TESTUSER.DEPT#LOC
http://empdb/TESTUSER.EMP#JOB
http://empdb/TESTUSER.DEPT#DEPTNO
http://empdb/TESTUSER.EMP#ENAME
http://www.w3.org/1999/02/22-rdf-syntax-ns#type
http://empdb/TESTUSER.DEPT#DNAME
http://empdb/TESTUSER.EMP#EMPNO
http://empdb/TESTUSER.EMP#ref-DEPTNO
9 rows selected.
例10-2 CONFORMANCE=Tの使用
例10-2は本質的に例10-1と同じですが、CONFORMANCE=Tオプションを使用します(SEM_APIS.CREATE_RDFVIEW_MODELのoptionsパラメータの説明を参照)。出力について、スキーマ名はプロパティ・リストに含まれないことに注意してください。たとえば、例10-2の最初の出力レコードがhttp://empdb/DEPT#LOCであるのに対し、例10-1で生成されるもう一方はhttp://empdb/TESTUSER.DEPT#LOCとなります。
BEGIN
sem_apis.create_rdfview_model(
model_name => 'empdb_model',
tables => SYS.ODCIVarchar2List('EMP', 'DEPT'),
prefix => 'http://empdb/',
options => 'CONFORMANCE=T'
);
END;
/
SELECT DISTINCT p
FROM TABLE(SEM_MATCH(
'{?s ?p ?o}',
SEM_Models('empdb_model'),
NULL,
NULL,
NULL));
P
--------------------------------------------------------------------------------
http://empdb/DEPT#LOC
http://empdb/EMP#ref-DEPTNO
http://empdb/EMP#ENAME
http://empdb/DEPT#DEPTNO
http://empdb/EMP#JOB
http://empdb/EMP#EMPNO
http://www.w3.org/1999/02/22-rdf-syntax-ns#type
http://empdb/DEPT#DNAME
http://empdb/EMP#DEPTNO
9 rows selected.
2つの表EMPとDEPTを使用してRDFビューを、独自のカスタマイズによって作成する場合、Turtleを使用して指定したR2RMLマッピング・ドキュメントを作成することができます。次に例を示します。
@prefix rr: <http://www.w3.org/ns/r2rml#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
@prefix ex: <http://example.com/ns#>.
ex:TriplesMap_Dept
rr:logicalTable [ rr:tableName "DEPT" ];
rr:subjectMap [
rr:template "http://data.example.com/department/{DEPTNO}";
rr:class ex:Department;
];
rr:predicateObjectMap [
rr:predicate ex:deptNum;
rr:objectMap [ rr:column "DEPTNO" ; rr:datatype xsd:integer ];
];
rr:predicateObjectMap [
rr:predicate ex:deptName;
rr:objectMap [ rr:column "DNAME" ];
];
rr:predicateObjectMap [
rr:predicate ex:deptLocation;
rr:objectMap [ rr:column "LOC" ];
].
ex:TriplesMap_Emp
rr:logicalTable [ rr:tableName "EMP" ];
rr:subjectMap [
rr:template "http://data.example.com/employee/{EMPNO}";
rr:class ex:Employee;
];
rr:predicateObjectMap [
rr:predicate ex:empNum;
rr:objectMap [ rr:column "EMPNO" ; rr:datatype xsd:integer ];
];
rr:predicateObjectMap [
rr:predicate ex:empName;
rr:objectMap [ rr:column "ENAME" ];
];
rr:predicateObjectMap [
rr:predicate ex:jobType;
rr:objectMap [ rr:column "JOB" ];
];
rr:predicateObjectMap [
rr:predicate ex:worksForDeptNum;
rr:objectMap [ rr:column "DEPTNO" ; rr:dataType xsd:integer ];
];
rr:predicateObjectMap [
rr:predicate ex:worksForDept;
rr:objectMap [
rr:parentTriplesMap ex:TriplesMap_Dept ;
rr:joinCondition [ rr:child "DEPTNO"; rr:parent "DEPTNO" ]]].
その後、(N-Triples形式に変換された)R2RMLマッピングを、SCOTT.R2RTABなどのステージング表にロードし、この表へのSELECT権限をMDSYSに付与します。
次に、例10-3の場合のように、SEM_APIS.CREATE_RDFVIEW_MODELをコールします。
例10-3 R2RMLマッピングによるRDFビューの作成
BEGIN
sem_apis.create_rdfview_model(
model_name => 'empdb_model',
tables => NULL,
r2rml_table_owner => 'SCOTT',
r2rml_table_name => 'R2RTAB'
);
END;
/
例10-4に示すように、RDFビューは、SEM_APIS.DROP_RDFVIEW_MODELプロシージャを使用して削除できます。
例10-4 RDFビューの削除
BEGIN
sem_apis.drop_rdfview_model(
model_name => 'empdb_model'
);
END;
/
RDFビューのコンテンツは仮想、つまり直接マッピングまたはR2RMLマッピングによってマップされ、基礎となるリレーショナル・データに対応するRDFトリプルであり、実体はなく、どこにも格納されていません。ただしテストのために、これらの仮想RDFトリプルをRDFモデルに具体化し、格納する必要がある場合があります。SEM_APIS.EXPORT_RDFVIEW_MODELサブプログラムは、RDFビューのRDFトリプルをステージング表に格納します。その後、ステージング表を使用してRDFモデルへロードすることができます。
例10-5では、RDFビューempdb_modelのコンテンツをステージング表SCOTT.RDFTABに実体化(N-Triples形式)します。
例10-5 RDFビューのエクスポート
BEGIN
sem_apis.export_rdfview_model(
model_name => 'empdb_model',
rdf_table_owner => 'SCOTT',
rdf_table_name => 'RDFTAB'
);
END;
例10-6は、直接マッピングによるRDFビューを使用した単純なワークフローを示しています。ここでは、次のことを行っています。
2つのリレーショナル表(EMPおよびDEPT)を作成します。
表にデータを挿入します。
2つの表の直接マッピングを使用して、RDFビュー・モデル(empdb_model)を作成します。
SEM_MATCHベースのSQL問合せで、SPARQLを使用してRDFビューを問い合せます。
例10-6 直接マッピングによるRDFビューの使用
-- Use the following relational tables.
CREATE TABLE dept (
deptno NUMBER CONSTRAINT pk_DeptTab_deptno PRIMARY KEY,
dname VARCHAR2(30),
loc VARCHAR2(30)
);
CREATE TABLE emp (
empno NUMBER PRIMARY KEY,
ename VARCHAR2(30),
job VARCHAR2(20),
deptno NUMBER REFERENCES dept (deptno)
);
-- Insert some data.
INSERT INTO dept (deptno, dname, loc)
VALUES (1, 'Sales', 'Boston');
INSERT INTO dept (deptno, dname, loc)
VALUES (2, 'Manufacturing', 'Chicago');
INSERT INTO dept (deptno, dname, loc)
VALUES (3, 'Marketing', 'Boston');
INSERT INTO emp (empno, ename, job, deptno)
VALUES (1, 'Alvarez', 'SalesRep', 1);
INSERT INTO emp (empno, ename, job, deptno)
VALUES (2, 'Baxter', 'Supervisor', 2);
INSERT INTO emp (empno, ename, job, deptno)
VALUES (3, 'Chen', 'Writer', 3);
INSERT INTO emp (empno, ename, job, deptno)
VALUES (4, 'Davis', 'Technician', 2);
-- Create an RDF view model using direct mapping of two tables, EMP and DEPT,
-- with a base prefix of http://empdb/.
-- Specify KEY_BASED_REF_PROPERTY=T for the options parameter.
BEGIN
sem_apis.create_rdfview_model(
model_name => 'empdb_model',
tables => SYS.ODCIVarchar2List('EMP', 'DEPT'),
prefix => 'http://empdb/',
options => 'KEY_BASED_REF_PROPERTY=T'
);
END;
/
-- Query an RDF view using SPARQL in a SEM_MATCH-based SQL query.
-- The next statament is a query against an RDF view named empdb_model
-- to find the employees who work for any department located in Boston.
SELECT emp
FROM TABLE(SEM_MATCH(
'{?emp emp:ref-DEPTNO ?dept . ?dept dept:LOC "Boston"}',
SEM_Models('empdb_model'),
NULL,
SEM_ALIASES(
SEM_ALIAS('dept','http://empdb/TESTUSER.DEPT#'),
SEM_ALIAS('emp','http://empdb/TESTUSER.EMP#')
),
null));
-- The preceding query is functionally comparable to this:
SELECT e.empno FROM emp e, dept d WHERE e.deptno = d.deptno AND d.loc = 'Boston';
例10-7 例10-6の出力
SQL> -- Use the following relational tables.
SQL>
SQL> CREATE TABLE dept (
2 deptno NUMBER CONSTRAINT pk_DeptTab_deptno PRIMARY KEY,
3 dname VARCHAR2(30),
4 loc VARCHAR2(30)
5 );
Table created.
SQL>
SQL> CREATE TABLE emp (
2 empno NUMBER PRIMARY KEY,
3 ename VARCHAR2(30),
4 job VARCHAR2(20),
5 deptno NUMBER REFERENCES dept (deptno)
6 );
Table created.
SQL>
SQL> -- Insert some data.
SQL>
SQL> INSERT INTO dept (deptno, dname, loc)
2 VALUES (1, 'Sales', 'Boston');
1 row created.
SQL> INSERT INTO dept (deptno, dname, loc)
2 VALUES (2, 'Manufacturing', 'Chicago');
1 row created.
SQL> INSERT INTO dept (deptno, dname, loc)
2 VALUES (3, 'Marketing', 'Boston');
1 row created.
SQL>
SQL> INSERT INTO emp (empno, ename, job, deptno)
2 VALUES (1, 'Alvarez', 'SalesRep', 1);
1 row created.
SQL> INSERT INTO emp (empno, ename, job, deptno)
2 VALUES (2, 'Baxter', 'Supervisor', 2);
1 row created.
SQL> INSERT INTO emp (empno, ename, job, deptno)
2 VALUES (3, 'Chen', 'Writer', 3);
1 row created.
SQL> INSERT INTO emp (empno, ename, job, deptno)
2 VALUES (4, 'Davis', 'Technician', 2);
1 row created.
SQL>
SQL> -- Create an RDF view model using direct mapping of two tables, EMP and DEPT,
SQL> -- with a base prefix of http://empdb/.
SQL> -- Specify KEY_BASED_REF_PROPERTY=T for the options parameter.
SQL>
SQL> BEGIN
2 sem_apis.create_rdfview_model(
3 model_name => 'empdb_model',
4 tables => SYS.ODCIVarchar2List('EMP', 'DEPT'),
5 prefix => 'http://empdb/',
6 options => 'KEY_BASED_REF_PROPERTY=T'
7 );
8 END;
9 /
PL/SQL procedure successfully completed.
SQL>
SQL> -- Query an RDF view using SPARQL in a SEM_MATCH-based SQL query.
SQL> -- The next statament is a query against an RDF view named empdb_model
SQL> -- to find the employees who work for any department located in Boston.
SQL>
SQL> SELECT emp
2 FROM TABLE(SEM_MATCH(
3 '{?emp emp:ref-DEPTNO ?dept . ?dept dept:LOC "Boston"}',
4 SEM_Models('empdb_model'),
5 NULL,
6 SEM_ALIASES(
7 SEM_ALIAS('dept','http://empdb/TESTUSER.DEPT#'),
8 SEM_ALIAS('emp','http://empdb/TESTUSER.EMP#')
9 ),
10 null));
EMP
--------------------------------------------------------------------------------
http://empdb/TESTUSER.EMP/EMPNO=1
http://empdb/TESTUSER.EMP/EMPNO=3
SQL>
SQL> -- The preceding query is functionally comparable to this:
SQL> SELECT e.empno FROM emp e, dept d WHERE e.deptno = d.deptno AND d.loc = 'Boston';
EMPNO
----------
1
3
1つのSEM_MATCH問合せでSERVICEキーワード(「グラフ・パターン: SPARQL 1.1フェデレーテッド問合せのサポート」を参照)を使用してネイティブ・トリプル・データと仮想RDB2RDFトリプル・データを組み合せることができます。SERVICEキーワードは、ローカル(仮想) RDFデータを示す特別なSERVICE URLを使用してオーバーロードされます。特別なSERVICE URLを表すために次の接頭辞が使用されます。
ネイティブ・モデル - oram: <http://xmlns.oracle.com/models/>
ネイティブ仮想モデル - oravm: <http://xmlns.oracle.com/virtual_models/>
RDB2RDFモデル - orardbm: <http://xmlns.oracle.com/rdb_models/>
例10-8 複数のデータセットの問合せ
例10-8は複数のデータセットを問い合せます。この問合せでは、最初のトリプル・パターン{ ?x rdf:type :Person }は通常どおりネイティブ・モデルm1に対応しますが、{ ?x :name ?name }はローカル・ネイティブ・モデルm2に対応し、{ ?x :email ?email }はローカルRDB2RDFモデルrdfview1に対応します。
select * from table (sem_match(
'SELECT ?x ?name ?email
WHERE {
?x rdf:type :Person .
OPTIONAL { SERVICE oram:m2 { ?x :name ?name } }
OPTIONAL { SERVICE orardbm:rdfview1 { ?x :email ?email } }
}'
sem_models('m1'), null, null, null, null, ' '));
オーバーロードされたSERVICEの使用は、SEM_MATCHのmodels引数に指定された1つのモデルのみで許可されます。オーバーロードされたSERVICE問合せでは、複数のモデルまたは入力としてのルールベースは許可されません。そのような組合せのかわりに、複数のモデルまたは伴意(あるいは両方)を含む仮想モデルを使用する必要があります。また、SEM_MATCHのindex_status引数は、modelsパラメータで入力として渡された仮想モデルに含まれる伴意のみをチェックします。つまり、オーバーロードされたSERVICEコールで参照される伴意のステータスはチェックされません。
例10-9 仮想RDB2RDFデータとネイティブRDFデータの問合せ
例10-9は、2つのデータセットを問い合せます。例10-6のempdb_modelと、peopleという名前のネイティブ・モデルです。
-- Create native model people --
create table atab (gval varchar2(4000), tri sdo_rdf_triple_s);
execute sem_apis.create_sem_model('people','atab','tri');
create table stab(RDF$STC_GRAPH varchar2(4000), RDF$STC_sub varchar2(4000),
RDF$STC_pred varchar2(4000), RDF$STC_obj varchar2(4000));
grant select on stab to mdsys;
grant insert on atab to mdsys;
insert into stab values (null, '<http://empdb/TESTUSER.EMP/EMPNO=1>', '<http://people.org/age>', '"35"^^<http://www.w3.org/2001/XMLSchema#int>');
insert into stab values (null, '<http://empdb/TESTUSER.EMP/EMPNO=2>', '<http://people.org/age>', '"39"^^<http://www.w3.org/2001/XMLSchema#int>');
insert into stab values (null, '<http://empdb/TESTUSER.EMP/EMPNO=3>', '<http://people.org/age>', '"30"^^<http://www.w3.org/2001/XMLSchema#int>');
insert into stab values (null, '<http://empdb/TESTUSER.EMP/EMPNO=4>', '<http://people.org/age>', '"42"^^<http://www.w3.org/2001/XMLSchema#int>');
commit;
exec sem_apis.bulk_load_from_staging_table('people','testuser','stab');
-- Querying multiple datasets --
SELECT emp, age
FROM TABLE(SEM_MATCH(
'SELECT ?emp ?age WHERE{
?emp peop:age ?age
SERVICE orardbm:empdb_model { ?emp emp:ref-DEPTNO ?dept . ?dept dept:LOC "Boston" }
}',
SEM_Models('people'),
NULL,
SEM_ALIASES(
SEM_ALIAS('dept','http://empdb/TESTUSER.DEPT#'),
SEM_ALIAS('emp','http://empdb/TESTUSER.EMP#'),
SEM_ALIAS('peop','http://people.org/')
),
NULL));