2024年12月13日 (金)

実行計画は, SQL文のレントゲン写真だ! No.65 / JPOUG Advent Calendar 2024 / JSON-Relational Duality Views

本エントリーは、13日の金曜日のエントリーです。
昨日のポストは、Takayuki Nishio (Nisshii0)さんの「[Oracle] ここが違うよ Autonomous Database! 初めてデータ移行して気づいたこと」でした。




ということで、私のターン。

皆様の期待通り?、13日の金曜日なので、JSON を取り上げておきたいと思います。(実は元々別のながーーーいネタを用意していたのですが、13日の金曜日であることに気づきwww 以下略)
Oracle Database のJSON関連機能について、すでに多くの方がブログ等で書かれていることもあり、本エントリーでは、Mac De Oracleっぽくw、実行計画という名のレントゲン写真はどうなのかw を診ておきたいと思います。


Stable Diffusion WebUI
20241206-131544

対象とするのは、JSON-Relational Duality Views です。
この機能、名前の通り、リレーショナル表のままで、JSONにマッピングするVIEWを通して使えるようにしたものでOracle Database 23aiの新機能の一つです。(雑に解説すると。。)

気になりますよね。JSON-Relational Duality Viewsを介してアクセスした場合の実行計画!!!!

ちょっとわき道に逸れるのですが、Oracle Databaseには、RDFView という機能があります。リレーショナル表のままで、RDF Graphのトリプルとして参照する機能ですよね。これまた雑に解説すると。

実行計画は,SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 おまけ#3
トリプルとして扱うために、対象の列毎にSELECT文を作る必要がありかつ3列なのでUNIONも必要で、という想像通りのなかなかのレントゲン写真(実行計画でした)。
Rdfview


果たして、JSON-Relational Duality Views ではどうなるのか。。。。

早速、試してみましょう。

23aiを利用しています。

COTT@localhost:1521/freepdb1> select banner_full from v$version;

BANNER_FULL
--------------------------------------------------------------------------------
Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.4.0.24.05


まず、JSON-Relational Duality ViewsはViewなので元になるリレーショナル表を決めちゃいます。dept表をもとにして department表を作って使いましょう。 dept表のままでも良いのですけどもw

SCOTT@localhost:1521/freepdb1> set linesize 80
SCOTT@localhost:1521/freepdb1> desc dept
Name Null? Type
----------------------------------------- -------- ----------------------------
DEPTNO NOT NULL NUMBER(2)
DNAME VARCHAR2(14)
LOC VARCHAR2(13)

SCOTT@localhost:1521/freepdb1> select * from dept;

DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON

SCOTT@localhost:1521/freepdb1> create table department as select * from dept;

Table created.

SCOTT@localhost:1521/freepdb1> alter table department add constraint pk_department primary key (deptno) using index;

Table altered.


department表の列をJSONのキーにマップしちゃうだけ(おまけで, UPDATE/INSERT/DELETEも許可していますが、今回はSELECTしかしませんw)
JSON RELATIONAL DUALITY VIEWを作成します。(見ると リレーショナル表の列とJSONのキーをマップしているだけですね。シンプル)

SCOTT@localhost:1521/freepdb1> l
1 CREATE JSON RELATIONAL DUALITY VIEW department_dv
2 AS
3 SELECT
4 JSON { '_id' : d.deptno,
5 'departmentName' : d.dname,
6 'location' : d.loc }
7 FROM
8 department d
9* WITH UPDATE INSERT DELETE
SCOTT@localhost:1521/freepdb1> /

View created.

SCOTT@localhost:1521/freepdb1> select collection_name,collection_type from user_json_collections;

COLLECTION_NAME COLLECTION_T
------------------------------ ------------
DEPARTMENT_DV DUALITY VIEW

SCOTT@localhost:1521/freepdb1> set linesize 400
COTT@localhost:1521/freepdb1> select * from user_json_duality_views;

VIEW_NAME JSON ROOT_TABLE_NAME ROOT_TABLE_OWNER ALLOW_INSER ALLOW_UPDAT ALLOW_DELET READ_ONLY JSON_SCHEMA STATUS
------------------------------ ---- ------------------------------ ------------------------------ ----------- ----------- ----------- ----------- ------------------------------ -------
DEPARTMENT_DV DATA DEPARTMENT SCOTT TRUE TRUE TRUE FALSE {"title":"DEPARTMENT_DV","dbOb VALID
ject":"SCOTT.DEPARTMENT_DV","d
bObjectType":"dualit


特に何も指定せず問い合わせると、まんまのJSONが返されます。

SCOTT@localhost:1521/freepdb1> set long 4000
SCOTT@localhost:1521/freepdb1> set longchunk 4000
SCOTT@localhost:1521/freepdb1> set linesize 400
SCOTT@localhost:1521/freepdb1> select * from department_dv;

DATA
--------------------------------------------------------------------------------------------------------------------------------------------------
{"_id":10,"_metadata":{"etag":"66F269F721C734BAE74D56D6A948D0F6","asof":"0000000001799313"},"departmentName":"ACCOUNTING","location":"NEW YORK"}
{"_id":20,"_metadata":{"etag":"8A0701C115BFECAB64C34E2FF406FFDA","asof":"0000000001799313"},"departmentName":"RESEARCH","location":"DALLAS"}
{"_id":30,"_metadata":{"etag":"A7CDA588F9052B35B56E00BB22B6EC6F","asof":"0000000001799313"},"departmentName":"SALES","location":"CHICAGO"}
{"_id":40,"_metadata":{"etag":"93AE902896310C0DFFCE3FC70E0479F6","asof":"0000000001799313"},"departmentName":"OPERATIONS","location":"BOSTON"}


さて、table full scanになると思いますが、とりあえず見てみましょう。

SCOTT@localhost:1521/freepdb1> set autot trace exp stat
SCOTT@localhost:1521/freepdb1> select * from department_dv;

Elapsed: 00:00:00.03

Execution Plan
----------------------------------------------------------
Plan hash value: 826413278

--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 80 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| DEPARTMENT | 4 | 80 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
1469 bytes sent via SQL*Net to client
473 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
4 rows processed

SCOTT@localhost:1521/freepdb1> set autot off
SCOTT@localhost:1521/freepdb1> set linesize 80
SCOTT@localhost:1521/freepdb1> desc department_dv
Name Null? Type
----------------------------------------- -------- ----------------------------
DATA JSON

SCOTT@localhost:1521/freepdb1> set linesize 400
SCOTT@localhost:1521/freepdb1> col _id for a30
SCOTT@localhost:1521/freepdb1> col departmentName for a30
SCOTT@localhost:1521/freepdb1> col location for a30

...略...

リレーショナル表っぽいクエリーにもできます。

SCOTT@localhost:1521/freepdb1> r
1 select d.data."_id",
2 d.data."departmentName",
3 d.data."location"
4 from department_dv d
5* order by 1

_id departmentName location
------------------------------ ------------------------------ ------------------------------
10 "ACCOUNTING" "NEW YORK"
20 "RESEARCH" "DALLAS"
30 "SALES" "CHICAGO"
40 "OPERATIONS" "BOSTON"

では、次に、主キーにマップした _id 列でアクセスしてみましょう。おおおおお、普通に、INDEX UQNIQE SCANでしたね。(想像していた通りですがw)
Predicate Information に現れるアクセスパスを見ると、 access("D"."DEPTNO"=30) となっており、内部的にはリレーショナル表を問い合わせるSQL文に書き換えられているように見えますよね(まだ調べていないですがw)

SCOTT@localhost:1521/freepdb1> set autot trace exp stat
SCOTT@localhost:1521/freepdb1> select json_serialize(d.data pretty) from department_dv d where d.data."_id" = 30;

Elapsed: 00:00:00.01

Execution Plan
----------------------------------------------------------
Plan hash value: 3132674683

---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 20 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| DEPARTMENT | 1 | 20 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_DEPARTMENT | 1 | | 0 (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("D"."DEPTNO"=30)


Statistics
----------------------------------------------------------
8 recursive calls
0 db block gets
5 consistent gets
0 physical reads
0 redo size
782 bytes sent via SQL*Net to client
108 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

SCOTT@localhost:1521/freepdb1> set autot off
SCOTT@localhost:1521/freepdb1> r
1* select json_serialize(d.data pretty) from department_dv d where d.data."location" = 'CHICAGO'

JSON_SERIALIZE(D.DATAPRETTY)
----------------------------------------------------------------------------------------------------
{
"_id" : 30,
"_metadata" :
{
"etag" : "A7CDA588F9052B35B56E00BB22B6EC6F",
"asof" : "0000000001799BF8"
},
"departmentName" : "SALES",
"location" : "CHICAGO"
}

...略...

SCOTT@localhost:1521/freepdb1> r
1 select
2 d.data."_id" as deptno
3 , d.data."departmentName" as department_name
4 , d.data."location" as location
5 from
6 department_dv d
7 where
8* d.data."location" = 'CHICAGO'

DEPTNO DEPARTMENT_NAME LOCATION
------------------------------ ------------------------------ ------------------------------
30 "SALES" "CHICAGO"


JSON-Relational Duality Viewsから問い合わせてもリレーショナル表を直接問い合わせるのと同じなんですねぇ。なんとなく安心w

13日の金曜日のJSONネタなので、恐ろしーい結果を期待していた方、ごめんなさいwwww JSON怖くないですw


明日のJPOUG Advent Calendar 2024は、ketsujiさんです。




Related article on Mac De Oracle

実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 1 / TABLE FULL SCAN
実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 2 / INDEX UNIQUE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 3 / INDEX RANGE SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 4 / INDEX RANGE SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 5 / INDEX RANGE SCAN, INLIST ITERATOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 6 / INDEX FAST SCAN, Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 7 / INDEX FULL SCAN,Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 8 / INDEX SKIP SCAN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 9 / TABLE ACCESS INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 10 / NESTED LOOP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 11 / MERGE JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 12 / HASH JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 13 / HASH JOIN OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 14 / HASH JOIN FULL OUTER
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 15 / PX, TABLE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 16 / CONCATENATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 17 / SORT UNIQUE, UNION-ALL = UNION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 18 / UNION-ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 19 / INTERSECTION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 20 / MINUS
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 21 / WINDOW NOSORT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 22 / COUNT STOPKEY
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 23 / HASH JOIN - LEFT-DEEP JOIN vs RIGHT-DEEP JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 24 / CONNECT BY NO FILTERING WITH START-WITH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - Day 25 / UNION ALL (RECURSIVE WITH) DEPTH FIRST, RECURSIVE WITH PUMP
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#1 / STAR TRANSFORM, VECTOR TRANSFORM (DWH向け)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#2 / MERGE (UPSERT)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#3 / RDFView
・実行計画は, SQL文のレントゲン写真だ! Oracle Database編 (全部俺)Advent Calendar 2019 - おまけ#4 / INDEX FULL SCAN (MIN/MAX) - Index Only Scan
・実行計画は, SQL文のレントゲン写真だ! No.30 - LOAD TABLE CONVENTIONAL vs. LOAD AS SELECT
・実行計画は, SQL文のレントゲン写真だ! No.31 - TEMP TABLE TRANSFORMATION LOAD AS SELECT (CURSOR DURATION MEMORY)
・実行計画は, SQL文のレントゲン写真だ! No.32 - EXTERNAL TABLE ACCESS FULL / INMEMORY FULL
・実行計画は, SQL文のレントゲン写真だ! No.33 - BITMAP CONVERSION TO ROWIDS
・実行計画は, SQL文のレントゲン写真だ! No.34 - 似て非なるもの USE_CONCAT と OR_EXPAND ヒント と 手書きSQLのレントゲンの見分け方
・実行計画は, SQL文のレントゲン写真だ! No.35 - 似て非なるもの USE_CONCAT と OR_EXPANDヒントとパラレルクエリー
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 1 / No.36 / INTERSECT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 2 / No.37 / MINUS ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 3 / No.38 / EXCEPT and EXCEPT ALL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 4 / No.39 / In-Memory Hybrid Scans
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 5 / No.40 / PIVOT and UNPIVOT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 6 / No.41 / In-Memory Vectorized Join
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 7 / No.42 / INDEX RANGE SCAN (MULTI VALUE)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 8 / No.43 / TABLE ACCESS BY INDEX ROWID BATCHED
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 9 / No.44 / COLLECTION ITERATOR PICKLER FETCH
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 10 / No.45 / MAT_VIEW REWRITE ACCESS FULL
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 11 / No.46 / GROUPING SETS, ROLLUP, CUBE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 12 / No.47 / TEMP TABLE TRANSFORMATION
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 13 / No.48 / MULTI-TABLE INSERT
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 14 / No.49 / the DUAL Table
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 15 / No.50 / REMOTE
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 16 / No.51 / Concurrent Execution of Union All and Union
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 17 / No.52 / Order by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 18 / No.53 / Join Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 19 / No.54 / Group by Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 20 / No.55 / DISTINCT Elimination
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 21 / No.56 / INLIST ITERATOR と Sub Query と STATISTICS COLLECTOR
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 22 / No.57 / Subquery Unnesting
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 23 / No.58 / ANTI JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 24 / No.59 / SQL MACRO (19.7〜)
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 Day 25 / No.60 / ANSI JOIN
・実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 / No.60 / ANSI JOINのおまけ
実行計画は, SQL文のレントゲン写真だ! Oracle Database (全部俺)Advent Calendar 2022 / No.61 / ANSI JOINのおまけのおまけ
実行計画は, SQL文のレントゲン写真だ! No.62 / ORDBMS機能であるコレクション型の列をアクセスする実行計画ってどうなるの?
実行計画は, SQL文のレントゲン写真だ! No.63 / Join Elimination (再び)その1
実行計画は, SQL文のレントゲン写真だ! No.63 / Join Elimination (再び)その2
実行計画は, SQL文のレントゲン写真だ! No.63 / Join Elimination (再び)その3
実行計画は, SQL文のレントゲン写真だ! No.64 / 先生、私のLEFT OUTER JOINが無いんです!!(Join Elimination番外編

| | | コメント (0)

2019年12月29日 (日)

RDFナレッジ・グラフ / 備忘録 19c

5年ぐらい前に触ったことがある程度で、すっかり忘れてしまった。しばらくぶりで思い出してパタパタしてみたら、Apache Jenaも含めていろいろ変わっていたので備忘録

RDFナレッジ・グラフ開発者ガイド RDFナレッジ・グラフの概要

R2RML: RDB to RDF Mapping Language

A Direct Mapping of Relational Data to RDF

いろいろ思い出しながら....

$ sqlplus sys@orclcdb as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Sat Dec 28 00:51:52 2019
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle. All rights reserved.

Enter password:

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

SQL> col namespace for a30
SQL> col value for a40
SQL> col description for a50
SQL> set linesize 400
SQL> set tab off
SYS@orclcdb> select * from MDSYS.RDF_PARAMETER;

NAMESPACE ATTRIBUTE VALUE DESCRIPTION
------------------- ----------------- ------------- --------------------------------------------------
COMPONENT RDFCTX INSTALLED Semantic (Text) Search component
COMPONENT RDFOLS INSTALLED RDF Optional component for OLS support
MDSYS SEM_VERSION 19.1.0.0.0 VALID

SYS@orclcdb> r
1 SELECT namespace, attribute, value FROM mdsys.rdf_parameter
2 WHERE namespace='MDSYS'
3 AND attribute IN ('FLOAT_DOUBLE_DECIMAL',
4 'XSD_TIME', 'XSD_BOOLEAN',
5* 'DATA_CONVERSION_CHECK')

no rows selected

SYS@orclcdb> conn system@orcl
Enter password:
Connected.
SYSTEM@orcl> create tablespace rdf_users datafile 'rds_users01.dbf' size 128m reuse autoextend on next 64m maxsize unlimited segment space management auto;

Tablespace created.

SYSTEM@orcl> create user rdfuser identified by hogehoge default tablespace rdf_users temporary tablespace temp;

User created.

SYSTEM@orcl> grant create view to rdfuser;

Grant succeeded.

SYSTEM@orcl> grant unlimited tablespace to rdfuser;

Grant succeeded.

SYSTEM@orcl> grant unlimited tablespace to mdsys;

Grant succeeded.

SYSTEM@orcl> grant select any dictionary to rdfuser;

Grant succeeded.

SYSTEM@orcl> grant connect, resource to rdfuser;

Grant succeeded.

SYSTEM@orcl> execute sem_apis.create_sem_network('RDF_USERS', network_owner=>'RDFUSER', network_name=>'LOCALNET');

PL/SQL procedure successfully completed.


SYSTEM@orcl> conn rdfuser@orcl
Enter password:
Connected.
RDFUSER@orcl>

RDFUSER@orcl> l
1 create table r2rmlview_nt_staging_tab (
2 rdf$stc_sub varchar2(4000) not null
3 ,rdf$stc_pred varchar2(4000) not null
4 ,rdf$stc_obj varchar2(4000) not null
5 )
6* nologging
RDFUSER@orcl> /

Table created.

RDFUSER@orcl> l
1 create table rdfview_export_tab (
2 rdf$stc_sub varchar2(4000) not null
3 ,rdf$stc_pred varchar2(4000) not null
4 ,rdf$stc_obj varchar2(4000) not null
5 )
6* nologging
RDFUSER@orcl> /

Table created.

RDFでいろいろやるには sga_targetやsga_max_sizeはそれなりに必要なので適当に調整

そして、Apache Jenaのrdfcatもdeprecatedになってて、これまたしばし時代に追いつく作業を....

RDFUSER@orcl> !rdfcat --help
------------------------------------------------------------------
DEPRECATED: Please use 'riot' instead.
http://jena.apache.org/documentation/io/#command-line-tools
------------------------------------------------------------------

------------------------------------
DEPRECATED: Please use riot instead.
------------------------------------

Usage: java jena.rdfcat (option|input)*
Concatenates the contents of zero or more input RDF documents.
Options: -out N3 | N-TRIPLE | RDF/XML | RDF/XML-ABBREV
-n expect subsequent inputs in N3 syntax
-x expect subsequent inputs in RDF/XML syntax
-t expect subsequent inputs in N-TRIPLE syntax
-[no]include include rdfs:seeAlso and owl:imports
input can be filename, URL, or - for stdin
Recognised aliases for -n are: -n3 -ttl or -N3
Recognised aliases for -x are: -xml -rdf or -rdfxml
Recognised aliases for -t are: -ntriple
Output format aliases: x, xml or rdf for RDF/XML, n, n3 or ttl for N3, t or ntriple for N-TRIPLE
See the Javadoc for jena.rdfcat for additional details.

rdfcatに変えて、riot ってやつをつかわなきゃいけなくなったっぽい。

RDFUSER@orcl> !riot -version
Jena: VERSION: 3.13.1
Jena: BUILD_DATE: 2019-10-06T18:57:39+0000
RIOT: VERSION: 3.13.1
RIOT: BUILD_DATE: 2019-10-06T18:57:39+0000

ちなみに、SHユーザのEMPLOYEES表や索引をRDFUSERユーザへコピーした上で、以下のような、RDFVIEWとRelational表と列のマッピングをTurtle (Terse RDF Triple Language)で定義した。

RDFUSER@orcl> !cat test_real_rdf_r2rml.ttl
@prefix rr: .
@prefix xsd: .
@prefix ex: .

ex:TriplesMap_Employees
rr:logicalTable [ rr:tableName "EMPLOYEES" ];
rr:subjectMap [
rr:template "http://r2rml.com/employees/{EMPLOYEE_ID}";
rr:class ex:Employees;
];

rr:predicateObjectMap [
rr:predicate ex:FirstName;
rr:objectMap [ rr:column "FIRST_NAME" ];
];

rr:predicateObjectMap [
rr:predicate ex:LastName;
rr:objectMap [ rr:column "LAST_NAME" ];
];

rr:predicateObjectMap [
rr:predicate ex:ManagerId;
rr:objectMap [ rr:column "MANAGER_ID" ];
].

5年ぐらい前の記憶ではrdfcatを利用して変換していたが、今は、 riot というコマンドを利用してTurtle(Terse RDF Triple Language)N-Triplesへ変換するみたいね。

RDFUSER@orcl> !riot --out=N-TRIPLE test_real_rdf_r2rml.ttl > test_real_rdf_r2rml_use_riot.nt

RDFUSER@orcl> !cat test_real_rdf_r2rml_use_riot.nt
_:Bf70c7f0d1b418dc63ad89dbcea313cd1 "EMPLOYEES" .
_:Bf70c7f0d1b418dc63ad89dbcea313cd1 .
_:Bdd4cf5eb9ecb0b12212d342518513827 "http://r2rml.com/employees/{EMPLOYEE_ID}" .
_:Bdd4cf5eb9ecb0b12212d342518513827 .
_:Bdd4cf5eb9ecb0b12212d342518513827 .
_:B310abfde7d61aac8f303fbd1f4ba5db8 .
_:Bfe48b8372e4da59d0ce99e0e24b894ad "FIRST_NAME" .
_:B310abfde7d61aac8f303fbd1f4ba5db8 _:Bfe48b8372e4da59d0ce99e0e24b894ad .
_:B310abfde7d61aac8f303fbd1f4ba5db8 .
_:B11c76919901c01b44cb0e2507a997c28 .
_:B5474fc7a1b7c7302521175dac3c58028 "LAST_NAME" .
_:B11c76919901c01b44cb0e2507a997c28 _:B5474fc7a1b7c7302521175dac3c58028 .
_:B11c76919901c01b44cb0e2507a997c28 .
_:Be7008cecff6b130ea15b4ba060cee0fb .
_:B0f41936e13c4655082ee47f866dc9f61 "MANAGER_ID" .
_:Be7008cecff6b130ea15b4ba060cee0fb _:B0f41936e13c4655082ee47f866dc9f61 .
_:Be7008cecff6b130ea15b4ba060cee0fb .


SQL*Loaderを使用したステージング表へのN-Triple形式のデータのロードを参考

RDFUSER@orcl> !cat test_real_rdf_r2rml_nt_load.ctl
UNRECOVERABLE
LOAD DATA
TRUNCATE
into table r2rmlview_nt_staging_tab
when (1) <> '#'
(
RDF$STC_sub CHAR(4000) terminated by whitespace
"(
CASE
WHEN substr(:RDF$STC_sub,1,1)='<' AND substr(:RDF$STC_sub,-1,1)='>' AND
length(:RDF$STC_sub)>2
THEN :RDF$STC_sub
WHEN substr(:RDF$STC_sub,1,2)='_:' AND
REGEXP_LIKE(:RDF$STC_sub,'^(_:)[[:alpha:]][[:alnum:]]*$')
THEN :RDF$STC_sub
WHEN substr(:RDF$STC_sub,1,1) NOT IN ('\"','<','#') AND
substr(:RDF$STC_sub,-1,1) NOT IN ('\"','>')
THEN ('<' || SDO_RDF.replace_rdf_prefix(:RDF$STC_sub) || '>')
WHEN substr(:RDF$STC_sub,1,1)='#'
THEN SDO_RDF.raise_parse_error(
'Ignored Comment Line starting with ', :RDF$STC_sub)
ELSE SDO_RDF.raise_parse_error('Invalid Subject', :RDF$STC_sub)
END
)",
RDF$STC_pred CHAR(4000) terminated by whitespace
"(
CASE
WHEN substr(:RDF$STC_pred,1,1)='<' AND substr(:RDF$STC_pred,-1,1)='>' AND
length(:RDF$STC_pred)>2
THEN :RDF$STC_pred
WHEN substr(:RDF$STC_pred,1,2) != '_:' AND
substr(:RDF$STC_pred,1,1) NOT IN ('\"','<') AND
substr(:RDF$STC_pred,-1,1) NOT IN ('\"','>')
THEN ('<' || SDO_RDF.replace_rdf_prefix(:RDF$STC_pred) || '>')
ELSE SDO_RDF.raise_parse_error('Invalid Predicate', :RDF$STC_pred)
END
)",
--
-- right-trimming of WHITESPACEs is reqd for "RDF$STC_obj"
-- (due to absence of "TERMINATED BY WHITESPACE")
--
-- For ease of editing below replace
-- "rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13))" with ":xy".
-- and then replace back
--
RDF$STC_obj CHAR(4000)
"(
CASE
WHEN substr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),1,1)='<' AND
substr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),-1,1)='>' AND
length(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)))>2
THEN rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13))
WHEN substr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),1,1)='\"' AND
substr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),-1,1)='\"' AND
length(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)))>1
THEN rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13))
WHEN substr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),1,2)='_:' AND
REGEXP_LIKE(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),
'^(_:)[[:alpha:]][[:alnum:]]*$')
THEN rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13))
WHEN substr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),1,1)
NOT IN ('\"','<') AND
substr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),-1,1)
NOT IN ('\"','>')
THEN ('<' ||
SDO_RDF.replace_rdf_prefix(
rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13))) ||
'>')
WHEN substr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),1,1)='\"' AND
substr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),-1,1)
NOT IN ('\"','>') AND
instr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),'\"\@',-1)>1 AND
REGEXP_LIKE(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),
'^\"[[:print:]]*\"\@[[:alpha:]]+(-[[:alnum:]]+)*$')
THEN rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13))
WHEN (substr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),1,1)='\"' AND
instr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),'\"^^',-1)>1 AND
(length(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)))-
(instr(rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)),'\"^^',-1)+4)
)>0)
THEN SDO_RDF.pov_typed_literal(
rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)))
ELSE SDO_RDF.raise_parse_error(
'Invalid Object', rtrim(:RDF$STC_obj,'. '||CHR(9)||CHR(10)||CHR(13)))
END
)"
)

RDFUSER@orcl> exit


$ sqlldr userid=rdfuser@orcl control=test_real_rdf_r2rml_nt_load.ctl data=test_real_rdf_r2rml_use_riot.nt direct=true skip=0 load=1000000 discardmax=0 bad=test_real_rdf_r2rml_nt_load.bad discard=test_real_rdf_r2rml_nt_load.rej log=test_real_rdf_r2rml_nt_load.log errors=1000000
Password:

SQL*Loader: Release 19.0.0.0.0 - Production on Sat Dec 28 02:05:44 2019
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle and/or its affiliates. All rights reserved.

Path used: Direct, LOAD=1000000

Load completed - logical record count 17.

Table R2RMLVIEW_NT_STAGING_TAB:
17 Rows successfully loaded.

Check the log file:
test_real_rdf_r2rml_nt_load.log
for more information about the load.

そして、SEM_MATCH()関数を利用してモデルと問い合わせると....

RDFUSER@orcl> @test_real_rdf_cre_rdfview.sql

PL/SQL procedure successfully completed.

RDFUSER@orcl> l
1 SELECT
2 s
3 , p
4 , o
5 FROM
6 TABLE (
7 SEM_MATCH (
8 '{?s ?p ?o}'
9 , SEM_MODELS('TEST_MODEL1')
10 , null
11 , null
12 , null
13 , null
14 , ' '
15 , null
16 , null
17 , 'RDFUSER'
18 , 'LOCALNET'
19 )
20 )
21 ORDER BY
22 s
23 ,p
24*
RDFUSER@orcl>
RDFUSER@orcl> @test_query_rdfview.sql

S P O
---------------------------------------- -------------------------------------------------- ----------------------------------------
http://r2rml.com/employees/100 http://r2rml.com/ns#FirstName Steven
http://r2rml.com/employees/100 http://r2rml.com/ns#LastName King
http://r2rml.com/employees/100 http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://r2rml.com/ns#Employees
http://r2rml.com/employees/101 http://r2rml.com/ns#FirstName Neena
http://r2rml.com/employees/101 http://r2rml.com/ns#LastName Kochhar
http://r2rml.com/employees/101 http://r2rml.com/ns#ManagerId 100
http://r2rml.com/employees/101 http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://r2rml.com/ns#Employees
http://r2rml.com/employees/102 http://r2rml.com/ns#FirstName Lex
http://r2rml.com/employees/102 http://r2rml.com/ns#LastName De Haan
http://r2rml.com/employees/102 http://r2rml.com/ns#ManagerId 100

・・・中略・・・

http://r2rml.com/employees/205 http://r2rml.com/ns#FirstName Shelley
http://r2rml.com/employees/205 http://r2rml.com/ns#LastName Higgins
http://r2rml.com/employees/205 http://r2rml.com/ns#ManagerId 101
http://r2rml.com/employees/205 http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://r2rml.com/ns#Employees
http://r2rml.com/employees/206 http://r2rml.com/ns#FirstName William
http://r2rml.com/employees/206 http://r2rml.com/ns#LastName Gietz
http://r2rml.com/employees/206 http://r2rml.com/ns#ManagerId 205
http://r2rml.com/employees/206 http://www.w3.org/1999/02/22-rdf-syntax-ns#type http://r2rml.com/ns#Employees

| | | コメント (0)