先日、RDFグラフをAPEXで扱う記事を書いたのですが、基本的すぎて面白みがないと感じたので、RDFグラフの検索にバインド変数を使ってみました。アプリケーションの作成に当たっては、マニュアルRDFナレッジ・グラフ開発者ガイドに記載されている家系の情報を使っています。
以下のような動作をするアプリケーションを作成します。人の名前を入力すると、上の対話レポートにその人の子供を一覧し、下の対話モード・レポートには孫を一覧します。
アプリケーション開発に使用する環境は、以前の記事と同じです。データの準備やSQL の取り出しは手元で動かしているOracle Database 21c XEを使います。APEXアプリケーションはAutonomous Databaseに作成します。
両方の環境ともに、APEXDEVというスキーマで作業を行います。
Oracle Database 21c XEにロードしたグラフのデータは、DataPumpを使ってAutonomous Databaseへ移行します。
データの準備とSQLの取り出し
Oracle Database 21c XEに家系の情報をロードし、APEXアプリケーションに埋め込むSQLの取り出しを行います。
もしネットワークNET1が作成されていたら、削除しておきます。まっさらな環境で作業を行なうことで、エラーが発生する可能性を減らしておきます。
begin | |
sem_apis.drop_sem_network( | |
cascade => true | |
, options => null | |
, network_owner => 'APEXDEV' | |
, network_name => 'NET1' | |
); | |
end; | |
/ |
家系の情報をロードします。以下の作業を行なっています。
- SEM_APIS.CREATE_SEM_NETWORKを呼び出し、ネットワークNET1を作成。
- SEM_APIS.CRAETE_SEM_MODELを使用してモデルfamilyを作成。
- SEM_APIS.UPDATE_MODELを呼び出し、家系のスキーマを定義しデータを投入。
- SEM_APIS.CREATE_RULEBASEを呼び出し、grandParentOfのルール(parentOfのparentOf)を定義する。
- SEM_APIS.CREATE_ENTAILMENTを呼び出し、伴意(ルール索引)を作成する。
- SEM_MATCHを使った検索を実行し、動作の確認をする。
-- Create nework NET1 | |
begin | |
sem_apis.create_sem_network( | |
tablespace_name => 'APEX_2700775222008502' | |
, network_owner => 'APEXDEV' | |
, network_name => 'NET1' | |
); | |
end; | |
/ | |
-- Create the model. | |
begin | |
sem_apis.create_sem_model( | |
model_name => 'family' | |
, table_name => null | |
, column_name => null | |
, network_owner => 'APEXDEV' | |
, network_name => 'NET1' | |
); | |
end; | |
/ | |
-- Insert RDF triples using SEM_APIS.UPDATE_MODEL. These express the following information: | |
BEGIN | |
-- Insert some TBox (schema) information. | |
SEM_APIS.UPDATE_MODEL('family', | |
'PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> | |
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> | |
PREFIX family: <http://www.example.org/family/> | |
INSERT DATA { | |
# Person is a class. | |
family:Person rdf:type rdfs:Class . | |
# Male is a subclass of Person. | |
family:Male rdfs:subClassOf family:Person . | |
# Female is a subclass of Person. | |
family:Female rdfs:subClassOf family:Person . | |
# siblingOf is a property. | |
family:siblingOf rdf:type rdf:Property . | |
# parentOf is a property. | |
family:parentOf rdf:type rdf:Property . | |
# brotherOf is a subproperty of siblingOf. | |
family:brotherOf rdfs:subPropertyOf family:siblingOf . | |
# sisterOf is a subproperty of siblingOf. | |
family:sisterOf rdfs:subPropertyOf family:siblingOf . | |
# A brother is male. | |
family:brotherOf rdfs:domain family:Male . | |
# A sister is female. | |
family:sisterOf rdfs:domain family:Female . | |
# fatherOf is a subproperty of parentOf. | |
family:fatherOf rdfs:subPropertyOf family:parentOf . | |
# motherOf is a subproperty of parentOf. | |
family:motherOf rdfs:subPropertyOf family:parentOf . | |
# A father is male. | |
family:fatherOf rdfs:domain family:Male . | |
# A mother is female. | |
family:motherOf rdfs:domain family:Female . | |
}', | |
network_owner=>'APEXDEV', | |
network_name=>'NET1'); | |
-- Insert some ABox (instance) information. | |
SEM_APIS.UPDATE_MODEL('family', | |
'PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> | |
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> | |
PREFIX family: <http://www.example.org/family/> | |
INSERT DATA { | |
# John is the father of Suzie and Matt | |
family:John family:fatherOf family:Suzie . | |
family:John family:fatherOf family:Matt . | |
# Janice is the mother of Suzie and Matt | |
family:Janice family:motherOf family:Suzie . | |
family:Janice family:motherOf family:Matt . | |
# Sammy is the father of Cathy and Jack | |
family:Sammy family:fatherOf family:Cathy . | |
family:Sammy family:fatherOf family:Jack . | |
# Suzie is the mother of Cathy and Jack | |
family:Suzie family:motherOf family:Cathy . | |
family:Suzie family:motherOf family:Jack . | |
# Matt is the father of Tom and Cindy | |
family:Matt family:fatherOf family:Tom . | |
family:Matt family:fatherOf family:Cindy . | |
# Martha is the mother of Tom and Cindy | |
family:Martha family:motherOf family:Tom . | |
family:Martha family:motherOf family:Cindy . | |
# Cathy is the sister of Jack | |
family:Cathy family:sisterOf family:Jack . | |
# Jack is male | |
family:Jack rdf:type family:Male . | |
# Tom is male. | |
family:Tom rdf:type family:Male . | |
# Cindy is female. | |
family:Cindy rdf:type family:Female . | |
}', | |
network_owner=>'APEXDEV', | |
network_name=>'NET1'); | |
END; | |
/ | |
-- General inferencing in the family model | |
begin | |
sem_apis.create_rulebase( | |
rulebase_name => 'family_rb' | |
, options => null | |
, network_owner => 'APEXDEV' | |
, network_name => 'NET1' | |
); | |
end; | |
/ | |
-- insert grandparent rule | |
insert into net1#semr_family_rb | |
( | |
rule_name | |
, antecedents | |
, filter | |
, consequents | |
, aliases | |
) | |
values | |
( | |
'grandparent_rule' | |
, '(?x :parentOf ?y) (?y :parentOf ?z)' | |
, NULL | |
, '(?x :grandParentOf ?z)' | |
, SEM_ALIASES(SEM_ALIAS('','http://www.example.org/family/')) | |
); | |
commit; | |
-- Create the entailment. | |
begin | |
sem_apis.create_entailment( | |
index_name_in => 'rdfs_rix_family' | |
, models_in => SEM_Models('family') | |
, rulebases_in => SEM_Rulebases('RDFS','family_rb') | |
, network_owner=>'APEXDEV' | |
, network_name=>'NET1' | |
); | |
end; | |
/ | |
-- Select all grandfathers and their grandchildren from the family model, | |
-- without inferencing. (With no inferencing, no results are returned.) | |
SELECT x$rdfterm grandfather, y$rdfterm grandchild | |
FROM TABLE(SEM_MATCH( | |
'PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> | |
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> | |
PREFIX : <http://www.example.org/family/> | |
SELECT ?x ?y | |
WHERE {?x :grandParentOf ?y . ?x rdf:type :Male}', | |
SEM_Models('family'), | |
null, null, null, null, | |
' PLUS_RDFT=VC ', | |
null, null, | |
'APEXDEV', 'NET1')); | |
-- Select all grandfathers and their grandchildren from the family model. | |
-- Use inferencing from both the RDFS and family_rb rulebases. | |
SELECT x$rdfterm grandfather, y$rdfterm grandchild | |
FROM TABLE(SEM_MATCH( | |
'PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> | |
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> | |
PREFIX : <http://www.example.org/family/> | |
SELECT ?x ?y | |
WHERE {?x :grandParentOf ?y . ?x rdf:type :Male}', | |
SEM_Models('family'), | |
SEM_Rulebases('RDFS','family_rb'), | |
null, null, null, | |
' PLUS_RDFT=VC ', | |
null, null, | |
'APEXDEV', 'NET1')); |
GRANDFATHER
--------------------------------------------------------------------------------
GRANDCHILD
--------------------------------------------------------------------------------
<http://www.example.org/family/John>
<http://www.example.org/family/Cathy>
<http://www.example.org/family/John>
<http://www.example.org/family/Jack>
<http://www.example.org/family/John>
<http://www.example.org/family/Tom>
<http://www.example.org/family/John>
<http://www.example.org/family/Cindy>
DECLARE | |
sparql_stmt clob; | |
sql_stmt clob; | |
cur sys_refcursor; | |
vid number; | |
term varchar2(4000); | |
c_val varchar2(4000); | |
BEGIN | |
-- Add a dummy bind clause in the SPARQL statement | |
sparql_stmt := 'PREFIX : <http://www.example.org/family/> | |
SELECT ?c WHERE { | |
BIND("" as ?s) | |
?s :parentOf ?c }'; | |
-- Get the SQL translation for SPARQL statement | |
sql_stmt := sem_apis.sparql_to_sql( | |
sparql_stmt, | |
sem_models('family'), | |
SEM_Rulebases('RDFS','family_rb'), | |
null, | |
null,' USE_BIND_VAR=PLSQL PLUS_RDFT=VC ', null, null, | |
'APEXDEV', 'NET1'); | |
dbms_output.put_line(sql_stmt); | |
-- Execute with <http://www.example.org/family/Martha> | |
term := '<http://www.example.org/family/Martha>'; | |
vid := sem_apis.res2vid('NET1#RDF_VALUE$',term); | |
dbms_output.put_line(chr(10)||'?s='||term); | |
open cur for 'select c$rdfterm from('|| sql_stmt || ')' using vid,term; | |
loop | |
fetch cur into c_val; | |
exit when cur%NOTFOUND; | |
dbms_output.put_line('|-->?c='||c_val); | |
end loop; | |
close cur; | |
-- Execute with <http://www.example.org/family/Sammy> | |
term := '<http://www.example.org/family/Sammy>'; | |
vid := sem_apis.res2vid('NET1#RDF_VALUE$',term); | |
dbms_output.put_line(chr(10)||'?s='||term); | |
open cur for 'select c$rdfterm from('|| sql_stmt || ')' using vid,term; | |
loop | |
fetch cur into c_val; | |
exit when cur%NOTFOUND; | |
dbms_output.put_line('|-->?c='||c_val); | |
end loop; | |
close cur; | |
END; | |
/ |
?s=<http://www.example.org/family/Martha>
|-->?c=<http://www.example.org/family/Cindy>
|-->?c=<http://www.example.org/family/Tom>
?s=<http://www.example.org/family/Sammy>
|-->?c=<http://www.example.org/family/Jack>
|-->?c=<http://www.example.org/family/Cathy>
SELECT * FROM ( | |
SELECT | |
C,C$RDFVID,C$_PREFIX,C$_SUFFIX,C$RDFVTYP,C$RDFCLOB,C$RDFLTYP,C$RDFLANG,SEM_APIS. | |
escape_rdf_term(C$RDFTERM, options=>' SPCLCH_ONLY=T NETWORK_STORAGE_FORM=UNESC | |
') AS C$RDFTERM,SEM$ROWNUM AS SEM$ROWNUM | |
FROM (WITH /*+ MATERIALIZE */ | |
BV0 AS | |
(SELECT :P1_VID AS VALUE_ID, SDO_RDF_TERM(:P1_TERM) AS TERM FROM DUAL) | |
SELECT /*+ | |
NO_MERGE(R) NO_SWAP_JOIN_INPUTS(R) LEADING(R V0) NO_SWAP_JOIN_INPUTS(V0) */ | |
V0.VNAME_PREFIX || V0.VNAME_SUFFIX AS C, V0.VALUE_ID AS C$RDFVID, | |
V0.VNAME_PREFIX AS C$_PREFIX, V0.VNAME_SUFFIX AS C$_SUFFIX, (CASE WHEN | |
V0.VALUE_TYPE IS NULL THEN NULL WHEN V0.VALUE_TYPE IN ('UR','URI') THEN 'URI' | |
WHEN V0.VALUE_TYPE IN ('BN', 'BLN') THEN 'BLN' | |
ELSE 'LIT' | |
END) AS C$RDFVTYP, | |
V0.LONG_VALUE AS C$RDFCLOB, V0.LITERAL_TYPE AS C$RDFLTYP, V0.LANGUAGE_TYPE AS | |
C$RDFLANG, | |
CASE WHEN (CASE WHEN V0.VALUE_TYPE IS NULL THEN NULL WHEN | |
V0.VALUE_TYPE IN ('UR','URI') THEN 'URI' | |
WHEN V0.VALUE_TYPE IN ('BN', 'BLN') | |
THEN 'BLN' | |
ELSE 'LIT' | |
END) IS NULL | |
THEN NULL | |
WHEN (CASE WHEN V0.VALUE_TYPE IS | |
NULL THEN NULL WHEN V0.VALUE_TYPE IN ('UR','URI') THEN 'URI' | |
WHEN V0.VALUE_TYPE | |
IN ('BN', 'BLN') THEN 'BLN' | |
ELSE 'LIT' | |
END) IN ('UR','URI') | |
THEN '<' || | |
V0.VNAME_PREFIX || V0.VNAME_SUFFIX || '>' | |
WHEN (CASE WHEN V0.VALUE_TYPE IS NULL | |
THEN NULL WHEN V0.VALUE_TYPE IN ('UR','URI') THEN 'URI' | |
WHEN V0.VALUE_TYPE IN | |
('BN', 'BLN') THEN 'BLN' | |
ELSE 'LIT' | |
END) IN ('BL','BLN','BN') | |
THEN | |
V0.VNAME_PREFIX || V0.VNAME_SUFFIX | |
ELSE | |
'"' || REPLACE(V0.VNAME_PREFIX || | |
V0.VNAME_SUFFIX,chr(0)) || '"' || NVL2(V0.LANGUAGE_TYPE,'@' || | |
V0.LANGUAGE_TYPE,'') || NVL2(V0.LITERAL_TYPE,'^^<' || V0.LITERAL_TYPE || '>', | |
'')END AS C$RDFTERM, | |
1 AS SEM$ROWNUM | |
FROM (SELECT BV0.VALUE_ID AS | |
S$RDFVID, | |
T0.CANON_END_NODE_ID AS C$RDFVID, | |
T0.START_NODE_ID AS BGP$1 | |
FROM | |
( | |
SELECT * FROM ( | |
SELECT * FROM "APEXDEV".NET1#RDFM_FAMILY | |
UNION ALL | |
SELECT * | |
FROM "APEXDEV".NET1#RDFI_RDFS_RIX_FAMILY | |
)) T0, BV0 BV0 | |
WHERE T0.START_NODE_ID = | |
BV0.VALUE_ID AND | |
T0.P_VALUE_ID = 7703787944492226018) R, | |
"APEXDEV".NET1#RDF_VALUE$ V0 | |
WHERE (1=1) AND (R.C$RDFVID = V0.VALUE_ID)) | |
R | |
WHERE (1=1) | |
) WHERE (1=1) AND 1 NOT IN (SELECT * FROM | |
"APEXDEV".NET1#RDF_RI_SHAD_2$) |
DECLARE | |
sparql_stmt clob; | |
sql_stmt clob; | |
cur sys_refcursor; | |
vid number; | |
term varchar2(4000); | |
c_val varchar2(4000); | |
BEGIN | |
-- Add a dummy bind clause in the SPARQL statement | |
sparql_stmt := 'PREFIX : <http://www.example.org/family/> | |
SELECT ?c WHERE { | |
BIND("" as ?s) | |
?s :grandParentOf ?c }'; | |
-- Get the SQL translation for SPARQL statement | |
sql_stmt := sem_apis.sparql_to_sql( | |
sparql_stmt, | |
sem_models('family'), | |
SEM_Rulebases('RDFS','family_rb'), | |
null, | |
null,' USE_BIND_VAR=PLSQL PLUS_RDFT=VC ', null, null, | |
'APEXDEV', 'NET1'); | |
dbms_output.put_line(sql_stmt); | |
-- Execute with <http://www.example.org/family/John> | |
term := '<http://www.example.org/family/John>'; | |
vid := sem_apis.res2vid('NET1#RDF_VALUE$',term); | |
dbms_output.put_line(chr(10)||'?s='||term); | |
open cur for 'select c$rdfterm from('|| sql_stmt || ')' using vid,term; | |
loop | |
fetch cur into c_val; | |
exit when cur%NOTFOUND; | |
dbms_output.put_line('|-->?c='||c_val); | |
end loop; | |
close cur; | |
END; | |
/ |
?s=<http://www.example.org/family/John>
|-->?c=<http://www.example.org/family/Cindy>
|-->?c=<http://www.example.org/family/Jack>
|-->?c=<http://www.example.org/family/Cathy>
|-->?c=<http://www.example.org/family/Tom>
SELECT * FROM ( | |
SELECT | |
C,C$RDFVID,C$_PREFIX,C$_SUFFIX,C$RDFVTYP,C$RDFCLOB,C$RDFLTYP,C$RDFLANG,SEM_APIS. | |
escape_rdf_term(C$RDFTERM, options=>' SPCLCH_ONLY=T NETWORK_STORAGE_FORM=UNESC | |
') AS C$RDFTERM,SEM$ROWNUM AS SEM$ROWNUM | |
FROM (WITH /*+ MATERIALIZE */ | |
BV0 AS | |
(SELECT :P1_VID AS VALUE_ID, SDO_RDF_TERM(:P1_TERM) AS TERM FROM DUAL) | |
SELECT /*+ | |
NO_MERGE(R) NO_SWAP_JOIN_INPUTS(R) LEADING(R V0) NO_SWAP_JOIN_INPUTS(V0) */ | |
V0.VNAME_PREFIX || V0.VNAME_SUFFIX AS C, V0.VALUE_ID AS C$RDFVID, | |
V0.VNAME_PREFIX AS C$_PREFIX, V0.VNAME_SUFFIX AS C$_SUFFIX, (CASE WHEN | |
V0.VALUE_TYPE IS NULL THEN NULL WHEN V0.VALUE_TYPE IN ('UR','URI') THEN 'URI' | |
WHEN V0.VALUE_TYPE IN ('BN', 'BLN') THEN 'BLN' | |
ELSE 'LIT' | |
END) AS C$RDFVTYP, | |
V0.LONG_VALUE AS C$RDFCLOB, V0.LITERAL_TYPE AS C$RDFLTYP, V0.LANGUAGE_TYPE AS | |
C$RDFLANG, | |
CASE WHEN (CASE WHEN V0.VALUE_TYPE IS NULL THEN NULL WHEN | |
V0.VALUE_TYPE IN ('UR','URI') THEN 'URI' | |
WHEN V0.VALUE_TYPE IN ('BN', 'BLN') | |
THEN 'BLN' | |
ELSE 'LIT' | |
END) IS NULL | |
THEN NULL | |
WHEN (CASE WHEN V0.VALUE_TYPE IS | |
NULL THEN NULL WHEN V0.VALUE_TYPE IN ('UR','URI') THEN 'URI' | |
WHEN V0.VALUE_TYPE | |
IN ('BN', 'BLN') THEN 'BLN' | |
ELSE 'LIT' | |
END) IN ('UR','URI') | |
THEN '<' || | |
V0.VNAME_PREFIX || V0.VNAME_SUFFIX || '>' | |
WHEN (CASE WHEN V0.VALUE_TYPE IS NULL | |
THEN NULL WHEN V0.VALUE_TYPE IN ('UR','URI') THEN 'URI' | |
WHEN V0.VALUE_TYPE IN | |
('BN', 'BLN') THEN 'BLN' | |
ELSE 'LIT' | |
END) IN ('BL','BLN','BN') | |
THEN | |
V0.VNAME_PREFIX || V0.VNAME_SUFFIX | |
ELSE | |
'"' || REPLACE(V0.VNAME_PREFIX || | |
V0.VNAME_SUFFIX,chr(0)) || '"' || NVL2(V0.LANGUAGE_TYPE,'@' || | |
V0.LANGUAGE_TYPE,'') || NVL2(V0.LITERAL_TYPE,'^^<' || V0.LITERAL_TYPE || '>', | |
'')END AS C$RDFTERM, | |
1 AS SEM$ROWNUM | |
FROM (SELECT BV0.VALUE_ID AS | |
S$RDFVID, | |
T0.CANON_END_NODE_ID AS C$RDFVID, | |
T0.START_NODE_ID AS BGP$1 | |
FROM | |
( | |
SELECT * FROM ( | |
SELECT * FROM "APEXDEV".NET1#RDFM_FAMILY | |
UNION ALL | |
SELECT * | |
FROM "APEXDEV".NET1#RDFI_RDFS_RIX_FAMILY | |
)) T0, BV0 BV0 | |
WHERE T0.START_NODE_ID = | |
BV0.VALUE_ID AND | |
T0.P_VALUE_ID = 8440289324123914894) R, | |
"APEXDEV".NET1#RDF_VALUE$ V0 | |
WHERE (1=1) AND (R.C$RDFVID = V0.VALUE_ID)) | |
R | |
WHERE (1=1) | |
) WHERE (1=1) AND 1 NOT IN (SELECT * FROM | |
"APEXDEV".NET1#RDF_RI_SHAD_2$) |
データの移行
SQL> grant create any directory to apexdev;
Grant succeeded.
SQL>
SQL> create directory dump_dir as '/home/oracle';
Directory created.
SQL>
$ expdp apexdev/********@localhost/xepdb1 directory=dump_dir dumpfile=rdf.dmp version=19
Export: Release 21.0.0.0.0 - Production on Thu Dec 2 14:50:38 2021
Version 21.3.0.0.0
Copyright (c) 1982, 2021, Oracle and/or its affiliates. All rights reserved.
Connected to: Oracle Database 21c Express Edition Release 21.0.0.0.0 - Production
Starting "APEXDEV"."SYS_EXPORT_SCHEMA_01": apexdev/********@localhost/xepdb1 directory=dump_dir dumpfile=rdf.dmp version=19
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/FUNCTIONAL_INDEX/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type SCHEMA_EXPORT/STATISTICS/MARKER
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/SEQUENCE/SEQUENCE
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Processing object type SCHEMA_EXPORT/TABLE/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type SCHEMA_EXPORT/TABLE/COMMENT
Processing object type SCHEMA_EXPORT/PROCEDURE/PROCEDURE
Processing object type SCHEMA_EXPORT/PROCEDURE/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE
Processing object type SCHEMA_EXPORT/VIEW/VIEW
Processing object type SCHEMA_EXPORT/VIEW/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/INDEX/FUNCTIONAL_INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/REF_CONSTRAINT
Processing object type SCHEMA_EXPORT/VIEW/TRIGGER
. . exported "APEXDEV"."NET1#RDF_LINK$":"MODEL_2" 23.95 KB 219 rows
. . exported "APEXDEV"."NET1#RDF_VALUE$" 23.67 KB 94 rows
. . exported "APEXDEV"."NET1#RDF_RULEBASE$" 6.585 KB 9 rows
. . exported "APEXDEV"."NET1#RDF_CLIQUE$":"MODEL_0" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RDF_COLLISION$" 5.070 KB 1 rows
. . exported "APEXDEV"."NET1#RDF_CRS_URI$" 293.2 KB 5688 rows
. . exported "APEXDEV"."NET1#RDF_DELTA$":"MODEL_0" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RDF_GRANT_INFO$" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RDF_HIST$" 7.328 KB 1 rows
. . exported "APEXDEV"."NET1#RDF_LINK$":"MODEL_0" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RDF_LINK$":"MODEL_1" 12.67 KB 29 rows
. . exported "APEXDEV"."NET1#RDF_MODEL$_TBL" 8.109 KB 1 rows
. . exported "APEXDEV"."NET1#RDF_MODEL_INTERNAL$" 8.093 KB 1 rows
. . exported "APEXDEV"."NET1#RDF_NAMESPACE$" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RDF_NETWORK_INDEX_INTERNAL$" 14.77 KB 12 rows
. . exported "APEXDEV"."NET1#RDF_PARAMETER" 6.492 KB 2 rows
. . exported "APEXDEV"."NET1#RDF_PRECOMP$" 6.828 KB 1 rows
. . exported "APEXDEV"."NET1#RDF_PRECOMP_DEP$" 5.968 KB 3 rows
. . exported "APEXDEV"."NET1#RDF_PRED_STATS$":"MODEL_0" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RDF_PRED_STATS$":"MODEL_1" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RDF_RI_SHAD_2$" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RDF_RULE$" 19.73 KB 20 rows
. . exported "APEXDEV"."NET1#RDF_SYSTEM_EVENT$" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RDF_TERM_STATS$":"MODEL_0" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RDF_TERM_STATS$":"MODEL_1" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RDF_TS$" 0 KB 0 rows
. . exported "APEXDEV"."NET1#RENAMED_APPTAB_RDF_MODEL_ID_1" 0 KB 0 rows
. . exported "APEXDEV"."NET1#SEM_INDEXTYPE_METADATA$" 0 KB 0 rows
Master table "APEXDEV"."SYS_EXPORT_SCHEMA_01" successfully loaded/unloaded
******************************************************************************
Dump file set for APEXDEV.SYS_EXPORT_SCHEMA_01 is:
/home/oracle/rdf.dmp
Job "APEXDEV"."SYS_EXPORT_SCHEMA_01" successfully completed at Thu Dec 2 14:51:29 2021 elapsed 0 00:00:49
$
-- 入れ替える場合は、すでにあるファイルを削除する。
begin
dbms_cloud.delete_file(
directory_name => 'DATA_PUMP_DIR'
, file_name => 'rdf.dmp');
end;
/
begin
dbms_cloud.get_object(
object_uri => 'https://objectstorage.ap-tokyo-1.oraclecloud.com/p/事前承認済のURL/o/rdf.dmp',
directory_name => 'DATA_PUMP_DIR'
);
end;
DECLARE | |
ind NUMBER; -- Loop index | |
h1 NUMBER; -- Data Pump job handle | |
percent_done NUMBER; -- Percentage of job complete | |
job_state VARCHAR2(30); -- To keep track of job state | |
le ku$_LogEntry; -- For WIP and error messages | |
js ku$_JobStatus; -- The job status from get_status | |
jd ku$_JobDesc; -- The job description from get_status | |
sts ku$_Status; -- The status object returned by get_status | |
BEGIN | |
-- Create a (user-named) Data Pump job to do a "full" import (everything | |
-- in the dump file without filtering). | |
h1 := DBMS_DATAPUMP.OPEN( | |
operation => 'IMPORT', | |
job_mode => 'FULL', | |
remote_link => NULL, | |
job_name => 'IMP_APEXDEV' | |
); | |
-- Specify the single dump file for the job (using the handle just returned) | |
-- and directory object, which must already be defined and accessible | |
-- to the user running this procedure. This is the dump file created by | |
-- the export operation in the first example. | |
DBMS_DATAPUMP.ADD_FILE( | |
handle => h1, | |
filename => 'rdf.dmp', | |
directory => 'DATA_PUMP_DIR' | |
); | |
-- A metadata remap will map all schema objects from HR to BLAKE. | |
-- DBMS_DATAPUMP.METADATA_REMAP( | |
-- handle => h1, | |
-- name => 'REMAP_SCHEMA', | |
-- old_value => 'APEXDEV', | |
-- value => 'APEXDEV' | |
-- ); | |
-- If a table already exists in the destination schema, skip it (leave | |
-- the preexisting table alone). This is the default, but it does not hurt | |
-- to specify it explicitly. | |
DBMS_DATAPUMP.SET_PARAMETER( | |
handle => h1, | |
name => 'TABLE_EXISTS_ACTION', | |
value => 'SKIP' | |
); | |
-- Start the job. An exception is returned if something is not set up properly. | |
DBMS_DATAPUMP.START_JOB(h1); | |
-- The import job should now be running. In the following loop, the job is | |
-- monitored until it completes. In the meantime, progress information is | |
-- displayed. Note: this is identical to the export example. | |
percent_done := 0; | |
job_state := 'UNDEFINED'; | |
while (job_state != 'COMPLETED') and (job_state != 'STOPPED') loop | |
dbms_datapump.get_status(h1, | |
dbms_datapump.ku$_status_job_error + | |
dbms_datapump.ku$_status_job_status + | |
dbms_datapump.ku$_status_wip,-1,job_state,sts); | |
js := sts.job_status; | |
-- If the percentage done changed, display the new value. | |
if js.percent_done != percent_done | |
then | |
dbms_output.put_line('*** Job percent done = ' || | |
to_char(js.percent_done)); | |
percent_done := js.percent_done; | |
end if; | |
-- If any work-in-progress (WIP) or Error messages were received for the job, | |
-- display them. | |
if (bitand(sts.mask,dbms_datapump.ku$_status_wip) != 0) | |
then | |
le := sts.wip; | |
else | |
if (bitand(sts.mask,dbms_datapump.ku$_status_job_error) != 0) | |
then | |
le := sts.error; | |
else | |
le := null; | |
end if; | |
end if; | |
if le is not null | |
then | |
ind := le.FIRST; | |
while ind is not null loop | |
dbms_output.put_line(le(ind).LogText); | |
ind := le.NEXT(ind); | |
end loop; | |
end if; | |
end loop; | |
-- Indicate that the job finished and gracefully detach from it. | |
dbms_output.put_line('Job has completed'); | |
dbms_output.put_line('Final job state = ' || job_state); | |
dbms_datapump.detach(h1); | |
END; | |
/ |
Master table "ADMIN"."IMP_APEXDEV" successfully loaded/unloaded
Starting "ADMIN"."IMP_APEXDEV":
Processing object type SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA
Processing object type SCHEMA_EXPORT/SEQUENCE/SEQUENCE
Processing object type SCHEMA_EXPORT/TABLE/TABLE
Table "APEXDEV"."NET1#RENAMED_APPTAB_RDF_MODEL_ID_1" exists. All dependent
metadata and data will be skipped due to table_exists_action of skip
Processing object type SCHEMA_EXPORT/TABLE/TABLE_DATA
. . imported "APEXDEV"."NET1#RDF_LINK$":"MODEL_2" 23.95 KB 219 rows
. . imported "APEXDEV"."NET1#RDF_VALUE$" 23.67 KB 94 rows
*** Job percent done = 32
. . imported "APEXDEV"."NET1#RDF_RULEBASE$" 6.585 KB 9 rows
. . imported "APEXDEV"."NET1#RDF_CLIQUE$":"MODEL_0" 0 KB 0 rows
. . imported "APEXDEV"."NET1#RDF_COLLISION$" 5.070 KB 1 rows
*** Job percent done = 99
. . imported "APEXDEV"."NET1#RDF_CRS_URI$" 293.2 KB 5688 rows
. . imported "APEXDEV"."NET1#RDF_DELTA$":"MODEL_0" 0 KB 0 rows
. . imported "APEXDEV"."NET1#RDF_GRANT_INFO$" 0 KB 0 rows
. . imported "APEXDEV"."NET1#RDF_HIST$" 7.328 KB 1 rows
. . imported "APEXDEV"."NET1#RDF_LINK$":"MODEL_0" 0 KB 0 rows
. . imported "APEXDEV"."NET1#RDF_LINK$":"MODEL_1" 12.67 KB 29 rows
. . imported "APEXDEV"."NET1#RDF_MODEL$_TBL" 8.109 KB 1 rows
. . imported "APEXDEV"."NET1#RDF_MODEL_INTERNAL$" 8.093 KB 1 rows
. . imported "APEXDEV"."NET1#RDF_NAMESPACE$" 0 KB 0 rows
. . imported "APEXDEV"."NET1#RDF_NETWORK_INDEX_INTERNAL$" 14.77 KB 12 rows
. . imported "APEXDEV"."NET1#RDF_PARAMETER" 6.492 KB 2 rows
. . imported "APEXDEV"."NET1#RDF_PRECOMP$" 6.828 KB 1 rows
. . imported "APEXDEV"."NET1#RDF_PRECOMP_DEP$" 5.968 KB 3 rows
. . imported "APEXDEV"."NET1#RDF_PRED_STATS$":"MODEL_0" 0 KB 0 rows
. . imported "APEXDEV"."NET1#RDF_PRED_STATS$":"MODEL_1" 0 KB 0 rows
. . imported "APEXDEV"."NET1#RDF_RI_SHAD_2$" 0 KB 0 rows
. . imported "APEXDEV"."NET1#RDF_RULE$" 19.73 KB 20 rows
. . imported "APEXDEV"."NET1#RDF_SYSTEM_EVENT$" 0 KB 0 rows
. . imported "APEXDEV"."NET1#RDF_TERM_STATS$":"MODEL_0" 0 KB 0 rows
. . imported "APEXDEV"."NET1#RDF_TERM_STATS$":"MODEL_1" 0 KB 0 rows
. . imported "APEXDEV"."NET1#RDF_TS$" 0 KB 0 rows
. . imported "APEXDEV"."NET1#SEM_INDEXTYPE_METADATA$" 0 KB 0 rows
Processing object type SCHEMA_EXPORT/TABLE/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type SCHEMA_EXPORT/PROCEDURE/PROCEDURE
ORA-31684: Object type PROCEDURE:"APEXDEV"."NET1#SDO_RDF_PROC_DR_TRUNC_1"
already exists
Processing object type SCHEMA_EXPORT/PROCEDURE/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type SCHEMA_EXPORT/PROCEDURE/ALTER_PROCEDURE
ORA-39111: Dependent object type
ALTER_PROCEDURE:"APEXDEV"."NET1#SDO_RDF_PROC_DR_TRUNC_1" skipped, base object
type PROCEDURE:"APEXDEV"."NET1#SDO_RDF_PROC_DR_TRUNC_1" already exists
Processing object type SCHEMA_EXPORT/VIEW/VIEW
ORA-31684: Object type VIEW:"APEXDEV"."FAMILY_RDF_DATA" already exists
Processing object type SCHEMA_EXPORT/VIEW/GRANT/OWNER_GRANT/OBJECT_GRANT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/INDEX/FUNCTIONAL_INDEX/INDEX
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT
Processing object type SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS
Processing object type
SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/FUNCTIONAL_INDEX/INDEX_STATISTICS
Processing object type SCHEMA_EXPORT/TABLE/CONSTRAINT/REF_CONSTRAINT
Processing object type SCHEMA_EXPORT/VIEW/TRIGGER
Processing object type SCHEMA_EXPORT/TABLE/STATISTICS/TABLE_STATISTICS
Processing object type SCHEMA_EXPORT/STATISTICS/MARKER
ORA-39082: Object type TRIGGER:"APEXDEV"."NET1#SDO_RDF_TRIG_AVIEW_1" created
with compilation warnings
*** Job percent done = 100
Job "ADMIN"."IMP_APEXDEV" completed with 4 error(s) at Thu Dec 2 06:54:12 2021
elapsed 0 00:00:25
Job has completed
Final job state = COMPLETED
PL/SQL procedure successfully completed.
Elapsed: 00:00:31.075
APEXアプリケーションの作成
declare | |
term varchar2(4000); | |
vid number; | |
begin | |
term := ''; | |
vid := sem_apis.res2vid('NET1#RDF_VALUE$', term); | |
:P1_TERM := term; | |
:P1_VID := vid; | |
end; |
- DataPumpを使ったエクスポート/インポートを行う際に、ローカルのデータベースとAutonomous Databaseでバージョンを合わせていませんでした。ローカルが21c、Autonomous Databaseは19cです。しかし、19cのExpress Editionはリリースされていないので、21cか18cかの選択になります。ライセンスを購入している場合は19cを使うと良いかと思います。MDSYS.SDO_RDFパッケージに含まれるプロシージャに違いがあるようです。
- やはりDataPumpでのデータ移行は強引なので(当然、サポートもされない)、Autonomous Databaseではユーザーがルールベースを追加することはできない前提でRDFナレッジ・グラフを使うのが妥当と言えます。