简体   繁体   中英

How to query the distance between two things with SPARQL

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 (eg 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>

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. Ie, 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. Eg, 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. Eg, 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM