Ordnance Survey Linked Data – A Simple Spatial Query
In this blog I thought I would give an example of some very simple spatial queries using the Ordnance Survey Linked Data. When we first created the Ordnance Survey linked data not many RDF triplestores had spatial indexes, or in other words there was no easy way to say ‘find me all the Parishes in Hampshire‘ using a query based on the geometries of these regions. This functionality is fairly standard in GIS systems and a number of spatially enabled relational databases, and is now being increasingly implemented in RDF triplestores and other NoSQL technologies. To get round this issue it was decided that it would be very useful to precompute various topological relationships between the administrative areas described in the Boundary-Line(TM) linked data. What you will see in the data are explicit spatial relationships like touches, within and contains that relate the different administrative regions. Now the administrative geography of this country is complicated, and I’m no geographer so a complete description of it will be left for a later blog post. For now I will say that Boundary-Line contains different geographies based on national voting and some on local authorities. The spatial relationships are only includedwhere relevant – for example you won’t find explicit spatial relationships between Westminster Constituencies and Counties, but you will find them between Counties and Districts.
In the Ordnance Survey linked data you will find three types of spatial relationship: touches, within and contains:
- touches means that two regions share a point on their boundary, but share no common points on their interior. They are adjacent/bordering. Touches relationships are typically only recorded between regions of the same type, i.e. which parish touches which parish. You won’t find a list of parishes touching counties. However, at some levels it gets a bit more complicated due to single tier local authorities (unitary authorities) and those based on a double tier (county/district). Counties and unitary authorities tessellate the country at some level, as do districts and unitary authorities.
- contains and within are fairly self explanatory I hope. Contains and within relationships are only stated between regions in the same geography and only explicitly stated between entities that directly contain/are within each other. What does this last part mean? In the local authorities geography counties contain districts and districts, in turn, contain parishes. You will only find explicit ‘contains’ statements between counties and districts, and between districts and parishes – you won’t find them between counties and parishes.
So now for some examples. Supposed I want to find the name of all the regions contained immediately in Hampshire. First you need to find which URI identifies Hampshire. Go to the Boundary-Line search API and search for Hampshire. You should then see that the county of Hampshire has the following URI:
http://data.ordnancesurvey.co.uk/id/7000000000017765
You can now use this in your query. Go to the SPARQL endpoint and enter the following:
select ?x ?name
where
{
?x <http://data.ordnancesurvey.co.uk/ontology/spatialrelations/within> <http://data.ordnancesurvey.co.uk/id/7000000000017765> .
?x <http://www.w3.org/2000/01/rdf-schema#label> ?name .
}
You will see a list of everything immediately within Hampshire, and these will all be of type district. Supposed you now want to get everything within Hampshire. This can be done easily by adding a ‘+’ at the end of the within predicate as follows:
select ?x ?name
where
{
?x <http://data.ordnancesurvey.co.uk/ontology/spatialrelations/within>+ <http://data.ordnancesurvey.co.uk/id/7000000000017765> .
?x <http://www.w3.org/2000/01/rdf-schema#label> ?name .
}
You now have a list of everything within Hampshire – this includes districts, wards and parishes. Now suppose you just want the parishes- you can do this by adding an extra line to the query to only match x to things of type civil parish:
select ?x ?name
where
{
?x <http://data.ordnancesurvey.co.uk/ontology/spatialrelations/within>+ <http://data.ordnancesurvey.co.uk/id/7000000000017765> .
?x <http://www.w3.org/2000/01/rdf-schema#label> ?name .
?x a <http://data.ordnancesurvey.co.uk/ontology/admingeo/CivilParish> .
}
Touches works in a similar way. Supposed you want the names of unitary authorities that touch Hampshire issue the following:
select ?x ?name
where
{
?x <http://data.ordnancesurvey.co.uk/ontology/spatialrelations/touches> <http://data.ordnancesurvey.co.uk/id/7000000000017765> .
?x <http://www.w3.org/2000/01/rdf-schema#label> ?name .
?x a <http://data.ordnancesurvey.co.uk/ontology/admingeo/UnitaryAuthority> .
}
Say you want to find parishes that touch Hampshire. This is where it gets complicated and the following is maybe for advanced SPARQL-wizards only. First find all of things that touch Hampshire (this will include other counties, unitary authorities and districts), then find all parishes within those regions and find which of those parishes touch parishes within Hampshire:
select distinct ?y ?name
where
{
?x <http://data.ordnancesurvey.co.uk/ontology/spatialrelations/touches> <http://data.ordnancesurvey.co.uk/id/7000000000017765> .
?y <http://data.ordnancesurvey.co.uk/ontology/spatialrelations/within> ?x .
?y a <http://data.ordnancesurvey.co.uk/ontology/admingeo/CivilParish> .
?z <http://data.ordnancesurvey.co.uk/ontology/spatialrelations/within>+ <http://data.ordnancesurvey.co.uk/id/7000000000017765> .
?z a <http://data.ordnancesurvey.co.uk/ontology/admingeo/CivilParish> .
?z <http://data.ordnancesurvey.co.uk/ontology/spatialrelations/touches> ?y .
?y <http://www.w3.org/2000/01/rdf-schema#label> ?name .
}
Congratulations – you now have a list of all the parishes that touch Hampshire.
Hopefully some of these queries are useful – happy SPARQLing.
John –
Any chance of supporting GeoSPARQL alongside the ordnance survey spatial relations?
Certainly on the cards for future releases. We didn’t do it on this release because we didn’t want to break peoples applications without migrating them properly onto the new schema.