问题
I created a little metro map with RDF/XML and wonder, how to query the distance between two stops. I'm very new to SPARQL and don't know how to start.
"Distance" means, that I want to know, how many stations are between the two ones. Later, I want to calculate the duration, but that's another point.
Thats my first approach:
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX ex: <http://example.com>
SELECT (count(?mid) as ?distance) WHERE {
<http://example.com/StopD> ex:via* ?mid .
?mid ex:via+ <http://example.com/StopC> .
}
I think, that my query doesn't work because I'm using blank nodes? Doesn't work means, that I don't get the number of graphs that are between the two stops (like StopA and StopB). I have something like this in my mind: http://answers.semanticweb.com/questions/3491/how-can-i-calculate-the-length-of-a-path-between-2-graph-nodes-in-sparql/24609
Thats a sketch of my map. The numbers beside the lines represents the travel duration between two stations:
semantic-metro-map.JPG
My RDF code describe each station and its neighbour stops with available lines and travel duration. At the first look it looks quite redundant, but I want to include one-direction routes (e.g. for buses) in the future, so I think it's ok for the first try.
RDF (download the file here: http://gopeter.de/misc/metro.rdf)
<?xml version="1.0"?>
<rdf:RDF
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:ex="http://example.com/">
<rdf:Description rdf:about="http://example.com/StopA">
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopB" />
<ex:Line rdf:resource="http://example.com/Line1" />
<ex:Duration>2</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopB" />
<ex:Line rdf:resource="http://example.com/Line2" />
<ex:Duration>7</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopD" />
<ex:Line rdf:resource="http://example.com/Line4" />
<ex:Duration>2</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopD" />
<ex:Line rdf:resource="http://example.com/Line2" />
<ex:Duration>6</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopE" />
<ex:Line rdf:resource="http://example.com/Line1" />
<ex:Duration>1</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopF" />
<ex:Line rdf:resource="http://example.com/Line4" />
<ex:Duration>3</ex:Duration>
</ex:via>
</rdf:Description>
<rdf:Description rdf:about="http://example.com/StopB">
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopA" />
<ex:Line rdf:resource="http://example.com/Line1" />
<ex:Duration>2</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopA" />
<ex:Line rdf:resource="http://example.com/Line2" />
<ex:Duration>7</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopC" />
<ex:Line rdf:resource="http://example.com/Line2" />
<ex:Duration>10</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopF" />
<ex:Line rdf:resource="http://example.com/Line3" />
<ex:Duration>2</ex:Duration>
</ex:via>
</rdf:Description>
<rdf:Description rdf:about="http://example.com/StopC">
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopB" />
<ex:Line rdf:resource="http://example.com/Line2" />
<ex:Duration>10</ex:Duration>
</ex:via>
</rdf:Description>
<rdf:Description rdf:about="http://example.com/StopD">
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopA" />
<ex:Line rdf:resource="http://example.com/Line2" />
<ex:Duration>6</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopA" />
<ex:Line rdf:resource="http://example.com/Line4" />
<ex:Duration>2</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopF" />
<ex:Line rdf:resource="http://example.com/Line3" />
<ex:Duration>2</ex:Duration>
</ex:via>
</rdf:Description>
<rdf:Description rdf:about="http://example.com/StopE">
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopA" />
<ex:Line rdf:resource="http://example.com/Line1" />
<ex:Duration>1</ex:Duration>
</ex:via>
</rdf:Description>
<rdf:Description rdf:about="http://example.com/StopF">
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopA" />
<ex:Line rdf:resource="http://example.com/Line4" />
<ex:Duration>3</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopB" />
<ex:Line rdf:resource="http://example.com/Line3" />
<ex:Duration>2</ex:Duration>
</ex:via>
<ex:via rdf:parseType="Resource">
<ex:Stop rdf:resource="http://example.com/StopD" />
<ex:Line rdf:resource="http://example.com/Line3" />
<ex:Duration>2</ex:Duration>
</ex:via>
</rdf:Description>
</rdf:RDF>
回答1:
Why yours doesn't work
Let's take a look at your data in the more easily readable Turtle syntax (below). StopD connects to three blank nodes with the ex:via property. That means that you'll get four matches for ?mid
with StopD ex:via* ?mid
. You don't get any more, though, because there are no outgoing links from the blank nodes with the property ex:via. That means that there are no matches for ?mid ex:via+ StopC
because ?mid doesn't have any outgoing ex:via links. Something like ?mid ex:Stop/ex:via+ StopC
would be better, because the ex:Stop link gets you from the blank node to another stop.
@prefix ex: <http://example.com/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
ex:StopD ex:via [ ex:Duration "6" ;
ex:Line ex:Line2 ;
ex:Stop ex:StopA
] ;
ex:via [ ex:Duration "2" ;
ex:Line ex:Line4 ;
ex:Stop ex:StopA
] ;
ex:via [ ex:Duration "2" ;
ex:Line ex:Line3 ;
ex:Stop ex:StopF
] .
Even though you can add the addition ex:Stop to your property path, this still won't be computing distance just the way you want it though, because you won't be restricted to just one line. I.e., you'll get edges on multiple paths.
Making this work
I've recreated a simpler scenario:
@prefix : <https://stackoverflow.com/q/24538144/1281433/> .
# B
# * *
# 2 * * 4
# * *
# * *
# A +++++++++ C
# 3
#
# *** line 1
# +++ line 2
:StopA a :Stop ; :toLink :Link1 , :Link3 .
:StopB a :Stop ; :toLink :Link2 .
:StopC a :Stop .
:Link1 :hasDuration 2 ;
:toStop :StopB ;
:Line1Self :Link1 .
:Link2 :hasDuration 4 ;
:toStop :StopC ;
:Line1Self :Link2 .
:Link3 :hasDuration 3 ;
:toStop :StopC ;
:Line2Self :Link3 .
Each stop can connect to any number of links with :toStop. The line of each link is indicated with a rolification property for the line. E.g., link2 line1self link2
means that link2 is on line1. This means that we "stay on the right line" using a property path. Then, to find the duration of the trip from stopA to stopB on line 1, you can use a query like this:
prefix : <https://stackoverflow.com/q/24538144/1281433/>
select (sum(?duration) as ?length) where {
:StopA :toLink/(:toStop/:toLink)*/:Line1Self ?link .
?link :hasDuration ?duration ;
:toStop/(:toLink/:Line1Self/:toStop)* :StopC .
}
----------
| length |
==========
| 6 |
----------
To check for a different line, you just change the :LineXSelf properties. E.g., for line2:
prefix : <https://stackoverflow.com/q/24538144/1281433/>
select (sum(?duration) as ?length) where {
:StopA :toLink/(:toStop/:toLink)*/:Line2Self ?link .
?link :hasDuration ?duration ;
:toStop/(:toLink/:Line2Self/:toStop)* :StopC .
}
----------
| length |
==========
| 3 |
----------
Limitations
The are some limitations to this approach though. Property paths are your only option for doing arbitrarily deep queries like this, but you can't use variables in property paths, which means that you can't do the following to get the distance on each of the lines:
prefix : <https://stackoverflow.com/q/24538144/1281433/>
select ?line (sum(?duration) as ?length) where {
values ?line { :Line1Self :Line2Self }
:StopA :toLink/(:toStop/:toLink)*/?line ?link .
?link :hasDuration ?duration ;
:toStop/(:toLink/?line/:toStop)* :StopC .
}
group by ?line
来源:https://stackoverflow.com/questions/24538144/how-to-query-the-distance-between-two-things-with-sparql