Date post: | 20-Jan-2015 |
Category: |
Technology |
Upload: | stefan-bischof |
View: | 3,452 times |
Download: | 0 times |
Towards XSPARQL 1.1: New Features and Optimization
Master’s Thesis Presentation of Stefan BischofOctober 1, 2010
XML RDFXSPARQL
New Features and Faster Query Evaluation
for XSPARQL
Data Representation
XML (Extensible Markup Language) is a markup language designed for data exchange over the internet. Documents and other data are represented as trees.
RDF (Resource Description Framework) is a framework for describing arbitrary resources. Resources and their relations are represented as directed graphs. Mainly used for Semantic Web data.
XML RDFXSPARQL
Example Data
The ‘knows’ relation is directed; Charles knows nobody in this example.
knows knows
knows
RDF and XML
relations
person personperson
name knows knows name nameknows
CharlesBobAlice Bob CharlesCharles
_:b1
foaf:Person
Alice
foaf:name
_:b2foaf:knows
Bob
foaf:name
_:b3foaf:knows
Charles
foaf:name
foaf:knows
rdf:type
rdf:typerdf:type
@prefix foaf: <http://xmlns.com/foaf/0.1/> ._:b1 a foaf:Person; foaf:name "Alice"; foaf:knows _:b2; foaf:knows _:b3._:b2 a foaf:Person; foaf:name "Bob"; foaf:knows _:b3._:b3 a foaf:Person; foaf:name "Charles".
<relations> <person name="Alice"> <knows>Bob</knows> <knows>Charles</knows> </person> <person name="Bob"> <knows>Charles</knows> </person> <person name="Charles"/> </relations>
relations.xmlrelations.rdf
XQuery + SPARQL = XSPARQL
XQuery is a functional query language designed for processing XML data. Large function library; superset of XPath 2.0
SPARQL is a query language for RD. It uses graph patterns to filter RDF data.
XML RDFXSPARQL
What’s XSPARQL?
Simplifies data transformation by combining the advantages of XQuery and SPARQL:
Provides RDF graph pattern matching to XQuery ➔ serialization format agnostic access to RDF data
SPARQL gains access to large XQuery function library + subqueries
XML RDFXSPARQL
XSPARQL ExampleConvert from RDF to XML
For each person P:
Print P’s name
For each friend F of P:
Print F’s name
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
XSPARQL Summary
XML RDF
SPARQLXQuery
XSPARQL Summary
XML RDFXSPARQL
SPARQLXQuery
Implementation
XSPARQL query
XSPARQL rewriter
XQuery query
XQuery engine
SPARQL engine
RDFdata
XMLdata
XML or RDF
Query processing
Input
Output
HTTP
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
SELECT $name FROM <people.rdf>WHERE { $person a foaf:Person . $person foaf:name $name . }
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
# $name
1
2
3
“Alice”
“Bob”
“Charles”
SELECT $name FROM <people.rdf>WHERE { $person a foaf:Person . $person foaf:name $name . }
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
SELECT $fname FROM <people.rdf>WHERE { $pers1 foaf:name “Alice” . $pers1 foaf:knows $friend . $friend foaf:name $fname . }
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
# $fname
1
2
“Bob”
“Charles”
SELECT $fname FROM <people.rdf>WHERE { $pers1 foaf:name “Alice” . $pers1 foaf:knows $friend . $friend foaf:name $fname . }
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
SELECT $fname FROM <people.rdf>WHERE { $pers1 foaf:name “Bob” . $pers1 foaf:knows $friend . $friend foaf:name $fname . }
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
SELECT $fname FROM <people.rdf>WHERE { $pers1 foaf:name “Bob” . $pers1 foaf:knows $friend . $friend foaf:name $fname . }
# $fname
1 “Charles”
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
SELECT $fname FROM <people.rdf>WHERE { $pers1 foaf:name “Charles” . $pers1 foaf:knows $friend . $friend foaf:name $fname . }
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
SELECT $fname FROM <people.rdf>WHERE { $pers1 foaf:name “Charles” . $pers1 foaf:knows $friend . $friend foaf:name $fname . }
# $fname
Query EvaluationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <knows name=”{$fname}”/> } </person>
RDF to XML
@prefix foaf: <http://xmlns.com/foaf/0.1/> ._:b1 a foaf:Person; foaf:name "Alice"; foaf:knows _:b2; foaf:knows _:b3._:b2 a foaf:Person; foaf:name "Bob"; foaf:knows _:b3._:b3 a foaf:Person; foaf:name "Charles".
<relations> <person name="Alice"> <knows>Bob</knows> <knows>Charles</knows> </person> <person name="Bob"> <knows>Charles</knows> </person> <person name="Charles"/> </relations>
relations.xmlrelations.rdf
XDEP Join Optimization
Goal: Improve performance for nested queries
Reduce number of SPARQL calls: N ➔ 1
only one single SPARQL call for the inner loop
join is performed later using XQuery
Constraint: applicable only for dependent joins
join variable always bound
Saves communication and repeated evaluation time
XDEP Join OptimizationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
XDEP Join OptimizationSPARQLXQuery
for $name from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $pers1 foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
Practical Performance Evaluation
Use common XQuery benchmark suite XMark
Generate test documents of different sizes (5-100MB)
Automatically translate test documents to RDF
Manually translate queries from XQuery to XSPARQL
Compare standard XSPARQL with optimized XSPARQL
XSPARQL Performance
1
10
100
1000
10000
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Eva
luat
ion
time
(sec
)
XMark Query #
XQuery XSPARQL5 MB Dataset
XSPARQL Performance
1
10
100
1000
10000
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Eva
luat
ion
time
(sec
)
XMark Query #
XQuery XSPARQL5 MB Dataset
Nested SPARQL parts
XDEP Performance Increase
1
10
100
1000
0 5 10 15 20
Per
form
ance
gai
n fa
ctor
Dataset size (MB)
Unoptimized timeoptimized time
Query 8
Query 9
Query 10
XDEP Performance Increase
1
10
100
1000
10 100 1000 10000
Per
form
ance
gai
n fa
ctor
Number of outer loop iterations
Query 8
Query 9
Query 10
= number of saved SPARQL calls
New Features
Dataset Scoping
Fixes unintended behavior of nested queries
Constructed Dataset
Create and query temporary data source
Fixes unintended behavior of nested SPARQL parts
Reuse variable bound to blank node in inner query
Variable behaves as free/unbound variable again because
Scope of blank node is limited to one dataset/SPARQL query
Blank nodes in graph patterns are similar to unbound variables
Dataset Scoping extends the scope of a dataset over subqueries and allows blank node joins
New Features Dataset Scoping
New Features Constructed Dataset
Create intermediary RDF graphs to be used in the same query as data source
Use cases
Query aggregated data using XQuery’s built-in functions.
Manually optimize queries by preselecting relevant parts of a data source.
Conclusions
Enhance XSPARQL Capabilities Constructed Dataset and Dataset Scoping features are valuable additions to XSPARQL
Increase Evaluation Performance Dependent join optimization XDEP offers a confirmed performance increase for nested XSPARQL queries
More info and demo http://xsparql.deri.org
ReferencesAkhtar W., Kopecký J., Krennwallner T., and Pollers A. XSPARQL: Traveling between the XML and RDF worlds - and Avoiding the XSLT pilgrimage. In 5th European Semantic Web Conference (ESWC2008), pages 432–447, 2008.
Bischof S. Implementation and Optimization of Queries in XSPARQL. Master’s Thesis, Vienna University of Technology, 2010.
Bray T., Paoli J., Sperberg-McQueen C. M., Maler E., and Yergeau F. Extensible Markup Language (XML) 1.0 (Fifth Edition). http:// www.w3.org/TR/xml/, November 2008. W3C Recommendation.
Boag S., Chamberlin D., Fernández M. F., Florescu D., Robie J., and Siméon J. XQuery 1.0: An XML Query Language. http://www.w3.org/TR/xquery/, January 2007. W3C Recommendation.
Manola F. and Miller E. RDF Primer. http://www.w3.org/TR/rdf-primer/, February 2004. W3C Recommendation.
Prud’hommeaux E. and Seaborne A. SPARQL Query Language for RDF. http://www.w3.org/TR/rdf-sparql-query/, January 2008. W3C Recommendation.
Example Dataset Scoping
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
Example Dataset Scoping
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
Example Dataset Scoping
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
# $name $person
1
2
3
“Alice” _:b1
“Bob” _:b2
“Charles” _:b3
Example Dataset Scoping
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
# $name $person
1
2
3
“Alice” _:b1
“Bob” _:b2
“Charles” _:b3
SELECT $fnameFROM <people.rdf>WHERE { _:b1 foaf:knows $friend. $friend foaf:name $fname.}
Example Dataset Scoping
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
# $fname
1
2
3
“Bob”
“Bob”
“Charles”
# $name $person
1
2
3
“Alice” _:b1
“Bob” _:b2
“Charles” _:b3
SELECT $fnameFROM <people.rdf>WHERE { _:b1 foaf:knows $friend. $friend foaf:name $fname.}
Example Dataset Scoping<person name=”Alice”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Bob”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Charles”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
# $fname
1
2
3
“Bob”
“Bob”
“Charles”
# $name $person
1
2
3
“Alice” _:b1
“Bob” _:b2
“Charles” _:b3
SELECT $fnameFROM <people.rdf>WHERE { _:b1 foaf:knows $friend. $friend foaf:name $fname.}
Example Dataset Scoping<person name=”Alice”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Bob”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Charles”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
# $fname
1
2
3
“Bob”
“Bob”
“Charles”
# $name $person
1
2
3
“Alice” _:b1
“Bob” _:b2
“Charles” _:b3
SELECT $fnameFROM <people.rdf>WHERE { _:b1 foaf:knows $friend. $friend foaf:name $fname.}
Example Dataset Scoping<person name=”Alice”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Bob”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Charles”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
Problem:1. Blank nodes scoped to single SPARQL query2. Blank nodes in graph patterns are like variables➔ Variable bound to blank node behaves as free variable
# $fname
1
2
3
“Bob”
“Bob”
“Charles”
# $name $person
1
2
3
“Alice” _:b1
“Bob” _:b2
“Charles” _:b3
SELECT $fnameFROM <people.rdf>WHERE { _:b1 foaf:knows $friend. $friend foaf:name $fname.}
Example Dataset Scoping<person name=”Alice”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Bob”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Charles”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
Problem:1. Blank nodes scoped to single SPARQL query2. Blank nodes in graph patterns are like variables➔ Variable bound to blank node behaves as free variable
# $fname
1
2
3
“Bob”
“Bob”
“Charles”
# $name $person
1
2
3
“Alice” _:b1
“Bob” _:b2
“Charles” _:b3
SELECT $fnameFROM <people.rdf>WHERE { _:b1 foaf:knows $friend. $friend foaf:name $fname.}
Solution: Extend Scope of Blank node/
Dataset
Example Dataset Scoping<person name=”Alice”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Bob”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Charles”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
Problem:1. Blank nodes scoped to single SPARQL query2. Blank nodes in graph patterns are like variables➔ Variable bound to blank node behaves as free variable
# $fname
1
2
3
“Bob”
“Bob”
“Charles”
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
# $name $person
1
2
3
“Alice” _:b1
“Bob” _:b2
“Charles” _:b3
SELECT $fnameFROM <people.rdf>WHERE { _:b1 foaf:knows $friend. $friend foaf:name $fname.}
Solution: Extend Scope of Blank node/
Dataset
Example Dataset Scoping<person name=”Alice”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Bob”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person><person name=”Charles”> <friend name=”Bob” /> <friend name=”Charles” /> <friend name=”Charles” /></person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $pers1 foaf:name $name. $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
Problem:1. Blank nodes scoped to single SPARQL query2. Blank nodes in graph patterns are like variables➔ Variable bound to blank node behaves as free variable
# $fname
1
2
3
“Bob”
“Bob”
“Charles”
for $name $person from <people.rdf>where { $person a foaf:Person . $person foaf:name $name . }return <person name=”{$name}”> { for $fname from <people.rdf> where { $person foaf:knows $friend . $friend foaf:name $fname . } return <friend name=”{$fname}”/> } </person>
# $name $person
1
2
3
“Alice” _:b1
“Bob” _:b2
“Charles” _:b3
SELECT $fnameFROM <people.rdf>WHERE { _:b1 foaf:knows $friend. $friend foaf:name $fname.}
Solution: Extend Scope of Blank node/
Dataset<person name=”Alice”> <friend name=”Bob” /> <friend name=”Charles” />
</person><person name=”Bob”>
<friend name=”Charles” /></person><person name=”Charles”>
</person>