-
Notifications
You must be signed in to change notification settings - Fork 4
Query transformation through rules
SWObjects was designed as a query transformation and execution engine. In many cases, we wish to query a virtual graph, created by some rules applied to some other (potentially virtual) graph. Some of these graphs may be the direct graph implied by a relational database; in this case, the final query is transformed to SQL and performed against a database like mysql or postgresql.
The following example is taken from the first example in A Direct Mapping of Relational Data to RDF. The following mapping rule expresses this data as FOAF:
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX empP: <http://hr.example/DB/Employee#>
PREFIX task: <http://hr.example/DB/Task#>
SHAREDVARS DRACONIAN
INTERSECTION {<Emp_TaskToFoaf>}?emp {<Emp_TaskToFoaf>}?man
<Emp_TaskToFoaf>
CONSTRUCT { ?emp foaf:last_name ?wname .
?emp foaf:knows ?man .
?man foaf:last_name ?mname }
WHERE { ?emp empP:lastName ?wname .
?pair task:drone ?emp .
?pair task:manager ?man .
?man empP:lastName ?mname }
Given a user query
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?lname {
?who foaf:last_name ?lname .
?who foaf:knows ?whom .
?whom foaf:knows ?whom2 .
?whom2 foaf:last_name 'Smith'^^xsd:string }
The mapping algorithms can be invoked from the command line tool sparql:
sparql -8 --debug 1 -npm Emp_TaskToFoaf.map two.rq
- -8 : unicode box characters
- --debug 1 : set debug level to 1 (currently any non-zero value is the same)
- -n : no execute -- don't run the query.
- -p : print the final query.
- Emp_TaskToFoaf.map : SPIN rules file (above) to create the virtual graph with FOAF arcs.
- two.rq : a query (above) which is satisfied by two invokations of Emp_TaskToFoaf.map.
Debug level: 1. Queued reading default map from Emp_TaskToFoaf.map. Query resource: two.rq. Switching to utf-8. Execution suppressed. + Stream constructed to read file Emp_TaskToFoaf.map.
Emp_TaskToFoaf.map has one rule in it, labeled .
adding rule: <Emp_TaskToFoaf> {
?emp <http://hr.example/DB/Employee#lastName> ?wname .
?pair <http://hr.example/DB/Task#drone> ?emp .
?pair <http://hr.example/DB/Task#manager> ?man .
?man <http://hr.example/DB/Employee#lastName> ?mname .
}
=> {
?emp <http://xmlns.com/foaf/0.1/last_name> ?wname .
?emp <http://xmlns.com/foaf/0.1/knows> ?man .
?man <http://xmlns.com/foaf/0.1/last_name> ?mname .
}
+ Stream constructed to read file two.rq.
Transforming user query by applying 1 rule maps.
The query mapper visits each graph pattern in the user's query. In this case, there is only one graph pattern, a basic graph pattern with four triple patterns.
transforming bgp: {
?who <http://xmlns.com/foaf/0.1/last_name> ?lname .
?who <http://xmlns.com/foaf/0.1/knows> ?whom .
?whom <http://xmlns.com/foaf/0.1/knows> ?whom2 .
?whom2 <http://xmlns.com/foaf/0.1/last_name> "Smith"^^<http://www.w3.org/2001/XMLSchema#string> .
}
There are four possible ways that the mapping rule can be instantiated to produce the graph pattern in the user's query.
-> [[
alternative: <Emp_TaskToFoaf>
┌────────┬────────┬────────┬───────┬────────────────────────────────────────────────────┐
│ ?emp │ ?man │ ?mname │ ?pair │ ?wname │
│ ?who │ ?whom │ -- │ -- │ ?lname │
│ ?whom │ ?whom2 │ -- │ -- │ -- │
│ ?whom2 │ -- │ -- │ -- │ "Smith"^^<http://www.w3.org/2001/XMLSchema#string> │
└────────┴────────┴────────┴───────┴────────────────────────────────────────────────────┘
bindings: {?emp=?who, ?man=?whom, ?wname=?lname} instantiate as:
?who <http://hr.example/DB/Employee#lastName> ?lname .
?_Emp_TaskToFoaf_0_pair <http://hr.example/DB/Task#drone> ?who .
?_Emp_TaskToFoaf_0_pair <http://hr.example/DB/Task#manager> ?whom .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_0_mname .
bindings: {?emp=?whom, ?man=?whom2} instantiate as:
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_1_wname .
?_Emp_TaskToFoaf_1_pair <http://hr.example/DB/Task#drone> ?whom .
?_Emp_TaskToFoaf_1_pair <http://hr.example/DB/Task#manager> ?whom2 .
?whom2 <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_1_mname .
bindings: {?emp=?whom2, ?wname="Smith"^^<http://www.w3.org/2001/XMLSchema#string>} instantiate as:
?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string> .
?_Emp_TaskToFoaf_2_pair <http://hr.example/DB/Task#drone> ?whom2 .
?_Emp_TaskToFoaf_2_pair <http://hr.example/DB/Task#manager> ?_Emp_TaskToFoaf_2_man .
?_Emp_TaskToFoaf_2_man <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_2_mname .
The possible invocations of rules produce a set of ways the query could be mapped to the antecedent to the rules. The query solution is the union of these mappings. Below is one example mapping:
UNION
alternative: <Emp_TaskToFoaf>
┌───────┬────────┬────────────────────────────────────────────────────┬───────┬────────┐
│ ?emp │ ?man │ ?mname │ ?pair │ ?wname │
│ ?who │ ?whom │ -- │ -- │ ?lname │
│ ?whom │ ?whom2 │ "Smith"^^<http://www.w3.org/2001/XMLSchema#string> │ -- │ -- │
└───────┴────────┴────────────────────────────────────────────────────┴───────┴────────┘
bindings: {?emp=?who, ?man=?whom, ?wname=?lname} instantiate as:
?who <http://hr.example/DB/Employee#lastName> ?lname .
?_Emp_TaskToFoaf_3_pair <http://hr.example/DB/Task#drone> ?who .
?_Emp_TaskToFoaf_3_pair <http://hr.example/DB/Task#manager> ?whom .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_3_mname .
bindings: {?mname="Smith"^^<http://www.w3.org/2001/XMLSchema#string>, ?emp=?whom, ?man=?whom2} instantiate as:
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_4_wname .
?_Emp_TaskToFoaf_4_pair <http://hr.example/DB/Task#drone> ?whom .
?_Emp_TaskToFoaf_4_pair <http://hr.example/DB/Task#manager> ?whom2 .
?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string> .
In the above mapping, two invocations the UNION
alternative: <Emp_TaskToFoaf>
┌────────┬────────┬────────┬───────┬────────────────────────────────────────────────────┐
│ ?emp │ ?man │ ?mname │ ?pair │ ?wname │
│ ?whom2 │ ?who │ ?lname │ -- │ "Smith"^^<http://www.w3.org/2001/XMLSchema#string> │
│ ?who │ ?whom │ -- │ -- │ -- │
│ ?whom │ ?whom2 │ -- │ -- │ -- │
└────────┴────────┴────────┴───────┴────────────────────────────────────────────────────┘
bindings: {?mname=?lname, ?emp=?whom2, ?man=?who, ?wname="Smith"^^<http://www.w3.org/2001/XMLSchema#string>} instantiate as:
?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string> .
?_Emp_TaskToFoaf_5_pair <http://hr.example/DB/Task#drone> ?whom2 .
?_Emp_TaskToFoaf_5_pair <http://hr.example/DB/Task#manager> ?who .
?who <http://hr.example/DB/Employee#lastName> ?lname .
bindings: {?emp=?who, ?man=?whom} instantiate as:
?who <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_6_wname .
?_Emp_TaskToFoaf_6_pair <http://hr.example/DB/Task#drone> ?who .
?_Emp_TaskToFoaf_6_pair <http://hr.example/DB/Task#manager> ?whom .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_6_mname .
bindings: {?emp=?whom, ?man=?whom2} instantiate as:
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_7_wname .
?_Emp_TaskToFoaf_7_pair <http://hr.example/DB/Task#drone> ?whom .
?_Emp_TaskToFoaf_7_pair <http://hr.example/DB/Task#manager> ?whom2 .
?whom2 <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_7_mname .
UNION
alternative: <Emp_TaskToFoaf>
┌───────┬────────┬────────────────────────────────────────────────────┬───────┬────────┐
│ ?emp │ ?man │ ?mname │ ?pair │ ?wname │
│ -- │ ?who │ ?lname │ -- │ -- │
│ ?who │ ?whom │ -- │ -- │ -- │
│ ?whom │ ?whom2 │ "Smith"^^<http://www.w3.org/2001/XMLSchema#string> │ -- │ -- │
└───────┴────────┴────────────────────────────────────────────────────┴───────┴────────┘
bindings: {?mname=?lname, ?man=?who} instantiate as:
?_Emp_TaskToFoaf_8_emp <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_8_wname .
?_Emp_TaskToFoaf_8_pair <http://hr.example/DB/Task#drone> ?_Emp_TaskToFoaf_8_emp .
?_Emp_TaskToFoaf_8_pair <http://hr.example/DB/Task#manager> ?who .
?who <http://hr.example/DB/Employee#lastName> ?lname .
bindings: {?emp=?who, ?man=?whom} instantiate as:
?who <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_9_wname .
?_Emp_TaskToFoaf_9_pair <http://hr.example/DB/Task#drone> ?who .
?_Emp_TaskToFoaf_9_pair <http://hr.example/DB/Task#manager> ?whom .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_9_mname .
bindings: {?mname="Smith"^^<http://www.w3.org/2001/XMLSchema#string>, ?emp=?whom, ?man=?whom2} instantiate as:
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_10_wname .
?_Emp_TaskToFoaf_10_pair <http://hr.example/DB/Task#drone> ?whom .
?_Emp_TaskToFoaf_10_pair <http://hr.example/DB/Task#manager> ?whom2 .
?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string> .
]]
=== As SPARQL Algebra ===
The debugging output includes a view of the final query expressed in the SPARQL Algebra.
<Query_algebra>
SELECT ?lname
(union
(bgp
(triple ?who <http://hr.example/DB/Employee#lastName> ?lname)
(triple ?_Emp_TaskToFoaf_0_pair <http://hr.example/DB/Task#drone> ?who)
(triple ?_Emp_TaskToFoaf_0_pair <http://hr.example/DB/Task#manager> ?whom)
(triple ?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_0_mname)
(triple ?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_1_wname)
(triple ?_Emp_TaskToFoaf_1_pair <http://hr.example/DB/Task#drone> ?whom)
(triple ?_Emp_TaskToFoaf_1_pair <http://hr.example/DB/Task#manager> ?whom2)
(triple ?whom2 <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_1_mname)
(triple ?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string>)
(triple ?_Emp_TaskToFoaf_2_pair <http://hr.example/DB/Task#drone> ?whom2)
(triple ?_Emp_TaskToFoaf_2_pair <http://hr.example/DB/Task#manager> ?_Emp_TaskToFoaf_2_man)
(triple ?_Emp_TaskToFoaf_2_man <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_2_mname)
)
(bgp
(triple ?who <http://hr.example/DB/Employee#lastName> ?lname)
(triple ?_Emp_TaskToFoaf_3_pair <http://hr.example/DB/Task#drone> ?who)
(triple ?_Emp_TaskToFoaf_3_pair <http://hr.example/DB/Task#manager> ?whom)
(triple ?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_3_mname)
(triple ?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_4_wname)
(triple ?_Emp_TaskToFoaf_4_pair <http://hr.example/DB/Task#drone> ?whom)
(triple ?_Emp_TaskToFoaf_4_pair <http://hr.example/DB/Task#manager> ?whom2)
(triple ?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string>)
)
(bgp
(triple ?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string>)
(triple ?_Emp_TaskToFoaf_5_pair <http://hr.example/DB/Task#drone> ?whom2)
(triple ?_Emp_TaskToFoaf_5_pair <http://hr.example/DB/Task#manager> ?who)
(triple ?who <http://hr.example/DB/Employee#lastName> ?lname)
(triple ?who <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_6_wname)
(triple ?_Emp_TaskToFoaf_6_pair <http://hr.example/DB/Task#drone> ?who)
(triple ?_Emp_TaskToFoaf_6_pair <http://hr.example/DB/Task#manager> ?whom)
(triple ?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_6_mname)
(triple ?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_7_wname)
(triple ?_Emp_TaskToFoaf_7_pair <http://hr.example/DB/Task#drone> ?whom)
(triple ?_Emp_TaskToFoaf_7_pair <http://hr.example/DB/Task#manager> ?whom2)
(triple ?whom2 <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_7_mname)
)
(bgp
(triple ?_Emp_TaskToFoaf_8_emp <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_8_wname)
(triple ?_Emp_TaskToFoaf_8_pair <http://hr.example/DB/Task#drone> ?_Emp_TaskToFoaf_8_emp)
(triple ?_Emp_TaskToFoaf_8_pair <http://hr.example/DB/Task#manager> ?who)
(triple ?who <http://hr.example/DB/Employee#lastName> ?lname)
(triple ?who <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_9_wname)
(triple ?_Emp_TaskToFoaf_9_pair <http://hr.example/DB/Task#drone> ?who)
(triple ?_Emp_TaskToFoaf_9_pair <http://hr.example/DB/Task#manager> ?whom)
(triple ?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_9_mname)
(triple ?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_10_wname)
(triple ?_Emp_TaskToFoaf_10_pair <http://hr.example/DB/Task#drone> ?whom)
(triple ?_Emp_TaskToFoaf_10_pair <http://hr.example/DB/Task#manager> ?whom2)
(triple ?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string>)
)
)
</query_algebra>
=== Output ===
The output is a SPARQL query which, when performed over the input RDF graph, which give the same solutions as would the user query performed over the inferred graph.
Final query: .
SELECT ?lname
WHERE
{
{
?who <http://hr.example/DB/Employee#lastName> ?lname .
?_Emp_TaskToFoaf_0_pair <http://hr.example/DB/Task#drone> ?who .
?_Emp_TaskToFoaf_0_pair <http://hr.example/DB/Task#manager> ?whom .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_0_mname .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_1_wname .
?_Emp_TaskToFoaf_1_pair <http://hr.example/DB/Task#drone> ?whom .
?_Emp_TaskToFoaf_1_pair <http://hr.example/DB/Task#manager> ?whom2 .
?whom2 <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_1_mname .
?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string> .
?_Emp_TaskToFoaf_2_pair <http://hr.example/DB/Task#drone> ?whom2 .
?_Emp_TaskToFoaf_2_pair <http://hr.example/DB/Task#manager> ?_Emp_TaskToFoaf_2_man .
?_Emp_TaskToFoaf_2_man <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_2_mname .
}
UNION
{
?who <http://hr.example/DB/Employee#lastName> ?lname .
?_Emp_TaskToFoaf_3_pair <http://hr.example/DB/Task#drone> ?who .
?_Emp_TaskToFoaf_3_pair <http://hr.example/DB/Task#manager> ?whom .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_3_mname .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_4_wname .
?_Emp_TaskToFoaf_4_pair <http://hr.example/DB/Task#drone> ?whom .
?_Emp_TaskToFoaf_4_pair <http://hr.example/DB/Task#manager> ?whom2 .
?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string> .
}
UNION
{
?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string> .
?_Emp_TaskToFoaf_5_pair <http://hr.example/DB/Task#drone> ?whom2 .
?_Emp_TaskToFoaf_5_pair <http://hr.example/DB/Task#manager> ?who .
?who <http://hr.example/DB/Employee#lastName> ?lname .
?who <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_6_wname .
?_Emp_TaskToFoaf_6_pair <http://hr.example/DB/Task#drone> ?who .
?_Emp_TaskToFoaf_6_pair <http://hr.example/DB/Task#manager> ?whom .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_6_mname .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_7_wname .
?_Emp_TaskToFoaf_7_pair <http://hr.example/DB/Task#drone> ?whom .
?_Emp_TaskToFoaf_7_pair <http://hr.example/DB/Task#manager> ?whom2 .
?whom2 <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_7_mname .
}
UNION
{
?_Emp_TaskToFoaf_8_emp <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_8_wname .
?_Emp_TaskToFoaf_8_pair <http://hr.example/DB/Task#drone> ?_Emp_TaskToFoaf_8_emp .
?_Emp_TaskToFoaf_8_pair <http://hr.example/DB/Task#manager> ?who .
?who <http://hr.example/DB/Employee#lastName> ?lname .
?who <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_9_wname .
?_Emp_TaskToFoaf_9_pair <http://hr.example/DB/Task#drone> ?who .
?_Emp_TaskToFoaf_9_pair <http://hr.example/DB/Task#manager> ?whom .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_9_mname .
?whom <http://hr.example/DB/Employee#lastName> ?_Emp_TaskToFoaf_10_wname .
?_Emp_TaskToFoaf_10_pair <http://hr.example/DB/Task#drone> ?whom .
?_Emp_TaskToFoaf_10_pair <http://hr.example/DB/Task#manager> ?whom2 .
?whom2 <http://hr.example/DB/Employee#lastName> "Smith"^^<http://www.w3.org/2001/XMLSchema#string> .
} }