8 RDF Views: Relational Data as RDF
You can create and use RDF views over relational data in Oracle Spatial and Graph RDF Semantic Graph.
Relational data is viewed as virtual RDF triples using one of the two forms of RDB2RDF mapping described in W3C documents on Direct Mapping and R2RML mapping:
-
R2RML: RDB to RDF Mapping Language, W3C Recommendation (
http://www.w3.org/TR/r2rml/
) -
A Direct Mapping of Relational Data to RDF, W3C Recommendation (
http://www.w3.org/TR/rdb-direct-mapping/
)
- Why Use RDF Views on Relational Data?
Using RDF views on relational data enables you to integrate data available from different sources. - API Support for RDF Views
Subprograms are included in the SEM_APIS package for creating, dropping, and exporting (that is, materializing the content of) RDF views. - Example: Using an RDF View with Direct Mapping
This topic provides an example of using an RDF view with direct mapping. - Combining Native RDF Data with Virtual RDB2RDF Data
You can combine native triple data with virtual RDB2RDF triple data in a single SEM_MATCH query by means of the SERVICE keyword.
Parent topic: Conceptual and Usage Information
8.1 Why Use RDF Views on Relational Data?
Using RDF views on relational data enables you to integrate data available from different sources.
You can exploit the advantages of relational data without the need for physical storage of the RDF triples that correspond to the relational data. Before RDF views were included in RDF Semantic Graph in Oracle Database 12c Release 1 (12.1), you needed to write custom SQL queries or use non-standard mappings and physically store the generated RDF triples in an RDF model.
The simplest way to create a mapping of relational data to RDF data is by calling the SEM_APIS.CREATE_RDFVIEW_MODEL procedure to create an RDF view and supplying the list of tables or views whose content you would like to be viewed as RDF. This provides a direct mapping of those relational tables or views.
To get a more customized mapping, you can write an R2RML mapping document (in RDF using Turtle, for example) to specify the desired mapping, load the mapping document (after converting it to N-Triple format) into a staging table (for the table definition, see Bulk Loading Semantic Data Using a Staging Table), and then call the SEM_APIS.CREATE_RDFVIEW_MODEL procedure to create an RDF view by supplying the name of the staging table.
In addition, as an alternative to the staging table-based strategy, you can supply the R2RML mapping (using Turtle or N-Triple syntax) directly to SEM_APIS.CREATE_RDFVIEW_MODEL with the r2rml_string
parameter.
Parent topic: RDF Views: Relational Data as RDF
8.2 API Support for RDF Views
Subprograms are included in the SEM_APIS package for creating, dropping, and exporting (that is, materializing the content of) RDF views.
An RDF view is created as an RDF model, but the RDF model physically contains only metadata. The actual data is still stored in the relational tables for which the RDF view has been created. (The SEM_APIS subprograms are documented in SEM_APIS Package Subprograms.)
For the examples in the rest of this section, assume that the following relational tables exist in the invoker's schema:
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) );
Note that if these tables are in a different schema (for example, SCOTT
) than the invoker's, when specifying the names of these tables, you need to use schema-qualified table names: "SCOTT"."DEPT"
and "SCOTT"."EMP"
.
- Creating an RDF View with Direct Mapping
- Creating an RDF View with an R2RML Mapping
- Dropping an RDF View
- Exporting Virtual Content of an RDF View into a Staging Table
Parent topic: RDF Views: Relational Data as RDF
8.2.1 Creating an RDF View with Direct Mapping
Example 8-1 creates an RDF view model using direct mapping of two tables, EMP and DEPT, with a base prefix of http://empdb/
. The (virtual) RDF terms are generated according to A Direct Mapping of Relational Data to RDF, W3C Recommendation (http://www.w3.org/TR/rdb-direct-mapping/
).
Example 8-1 Creating an RDF View with Direct Mapping
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; /
To see the properties that are generated, enter the following statement (which assumes that the objects are created in the schema of a user named 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.
Example 8-2 Using CONFORMANCE=T
Example 8-2 is essentially the same as Example 8-1, but it uses the CONFORMANCE=T
option (see the options
parameter description for SEM_APIS.CREATE_RDFVIEW_MODEL). Notice in the output that the schema name is not included in the list of properties; for example, the first output record in Example 8-2 is http://empdb/DEPT#LOC
, whereas its counterpart generated by Example 8-1 is 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.
Parent topic: API Support for RDF Views
8.2.2 Creating an RDF View with an R2RML Mapping
If you wanted to create an RDF view using the two tables EMP and DEPT, but with your own customizations, you could create an R2RML mapping document specified using Turtle, such as the following:
@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" ]]].
Then, load your R2RML mapping (converted into N-Triples format) into a staging table, such as SCOTT.R2RTAB, and grant the SELECT
privilege for this table to MDSYS.
Next, call SEM_APIS.CREATE_RDFVIEW_MODEL, as in Example 8-3.
Example 8-3 Creating an RDF View with an R2RML Mapping Stored in a Staging Table
BEGIN sem_apis.create_rdfview_model( model_name => 'empdb_model', tables => NULL, r2rml_table_owner => 'SCOTT', r2rml_table_name => 'R2RTAB' ); END; /
Example 8-4 Creating an RDF View with an R2RML Mapping String
An RDF view can also be created directly from an R2RML string, as shown in this example.
DECLARE r2rmlStr CLOB; BEGIN r2rmlStr := '@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" ]]].'; sem_apis.create_rdfview_model( model_name => 'empdb_model', tables => NULL, r2rml_string => r2rmlStr, r2rml_string_fmt => 'TURTLE' ); END; /
Parent topic: API Support for RDF Views
8.2.3 Dropping an RDF View
An RDF view can be dropped using the SEM_APIS.DROP_RDFVIEW_MODEL procedure, as shown in Example 8-5.
Example 8-5 Dropping an RDF View
BEGIN sem_apis.drop_rdfview_model( model_name => 'empdb_model' ); END; /
Parent topic: API Support for RDF Views
8.2.4 Exporting Virtual Content of an RDF View into a Staging Table
The content of an RDF view is virtual; that is, the RDF triples corresponding to the underlying relational data, as mapped by direct mapping or R2RML mapping, are not materialized and stored anywhere. You may, however, want to materialize and store these virtual RDF triples in an RDF model for your testing purposes. The SEM_APIS.EXPORT_RDFVIEW_MODEL subprogram lets you store the RDF triples of an RDF view in a staging table. The staging table can then be used for loading into an RDF model.
Example 8-6 materializes (in N-Triples format) the content of RDF view empdb_model
into the staging table SCOTT.RDFTAB.
Example 8-6 Exporting an RDF View
BEGIN sem_apis.export_rdfview_model( model_name => 'empdb_model', rdf_table_owner => 'SCOTT', rdf_table_name => 'RDFTAB' ); END;
Parent topic: API Support for RDF Views
8.3 Example: Using an RDF View with Direct Mapping
This topic provides an example of using an RDF view with direct mapping.
Example 8-7 shows a simple workflow using an RDF view with direct mapping. In it, you:
-
Create two relational tables (EMP and DEPT).
-
Insert data into the tables.
-
Create an RDF view model (
empdb_model
) using direct mapping of the two tables. -
Query the RDF view using SPARQL in a SEM_MATCH-based SQL query.
Example 8-8 shows the output of the statements in Example 8-7.
Example 8-7 Using an RDF View with Direct Mapping
-- 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';
Example 8-8 Output of Example 8-7
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
Parent topic: RDF Views: Relational Data as RDF
8.4 Combining Native RDF Data with Virtual RDB2RDF Data
You can combine native triple data with virtual RDB2RDF triple data in a single SEM_MATCH query by means of the SERVICE keyword.
The SERVICE keyword (explained in Graph Patterns: Support for SPARQL 1.1 Federated Query) is overloaded through the use of special SERVICE URLs that signify local (virtual) RDF data. The following prefixes are used to denote special SERVICE URLs:
-
Native models -
oram
: <http://xmlns.oracle.com/models/> -
Native virtual models -
oravm
: <http://xmlns.oracle.com/virtual_models/> -
RDB2RDF models -
orardbm
: <http://xmlns.oracle.com/rdb_models/>
Example 8-9 Querying Multiple Data Sets
Example 8-9 queries multiple data sets. In this query, the first triple pattern { ?x rdf:type :Person }
will go against native model m1
as usual, but { ?x :name ?name }
will go against the local native model m2
, and { ?x :email ?email }
will go against the local RDB2RDF model 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, ' '));
Overloaded SERVICE use is only allowed with a single model specified in the models
argument of SEM_MATCH. Overloaded SERVICE queries do not allow multiple models or a rulebase as input. A virtual model that contains multiple models and/or entailments should be used instead for such combinations. In addition, the index_status
argument for SEM_MATCH will only check the entailment contained in the virtual model passed as input in the models parameter. This means the status of entailments that are referenced in overloaded SERVICE calls will not be checked.
Example 8-10 Querying Virtual RDB2RDF Data and Native RDF Data
Example 8-10 queries two data sets: the empdb_model
from Example 8-7 and a native model named 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));
8.4.1 Nested Loop Pushdown with Overloaded Service
Using a nested loop service can improve performance is some scenarios. Consider the following examlpe query against multiple data sets, which finds the properties of all the departments with people who are 35 years old.
SELECT emp, dept, p, o
FROM TABLE(SEM_MATCH(
'SELECT * WHERE{
?emp peop:age 35
SERVICE orardbm:empdb_model{ ?emp emp:ref-DEPTNO ?dept . ?dept ?p ?o }
}',
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));
To get all the results that match for given graph pattern, first the triple { ?emp peop:age 35 }
is matched against model people
, then the triples { ?emp emp:ref-DEPTNO ?d . ?d dept:DNAME ?dept }
are matched against model empdb_model
, and finally the results are joined. Assume that there is only one 35-year-old person in the model people
, but there are 100,000 triples with information about departments. Obviously, a strategy that retrieves all the results is not the most efficient, and query may have poor performance because a large numberof results that need to be processed before being joined with the rest of the query.
An nested-loop service can improve performance in this case. If the hint OVERLOADED_NL=T
is used, the results of the first part of the query are computed and the SERVICE pattern is executed procedurally in a nested loop once for each ?emp
value from the root triple pattern. The ?emp
subject variable in the SERVICE pattern is replaced with a constant from the root triple pattern in each execution. This effectively pushes the join condition down into the SERVICE clause.
The following example shows the use of the OVERLOADED_NL=T
hint for the preceding query.
SELECT emp, dept, p, o
FROM TABLE(SEM_MATCH(
'SELECT * WHERE{
?emp peop:age 35
SERVICE orardbm:empdb_model { ?emp emp:ref-DEPTNO ?dept . ?dept ?p ?o }
}',
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,null,' OVERLOADED_NL=T '));
The hint OVERLOADED_NL=T
can be specified among SEM_MATCH options or among inline comments for a given SERVICE graph.
Parent topic: Combining Native RDF Data with Virtual RDB2RDF Data