RDF-to-RDF and RDF-to-relational query transformation in SWObjects.
trivial to dump RDB as RDF
test: is the graph query coherent (do generated node identifiers merge)?
Sociopathic RDF graph
?who mydb:fn ?name
Need interface graph
?who foaf:name ?name
The charter says to map RDBs to RDF/OWL.
clear algebra for:
Patterns | Modifiers | Query Forms |
---|---|---|
RDF terms | DISTINCT | SELECT |
triple patterns | REDUCED | CONSTRUCT |
Basic graph patterns | PROJECT | DESCRIBE |
Groups | ORDER BY | ASK |
OPTIONAL | LIMIT | |
UNION | OFFSET | |
GRAPH | ||
FILTER |
Graph Pattern | Solution Modifiers |
---|---|
BGP | ToList |
Join | OrderBy |
LeftJoin | Project |
Filter | Distinct |
Union | Reduced |
Graph | Slice |
Graph Pattern | Solution Modifiers | Evaluation |
---|---|---|
ProjectAlias | MultiSet | NULL |
TableAlias | OrderBy | |
Join | Project | |
LeftJoin | Distinct | |
Constraint | Reduced | |
Union | offset/limit |
RelSchema => StemMapping
StemMapping(stemURI, RelData) => StemGraph
StemMapping(stemURI, RelData) = TupleMapping1(stemURI, Table1) + TupleMapping2(stemURI, Table2)...
LexicalMap(string) => string LexicalMap(numeric) => lexical form of numberic
LiteralMap(string) => RDFLiteral(LexicalMap(string), xsd:String) LiteralMap(int) => RDFLiteral(LexicalMap(int), xsd:integer) LiteralMap(float) => RDFLiteral(LexicalMap(float), xsd:float)
S = <stemURI '/' Table '/' PrimaryKey(Table) '.' LexicalMap(Value(PrimaryKey(Table))) '#record' > P = <stemURI '/' Table '#' Attribute > O = attribute a FK to T2 ? <stemURI '/' T2 '/' PrimaryKey(T2) '.' LiteralMap(Value(PrimaryKey(T2))) '#record' > : LiteralMap(Value(Attribute)
test: does the StemGraph meet the same use cases as the relational data?
RelQuery(StemQuery) = set(AliasedJoin) + set(equivs)
(Rel, Attr) = match(P, stemURI + '/' + (\w+) + '#' (\w+)) some Alias = hash(Rel + S) join.insert(Rel AS Alias) pk = primary_key_attribute(Rel) match S with VAR -> if (bindings[S]) equivs.insert(Alias.pk= bindings[S]) bindings[S] = Alias.pk URI -> (=Rel, PkAttr, PkValue) = match(S, stemURI + '/' (\w+) '/' (\w+) '.' (\w+) '#record') some PkAlias = hash(PkRel + S) joins.insert(PkRel AS PkAttr) =pk = primary_key_attribute(Rel) equivs.insert(PkAlias.PkPk= PkValue) match O with LITERAL -> equivs.insert(alias.attr= O) VAR -> if (bindings[O]) equivs.insert(Alias.Attr= bindings[O]) bindings[O] = Alias.Attr URI -> (FkRel, FkAttr, FkValue) = match(S, stemURI + '/' (\w+) '/' (\w+) '.' (\w+) '#record') some FkAlias = hash(FkRel + O) joins.insert(FkRel AS FkAttr) FkPk = primary_key_attribute(FkRel) equivs.insert(FkAlias.FkPk= FkValue) equivs.insert(Alias.Attr= FkValue)
test: does RelQuery(RelData) == StemQuery(StemGraph)?
VARconstraint(VAR, FQAttribute): if bindings[VAR]) equivs.insert(FQAttribute= bindings[VAR] bindings[VAR]= FQAttribute URIconstraint(URI) => Value: (Rel, Attr, Value) = match(URI, stemURI + '/' (\w+) '/' (\w+) '.' (\w+) '#record') some Alias = hash(Rel + URI) joins.insert(Rel AS Attr) pk = primary_key_attribute(Rel) equivs.insert(Alias.pk= Value) Value (Rel, Attr) = match(P, stemURI + '/' + (\w+) + '#' (\w+)) some Alias = hash(Rel + S) join.insert(Rel AS Alias) pk = primary_key_attribute(Rel) match S with VAR -> VARconstraint(S, Alias.pk) URI -> URIconstraint(S) match O with LITERAL -> equivs.insert(alias.attr= O) VAR -> VARconstraint(O, Alias.Attr) URI -> equivs.insert(Alias.Attr= URIconstraint(O))
id | manager | section |
---|---|---|
1 | 4 | sales |
4 | NULL | exec |
Emp:id=1 emp:id 1 . Emp:id=1 emp:manager Emp:id=4 . Emp:id=1 emp:section "sales" . Emp:id=4 emp:id 4 . Emp:id=4 emp:manager "exec" .
employee | lead | name |
---|---|---|
1 | 4 | widgets |
4 | 5 | widgets |
_:t1 task.employee Emp:id=1 . _:t1 task.lead Emp:id=2 . _:t1 task.name "widgets" . _:t2 task.employee Emp:id=4 . _:t2 task.lead Emp:id=5 . _:t2 task.name "widgets".
SELECT ?sec ?name WHERE { GRAPH<HQ> { ?flunky emp:section ?sec OPTIONAL { ?flunky emp:manager ?boss } } GRAPH<Sales> { _:t task:employee ?flunky; task:lead ?boss; task:name ?task } }
flunky | boss | sec | task |
---|---|---|---|
Emp:id=1 | Emp:id=4 | "sales" | "widgets" |
Emp:id=4 | "exec" | "widgets" |
flunky | boss | sec | task |
---|---|---|---|
1 | 4 | sales | widgets |
CONSTRUCT { ?x shop:name ?name ; shop:price ?price } WHERE { ?x db:name ?name ; db:price ?price }
SELECT ?name WHERE { <...Items/id=5#record> shop:name ?name ; shop:price ?price }
SELECT id_5.nm AS name FROM Items AS id_5 WHERE id_5.id=5
SELECT id_5.nm AS name FROM Items AS id_5 WHERE id_5.id=5 AND id_5.price IS NOT NULL
CONSTRUCT { ?x a shop:SaleItem ; shop:name ?name ; shop:price ?price } WHERE { ?x db:name ?name ; db:price ?price ; db:discount ?discount FILTER (?discount > 0.0) }
SELECT ?cost
WHERE { <...Items/id=5#record> a shop:SaleItem ;
shop:name ?name ;
shop:price ?price }
SELECT id_5.nm AS name FROM Items AS id_5 WHERE id_5.id=5
SELECT id_5.nm AS name FROM Items AS id_5 WHERE id_5.id=5 AND id_5.discount > 0
CONSTRUCT { ?x a shop:SaleItem ; ?x shop:name ?name ; shop:price ?price } WHERE { ?x db:name ?name { ?x db:price ?price ; db:discount ?discount } }
Useful for:
What requirements to we have?
requirements feedback through:
system | expressivity | |
---|---|---|
Virtuoso | d2r/DDL | |
Triplify | SQL->app? | |
D2R | d2r | |
Metatomix | GUI | |
Ultrawrap | DDL | |
Oracle | DDL | |
SWObjects | CONSTRUCT | |
OKKAM | ??? |