blob: 96ac20492869dccea86631f5b5ccf1fa55d9f4b1 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<title>Apache Jena - Apache Jena GeoSPARQL</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/css/bootstrap.min.css" rel="stylesheet" media="screen">
<link href="/css/bootstrap-icons.css" rel="stylesheet" media="screen"><link rel="stylesheet" type="text/css" href="https://jena.apache.org/sass/jena.1b17c39a117e22b46db4c66f6395dc27c134a60377d87d2d5745b8600eb69722.css" integrity="sha256-GxfDmhF&#43;IrRttMZvY5XcJ8E0pgN32H0tV0W4YA62lyI=">
<link rel="shortcut icon" href="/images/favicon.ico" />
</head>
<body>
<nav class="navbar navbar-expand-lg bg-body-tertiary" role="navigation">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="/index.html">
<img class="logo-menu" src="/images/jena-logo/jena-logo-notext-small.png" alt="jena logo">Apache Jena</a>
</div>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li id="homepage" class="nav-item"><a class="nav-link" href="/index.html"><span class="bi-house"></span> Home</a></li>
<li id="download" class="nav-item"><a class="nav-link" href="/download/index.cgi"><span class="bi-download"></span> Download</a></li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal"></span> Learn <b class="caret"></b></a>
<ul class="dropdown-menu">
<li class="dropdown-header">Tutorials</li>
<li><a class="dropdown-item" href="/tutorials/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/fuseki2/index.html">Fuseki Triplestore</a></li>
<li><a class="dropdown-item" href="/documentation/notes/index.html">How-To's</a></li>
<li><a class="dropdown-item" href="/documentation/query/manipulating_sparql_using_arq.html">Manipulating SPARQL using ARQ</a></li>
<li><a class="dropdown-item" href="/tutorials/rdf_api.html">RDF core API tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/sparql.html">SPARQL tutorial</a></li>
<li><a class="dropdown-item" href="/tutorials/using_jena_with_eclipse.html">Using Jena with Eclipse</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">References</li>
<li><a class="dropdown-item" href="/documentation/index.html">Overview</a></li>
<li><a class="dropdown-item" href="/documentation/query/index.html">ARQ (SPARQL)</a></li>
<li><a class="dropdown-item" href="/documentation/io/">RDF I/O</a></li>
<li><a class="dropdown-item" href="/documentation/assembler/index.html">Assembler</a></li>
<li><a class="dropdown-item" href="/documentation/tools/index.html">Command-line tools</a></li>
<li><a class="dropdown-item" href="/documentation/rdfs/">Data with RDFS Inferencing</a></li>
<li><a class="dropdown-item" href="/documentation/geosparql/index.html">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/inference/index.html">Inference API</a></li>
<li><a class="dropdown-item" href="/documentation/ontology/">Ontology API</a></li>
<li><a class="dropdown-item" href="/documentation/permissions/index.html">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/extras/querybuilder/index.html">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/rdf/index.html">RDF API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfconnection/">RDF Connection - SPARQL API</a></li>
<li><a class="dropdown-item" href="/documentation/rdfstar/index.html">RDF-star</a></li>
<li><a class="dropdown-item" href="/documentation/shacl/index.html">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/shex/index.html">ShEx</a></li>
<li><a class="dropdown-item" href="/documentation/tdb/index.html">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/tdb2/index.html">TDB2</a></li>
<li><a class="dropdown-item" href="/documentation/query/text-query.html">Text Search</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-journal-code"></span> Javadoc <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/documentation/javadoc.html">All Javadoc</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/arq/">ARQ</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/fuseki2/">Fuseki</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/geosparql/">GeoSPARQL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/jena/">Jena Core</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/permissions/">Permissions</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/extras/querybuilder/">Query Builder</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/shacl/">SHACL</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/tdb/">TDB</a></li>
<li><a class="dropdown-item" href="/documentation/javadoc/text/">Text Search</a></li>
</ul>
</li>
</ul>
<form class="d-flex" role="search" action="/search" method="GET">
<div class="input-group">
<input class="form-control border-end-0 border m-0" type="search" name="q" id="search-query" placeholder="Search...." aria-label="Search" style="width: 10rem;">
<button class="btn btn-outline-secondary border-start-0 border" type="submit">
<i class="bi-search"></i>
</button>
</div>
</form>
<ul class="navbar-nav">
<li id="ask" class="nav-item"><a class="nav-link" href="/help_and_support/index.html" title="Ask"><span class="bi-patch-question"></span><span class="text-body d-none d-xxl-inline"> Ask</span></a></li>
<li class="nav-item dropdown">
<a href="#" title="Get involved" class="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdown" aria-expanded="false"><span class="bi-megaphone"></span><span class="text-body d-none d-xxl-inline"> Get involved </span><b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="/getting_involved/index.html">Contribute</a></li>
<li><a class="dropdown-item" href="/help_and_support/bugs_and_suggestions.html">Report a bug</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">Project</li>
<li><a class="dropdown-item" href="/about_jena/about.html">About Jena</a></li>
<li><a class="dropdown-item" href="/about_jena/architecture.html">Architecture</a></li>
<li><a class="dropdown-item" href="/about_jena/citing.html">Citing</a></li>
<li><a class="dropdown-item" href="/about_jena/team.html">Project team</a></li>
<li><a class="dropdown-item" href="/about_jena/contributions.html">Related projects</a></li>
<li><a class="dropdown-item" href="/about_jena/roadmap.html">Roadmap</a></li>
<li><a class="dropdown-item" href="/about_jena/security-advisories.html">Security Advisories</a></li>
<li class="dropdown-divider"></li>
<li class="dropdown-header">ASF</li>
<li><a class="dropdown-item" href="https://www.apache.org/">Apache Software Foundation</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Become a Sponsor</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/licenses/LICENSE-2.0">License</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/security/">Security</a></li>
<li><a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a></li>
</ul>
</li>
<li class="nav-item" id="edit"><a class="nav-link" href="https://github.com/apache/jena-site/edit/main/source/documentation/geosparql/__index.md" title="Edit this page on GitHub"><span class="bi-pencil-square"></span><span class="text-body d-none d-xxl-inline"> Edit this page</span></a></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="breadcrumbs">
<ol class="breadcrumb mt-4 p-2 bg-body-tertiary">
<li class="breadcrumb-item"><a href='/documentation'>DOCUMENTATION</a></li>
<li class="breadcrumb-item active">GEOSPARQL</li>
</ol>
</div>
<h1 class="title">Apache Jena GeoSPARQL</h1>
<main class="d-flex flex-xl-row flex-column">
<aside class="text-muted align-self-start mb-3 p-0 d-xl-none d-block">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#getting-started">Getting Started</a></li>
<li><a href="#features">Features</a></li>
<li><a href="#additional-features">Additional Features</a>
<ul>
<li><a href="#sparql-query-configuration">SPARQL Query Configuration</a></li>
<li><a href="#querying-datasets--models-with-sparql">Querying Datasets &amp; Models with SPARQL</a></li>
<li><a href="#api-the-library-can-be-used-as-an-api-in-java--the-main-class-to-handle">API The library can be used as an API in Java. The main class to handle</a></li>
</ul>
</li>
<li><a href="#key-dependencies">Key Dependencies</a>
<ul>
<li><a href="#geosparql">GeoSPARQL</a></li>
<li><a href="#apache-sissis_data-environment-variable">Apache SIS/SIS_DATA Environment Variable</a></li>
<li><a href="#java-topology-suite">Java Topology Suite</a></li>
</ul>
</li>
<li><a href="#note">Note</a>
<ul>
<li><a href="#geosparql-schema">GeoSPARQL Schema</a></li>
<li><a href="#spatial-relations">Spatial Relations</a></li>
<li><a href="#spatial-relations-and-geometry-shapestypes">Spatial Relations and Geometry Shapes/Types</a></li>
<li><a href="#equals-relations">Equals Relations</a></li>
<li><a href="#query-rewrite-extension">Query Rewrite Extension</a></li>
<li><a href="#dataset-conversion">Dataset Conversion</a></li>
<li><a href="#spatial-index">Spatial Index</a></li>
<li><a href="#units-uri">Units URI</a></li>
</ul>
</li>
<li><a href="#geography-markup-language-support-gml">Geography Markup Language Support (GML)</a></li>
<li><a href="#apache-jena-spatial-functionswgs84-geo-predicates">Apache Jena Spatial Functions/WGS84 Geo Predicates</a>
<ul>
<li><a href="#supported-features">Supported Features</a></li>
<li><a href="#filter-functions">Filter Functions</a></li>
<li><a href="#property-functions">Property Functions</a></li>
</ul>
</li>
<li><a href="#geometry-property-filter-functions">Geometry Property Filter Functions</a></li>
<li><a href="#future-work">Future Work</a></li>
<li><a href="#contributors">Contributors</a></li>
<li><a href="#why-use-this-implementation">Why Use This Implementation?</a></li>
</ul>
</nav>
</aside>
<article class="flex-column me-lg-4">
<p>An implementation of GeoSPARQL 1.0 standard for SPARQL query or API.</p>
<p>Integration with Fuseki is provided either by using the
<a href="geosparql-assembler.html">GeoSPARQL assembler</a> or using the self-contained original
<a href="geosparql-fuseki.html">jena-fuseki-geosparql</a>. In either case, this page
describes the GeoSPARQL supported features.</p>
<h2 id="getting-started">Getting Started</h2>
<p>GeoSPARQL Jena can be accessed as a library using Maven etc. from Maven Central.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">&lt;groupId&gt;</span>org.apache.jena<span style="color:#008000;font-weight:bold">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">&lt;artifactId&gt;</span>jena-geosparql<span style="color:#008000;font-weight:bold">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">&lt;version&gt;</span>...<span style="color:#008000;font-weight:bold">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">&lt;/dependency&gt;</span>
</span></span></code></pre></div><h2 id="features">Features</h2>
<p>This implementation follows the 11-052r4 OGC GeoSPARQL standard
(<a href="https://www.ogc.org/standards/geosparql">https://www.ogc.org/standards/geosparql</a>). The implementation is pure Java
and does not require any set-up or configuration of any third party relational
databases and geospatial extensions.</p>
<p>It implements the six Conformance Classes described in the GeoSPARQL document:</p>
<ul>
<li>Core</li>
<li>Topology Vocabulary</li>
<li>Geometry Extension</li>
<li>Geometry Topology</li>
<li>RDFS Entailment Extension</li>
<li>Query Rewrite Extension</li>
</ul>
<p>The WKT (as described in 11-052r4) and GML 2.0 Simple Features Profile
(10-100r3) serialisations are supported. Additional serialisations can be
implemented by extending the
<code>org.apache.jena.geosparql.implementation.datatype.GeometryDatatype</code> and
registering with Jena&rsquo;s <code>org.apache.jena.datatypes.TypeMapper</code>.</p>
<p>All three spatial relation families are supported: <em>Simple Feature</em>, <em>Egenhofer</em> and <em>RCC8</em>.</p>
<p>Indexing and caching of spatial objects and relations is performed <em>on-demand</em>
during query execution. Therefore, set-up delays should be minimal. Spatial
indexing is available based on the <em>STRtree</em> from the JTS library. The <em>STRtree</em>
is readonly once built and contributions of a <em>QuadTree</em> implementation are
welcome.</p>
<p>Benchmarking of the implementation against Strabon and Parliament has found it
to be comparable or quicker. The benchmarking used was the Geographical query
and dataset (<a href="http://geographica.di.uoa.gr/">http://geographica.di.uoa.gr/</a>).</p>
<h2 id="additional-features">Additional Features</h2>
<p>The following additional features are also provided:</p>
<ul>
<li>Geometry properties are automatically calculated and do not need to be asserted in the dataset.</li>
<li>Conversion between EPSG spatial/coordinate reference systems is applied
automatically. Therefore, mixed datasets or querying can be applied. This is
reliance upon local installation of Apache SIS EPSG dataset, see <strong>Key
Dependencies</strong>.</li>
<li>Units of measure are automatically converted to the appropriate units for the
coordinate reference system.</li>
<li>Geometry, transformation and spatial relation results are stored in persistent
and configurable time-limited caches to improve response times and reduce
recalculations.</li>
<li>Dataset conversion between serialisations and spatial/coordinate reference
systems. Tabular data can also be loaded, see RDF Tables project
(<a href="https://github.com/galbiston/rdf-tables">https://github.com/galbiston/rdf-tables</a>).</li>
<li>Functions to test Geometry properties directly on Geometry Literals have been included for convenience.</li>
</ul>
<h3 id="sparql-query-configuration">SPARQL Query Configuration</h3>
<p>Using the library for SPARQL querying requires one line of code. All indexing
and caching is performed during query execution and so there should be minimal
delay during initialisation. This will register the Property Functions with ARQ
query engine and configures the <em>indexes</em> used for time-limited caching.</p>
<p>There are three <em>indexes</em> which can be configured independently or switched off.
These <em>indexes</em> retain data that may be required again when a query is being
executed but may not be required between different queries. Therefore, the
memory usage will grow during query execution and then recede as data is not
re-used. All the <em>indexes</em> support concurrency and can be set to a maximum size
or allowed to increase capacity as required.</p>
<ul>
<li><em>Geometry Literal</em>: Geometry objects following de-serialisation from <code>Geometry Literal</code>.</li>
<li><em>Geometry Transform</em>: Geometry objects resulting from coordinate transformations between spatial reference systems.</li>
<li><em>Query Rewrite</em>: results of spatial relations between <code>Feature</code> and <code>Geometry</code> spatial objects.</li>
</ul>
<p>Testing has found up to 20% improvement in query completion durations using the indexes.
The <em>indexes</em> can be configured by size, retention duration and frequency of clean up.</p>
<ul>
<li>
<p>Basic setup with default values: <code>GeoSPARQLConfig.setupMemoryIndex()</code></p>
</li>
<li>
<p>Indexes set to maximum sizes: <code>GeoSPARQLConfig.setupMemoryIndexSize(50000, 50000, 50000)</code></p>
</li>
<li>
<p>Indexes set to remove objects not used after 5 seconds: <code>GeoSPARQLConfig.setupMemoryIndexExpiry(5000, 5000, 5000)</code></p>
</li>
<li>
<p>No indexes setup (Query rewrite still performed but results not stored) : <code>GeoSPARQLConfig.setupNoIndex()</code></p>
</li>
<li>
<p>No indexes and no query rewriting: <code>GeoSPARQLConfig.setupNoIndex(false)</code></p>
</li>
<li>
<p>Reset indexes and other stored data: <code>GeoSPARQLConfig.reset()</code></p>
</li>
</ul>
<p>A variety of configuration methods are provided in
<code>org.apache.jena.geosparql.configuration.GeoSPARQLConfig</code>. Caching of
frequently used but small quantity data is also applied in several <em>registries</em>,
e.g. coordinate reference systems and mathematical transformations.</p>
<p>Example GeoSPARQL query:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sparql" data-lang="sparql"><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">PREFIX</span> <span style="color:#00f;font-weight:bold">geo</span>: <span style="color:#a0a000">&lt;http://www.opengis.net/ont/geosparql#&gt;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">SELECT</span> <span style="color:#b8860b">?obj</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">WHERE</span>{
</span></span><span style="display:flex;"><span> <span style="color:#b8860b">?subj</span> <span style="color:#00f;font-weight:bold">geo</span>:<span style="color:#008000;font-weight:bold">sfContains</span> <span style="color:#b8860b">?obj</span>
</span></span><span style="display:flex;"><span>} <span style="color:#a2f;font-weight:bold">ORDER by</span> <span style="color:#b8860b">?obj</span>
</span></span></code></pre></div><h3 id="querying-datasets--models-with-sparql">Querying Datasets &amp; Models with SPARQL</h3>
<p>The setup of GeoSPARQL Jena only needs to be performed once in an application.
After it is set up querying is performed using Jena&rsquo;s standard query methods.</p>
<p>To query a Model with GeoSPARQL or standard SPARQL:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span>GeoSPARQLConfig<span style="color:#666">.</span><span style="color:#b44">setupMemoryIndex</span><span style="color:#666">();</span>
</span></span><span style="display:flex;"><span>Model model <span style="color:#666">=</span> <span style="color:#666">.....;</span>
</span></span><span style="display:flex;"><span>String query <span style="color:#666">=</span> <span style="color:#666">....;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">try</span> <span style="color:#666">(</span>QueryExecution qe <span style="color:#666">=</span> QueryExecution<span style="color:#666">.</span><span style="color:#b44">create</span><span style="color:#666">(</span>query<span style="color:#666">,</span> model<span style="color:#666">))</span> <span style="color:#666">{</span>
</span></span><span style="display:flex;"><span> ResultSet rs <span style="color:#666">=</span> qe<span style="color:#666">.</span><span style="color:#b44">execSelect</span><span style="color:#666">();</span>
</span></span><span style="display:flex;"><span> ResultSetFormatter<span style="color:#666">.</span><span style="color:#b44">outputAsTSV</span><span style="color:#666">(</span>rs<span style="color:#666">);</span>
</span></span><span style="display:flex;"><span><span style="color:#666">}</span>
</span></span></code></pre></div><p>If your dataset needs to be separate from your application and accessed over
HTTP then you probably need the <a href="geosparql-assembler">GeoSPARQL Assembler</a> to
integrate with Fuseki. The GeoSPARQL functionality needs to be setup in the
application or Fuseki server where the dataset is located.</p>
<p>It is <strong>recommended</strong> that <code>hasDefaultGeometry</code> properties are included in the
dataset to access all functionality. It is <strong>necessary</strong> that <code>SpatialObject</code>
classes are asserted or inferred (i.e. a reasoner with the GeoSPARQL schema is
applied) in the dataset. Methods to prepare a dataset can be found in
<code>org.apache.jena.geosparql.configuration.GeoSPARQLOperations</code>.</p>
<h3 id="api-the-library-can-be-used-as-an-api-in-java--the-main-class-to-handle">API The library can be used as an API in Java. The main class to handle</h3>
<p>geometries and their spatial relations is the <code>GeometryWrapper</code>. This can be
obtained by parsing the string representation of a geometry using the
appropriate datatype (e.g. WKT or GML). Alternatively, a Literal can be
extracted automatically using the <code>GeometryWrapper.extract()</code> method and
registered datatypes. The <code>GeometryWrapperFactory</code> can be used to directly
construct a <code>GeometryWrapper</code>. There is overlap between spatial relation
families so repeated methods are not specified.</p>
<ul>
<li>
<p>Parse a <code>Geometry Literal</code>: <code>GeometryWrapper geometryWrapper = WKTDatatype.INSTANCE.parse(&quot;POINT(1 1)&quot;);</code></p>
</li>
<li>
<p>Extract from a Jena Literal: <code>GeometryWrapper geometryWrapper = GeometryWrapper.extract(geometryLiteral);</code></p>
</li>
<li>
<p>Create from a JTS Geometry: <code>GeometryWrapper geometryWrapper = GeometryWrapperFactory.createGeometry(geometry, srsURI, geometryDatatypeURI);</code></p>
</li>
<li>
<p>Create from a JTS Point Geometry: <code>GeometryWrapper geometryWrapper = GeometryWrapperFactory.createPoint(coordinate, srsURI, geometryDatatypeURI);</code></p>
</li>
<li>
<p>Convert CRS/SRS: <code>GeometryWrapper otherGeometryWrapper = geometryWrapper.convertCRS(&quot;http://www.opengis.net/def/crs/EPSG/0/27700&quot;)</code></p>
</li>
<li>
<p>Spatial Relation: <code>boolean isCrossing = geometryWrapper.crosses(otherGeometryWrapper);</code></p>
</li>
<li>
<p>DE-9IM Intersection Pattern: <code>boolean isRelated = geometryWrapper.relate(otherGeometryWrapper, &quot;TFFFTFFFT&quot;);</code></p>
</li>
<li>
<p>Geometry Property: <code>boolean isEmpty = geometryWrapper.isEmpty();</code></p>
</li>
</ul>
<p>The GeoSPARQL standard specifies that WKT Geometry Literals without an SRS URI are defaulted to CRS84 <code>http://www.opengis.net/def/crs/OGC/1.3/CRS84</code>.</p>
<h2 id="key-dependencies">Key Dependencies</h2>
<h3 id="geosparql">GeoSPARQL</h3>
<p>The OGC GeoSPARQL standard supports representing and querying geospatial data on
the Semantic Web. GeoSPARQL defines a vocabulary for representing geospatial
data in RDF, and it defines an extension to the SPARQL query language for
processing geospatial data. In addition, GeoSPARQL is designed to accommodate
systems based on qualitative spatial reasoning and systems based on quantitative
spatial computations.</p>
<p>The GeoSPARQL standard is based upon the OGC Simple Features standard
(<a href="http://www.opengeospatial.org/standards/sfa">http://www.opengeospatial.org/standards/sfa</a>) used in relational databases.
Modifications and enhancements have been made for usage with RDF and SPARQL.
The Simple Features standard, and by extension GeoSPARQL, simplify calculations
to Euclidean planer geometry. Therefore, datasets using a geographic
spatial/coordinate reference system, which are based on latitude and longitude
on an ellipsoid, e.g. WGS84, will have minor error introduced. This error has
been deemed acceptable due to the simplification in calculation it offers.</p>
<h3 id="apache-sissis_data-environment-variable">Apache SIS/SIS_DATA Environment Variable</h3>
<p>Apache Spatial Information System (SIS) is a free software, Java language
library for developing geospatial applications. SIS provides data structures
for geographic features and associated meta-data along with methods to
manipulate those data structures. The library is an implementation of GeoAPI
3.0 interfaces and can be used for desktop or server applications.</p>
<p>A subset of the EPSG spatial/coordinate reference systems are included by default.
The full EPSG dataset is not distributed due to the EPSG terms of use being incompatible with the Apache Licence.
Several options are available to include the EPSG dataset by setting the <code>SIS_DATA</code> environment variable (<a href="http://sis.apache.org/epsg.html">http://sis.apache.org/epsg.html</a>).</p>
<p>An embedded EPSG dataset can be included in a Gradle application by adding the following dependency to <code>build.gradle</code>:</p>
<pre><code>ext.sisVersion = &quot;1.1&quot;
implementation &quot;org.apache.sis.non-free:sis-embedded-data:$sisVersion&quot;
</code></pre>
<h3 id="java-topology-suite">Java Topology Suite</h3>
<p>The JTS Topology Suite is a Java library for creating and manipulating vector geometry.</p>
<h2 id="note">Note</h2>
<p>The following are implementation points that may be useful during usage.</p>
<h3 id="geosparql-schema">GeoSPARQL Schema</h3>
<p>An RDF/XML schema has been published for the GeoSPARQL v1.0 standard (v1.0.1 -
<a href="http://schemas.opengis.net/geosparql/1.0/geosparql_vocab_all.rdf">http://schemas.opengis.net/geosparql/1.0/geosparql_vocab_all.rdf</a>). This can
be applied to Jena Models (see <a href="/documentation/inference/">the inference
documentation</a>) to provide RDFS and OWL inferencing
on a GeoSPARQL conforming dataset. However, the published schema does not
conform with the standard.</p>
<p>The property <code>hasDefaultGeometry</code> is missing from the schema and instead the
<code>defaultGeometry</code> property is stated.</p>
<p>This prevents RDFS inferencing being performed correctly and has been reported
to the OGC Standards Tracker. A corrected version of the schema is available in
the <code>Resources</code> folder.</p>
<h3 id="spatial-relations">Spatial Relations</h3>
<p>The GeoSPARQL and Simple Features standard both define the DE-9IM intersection
patterns for the three spatial relation families. However, these patterns are
not always consistent with the patterns stated by the JTS library for certain
relations.</p>
<p>For example, GeoSPARQL/Simple Features use <code>TFFFTFFFT</code> <em>equals</em> relations in
<em>Simple Feature</em>, <em>Egenhofer</em> and <em>RCC8</em>. However, this does not yield the
usually expected result when comparing a pair of point geometries. The Simple
Features standard states that the boundary of a point is empty. Therefore, the
boundary intersection of two points would also be empty so give a negative
comparison result.</p>
<p>JTS, and other libraries, use the alternative intersection pattern of
<code>T*F**FFF*</code>. This is a combination of the <em>within</em> and <em>contains</em> relations and
yields the expected results for all geometry types.</p>
<p>The spatial relations utilised by JTS have been implemented as the extension
<code>spatial:equals</code> filter and property functions. A user can also supply their
own DE-9IM intersection patterns by using the <code>geof:relate</code> filter function.</p>
<h3 id="spatial-relations-and-geometry-shapestypes">Spatial Relations and Geometry Shapes/Types</h3>
<p>The spatial relations for the three spatial families do not apply to all
combinations of the geometry shapes (<code>Point</code>, <code>LineString</code>, <code>Polygon</code>) and their
collections (<code>MultiPoint</code>, <code>MultiLineString</code>, <code>MultiPolygon</code>). Therefore, some
queries may not produce all the results that may initially be expected.</p>
<p>Some examples are:</p>
<ul>
<li>In some relations there may only be results when a collection of shapes is being used, e.g. two multi-points can overlap but two points cannot.</li>
<li>A relation may only apply for one combination but not its reciprocal, e.g. a line may cross a polygon but a polygon may not cross a line.</li>
<li>The <em>RCC8</em> family only applies to <code>Polygon</code> and <code>MultiPolygon</code> types.</li>
</ul>
<p>Refer to pages 8-10 of 11-052r4 GeoSPARQL standard for more details.</p>
<h3 id="equals-relations">Equals Relations</h3>
<p>The three equals relations (<em>sfEquals</em>, <em>ehEquals</em> and <em>rccEquals</em>) use spatial
equality and not lexical equality. Therefore, some comparisons using these
relations may not be as expected.</p>
<p>The JTS description of <em>sfEquals</em> is:</p>
<ul>
<li>True if two geometries have at least one point in common and no point of either geometry lies in the exterior of the other geometry.</li>
</ul>
<p>Therefore, two empty geometries will return false as they are not spatially equal.
Shapes which differ in the number of points but have the same geometry are equal and will return true.</p>
<p>e.g. <code>LINESTRING (0 0, 0 10)</code> and <code>LINESTRING (0 0, 0 5, 0 10)</code> are spatially equal.</p>
<h3 id="query-rewrite-extension">Query Rewrite Extension</h3>
<p>The Query Rewrite Extension provides for simpler querying syntax. <code>Feature</code> and
<code>Geometry</code> can be used in spatial relations without needing the relations to be
asserted in the dataset. This also means the <code>Geometry Literal</code> does not need
to be specified in the query. In the case of <code>Features</code> this requires the
<code>hasDefaultGeometry</code> property to be used in the dataset.</p>
<p>This means the query:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sparql" data-lang="sparql"><span style="display:flex;"><span><span style="color:#b8860b">?subj</span> <span style="color:#00f;font-weight:bold">geo</span>:<span style="color:#008000;font-weight:bold">hasDefaultGeometry</span> <span style="color:#b8860b">?subjGeom</span> .
</span></span><span style="display:flex;"><span><span style="color:#b8860b">?subjGeom</span> <span style="color:#00f;font-weight:bold">geo</span>:<span style="color:#008000;font-weight:bold">hasSerialization</span> <span style="color:#b8860b">?subjLit</span> .
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#b8860b">?obj</span> <span style="color:#00f;font-weight:bold">geo</span>:<span style="color:#008000;font-weight:bold">hasDefaultGeometry</span> <span style="color:#b8860b">?objGeom</span> .
</span></span><span style="display:flex;"><span><span style="color:#b8860b">?objGeom</span> <span style="color:#00f;font-weight:bold">geo</span>:<span style="color:#008000;font-weight:bold">hasSerialization</span> <span style="color:#b8860b">?objLit</span> .
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">FILTER</span>(<span style="color:#00f;font-weight:bold">geof</span>:<span style="color:#008000;font-weight:bold">sfContains</span>(<span style="color:#b8860b">?subjLit</span>, <span style="color:#b8860b">?objLit</span>))
</span></span></code></pre></div><p>becomes:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sparql" data-lang="sparql"><span style="display:flex;"><span><span style="color:#b8860b">?subj</span> <span style="color:#00f;font-weight:bold">geo</span>:<span style="color:#008000;font-weight:bold">sfContains</span> <span style="color:#b8860b">?obj</span> .
</span></span></code></pre></div><p>Methods are available to apply the <code>hasDefaultGeometry</code> property to every
<code>Geometry</code> with a single <code>hasGeometry</code> property, see
<code>org.apache.jena.geosparql.configuration.GeoSPARQLOperations</code>.</p>
<p>Depending upon the spatial relation, queries may include the specified <code>Feature</code>
and <code>Geometry</code> in the results. e.g. FeatureA is bound in a query on a dataset
only containing FeatureA and GeometryA. The results FeatureA and GeometryA are
returned rather than no results. Therefore, filtering using
<code>FILTER(!sameTerm(?subj, ?obj))</code> etc. may be needed in some cases. The query
rewrite functionality can be switched off in the library configuration, see
<code>org.apache.jena.geosparql.configuration.GeoSPARQLConfig</code>.</p>
<p>Each dataset is assigned a Query Rewrite Index to store the results of previous
tests. There is the potential that relations are tested multiple times in a
query (i.e. <em>Feature-Feature</em>, <em>Feature-Geometry</em>, <em>Geometry-Geometry</em>,
<em>Geometry-Feature</em>). Therefore, it is useful to retain the results for at least
a short period of time.</p>
<p>Iterating through all combinations of spatial relations for a dataset containing
<em>n</em> Geometry Literals will produce 27<em>n</em>^2 true/false results (asserting the
true result statements in a dataset would be a subset). Control is given on a
dataset basis to allow choice in when and how storage of rewrite results is
applied, e.g. store all found results on a small dataset but on demand for a
large dataset.</p>
<p>This index can be configured on a global and individual dataset basis for the
maximum size and duration until unused items are removed. Query rewriting can
be switched on independently of the indexes, i.e. query rewriting can be
performed but an index is configured to not store the result.</p>
<p>As an extension to the standard, supplying a <code>Geometry Literal</code> is
also permitted. For example:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sparql" data-lang="sparql"><span style="display:flex;"><span><span style="color:#b8860b">?subj</span> <span style="color:#00f;font-weight:bold">geo</span>:<span style="color:#008000;font-weight:bold">sfContains</span> <span style="color:#b44">&#34;POINT(0 0)&#34;</span><span style="color:#666">^^</span><span style="color:#00f;font-weight:bold">geo</span>:<span style="color:#008000;font-weight:bold">wktLiteral</span> .
</span></span></code></pre></div><h3 id="dataset-conversion">Dataset Conversion</h3>
<p>Methods to convert datasets between serialisations and spatial/coordinate
reference systems are available in:
<code>org.apache.jena.geosparql..configuration.GeoSPARQLOperations</code></p>
<p>The following list shows some of the operations that can be performed. Once
these operations have been performed they can be serialised to file or stored in
a Jena TDB to remove the need to reprocess.</p>
<ul>
<li>
<p>Load a Jena Model from file: <code>Model dataModel = RDFDataMgr.loadModel(&quot;data.ttl&quot;);</code></p>
</li>
<li>
<p>Convert <code>Feature-GeometryLiteral</code> to the GeoSPARQL <code>Feature-Geometry-GeometryLiteral</code> structure: <code>Model geosparqlModel = GeoSPARQLOperations.convertGeometryStructure(dataModel);</code></p>
</li>
<li>
<p>Convert <code>Feature-Lat, Feature-Lon</code> Geo predicates to the GeoSPARQL <code>Feature-Geometry-GeometryLiteral</code> structure, with option to remove Geo predicates: <code>Model geosparqlModel = GeoSPARQLOperations.convertGeoPredicates(dataModel, true);</code></p>
</li>
<li>
<p>Assert additional <code>hasDefaultGeometry</code> statements for single <code>hasGeometry</code> triples, used in Query Rewriting: <code>GeoSPARQLOperations.applyDefaultGeometry(geosparqlModel);</code></p>
</li>
<li>
<p>Convert Geometry Literals to the WGS84 spatial reference system and WKT datatype: <code>Model model = GeoSPARQLOperations.convert(geosparqlModel, &quot;http://www.opengis.net/def/crs/EPSG/0/4326&quot;, &quot;http://www.opengis.net/ont/geosparql#wktLiteral&quot;);</code></p>
</li>
<li>
<p>Apply GeoSPARQL schema with RDFS inferencing and assert additional statements in the Model: <code>GeoSPARQLOperations.applyInferencing(model);</code></p>
</li>
<li>
<p>Apply commonly used GeoSPARQL prefixes for URIs to the model: <code>GeoSPARQLOperations.applyPrefixes(model);</code></p>
</li>
<li>
<p>Create Spatial Index for a Model within a Dataset for spatial querying: <code>Dataset dataset = SpatialIndex.wrapModel(model);</code></p>
</li>
</ul>
<p>Other operations are available and can be applied to a Dataset containing
multiple Models and in some cases files and folders. These operations do
<strong>not</strong> configure and set up the GeoSPARQL functions or indexes that are required
for querying.</p>
<h3 id="spatial-index">Spatial Index</h3>
<p>A Spatial Index can be created to improve searching of a dataset. The Spatial
Index is expected to be unique to the dataset and should not be shared between
datasets. Once built the Spatial Index cannot have additional items added to
it.</p>
<p>A Spatial Index is required for the <code>jena-spatial</code> property functions and is
optional for the GeoSPARQL spatial relations. Only a single SRS can be used for
a Spatial Index, and it is recommended that datasets are converted to a single
SRS, see <code>GeoSPARQLOperations</code>.</p>
<p>Setting up a Spatial Index can be done through
<code>org.apache.jena.geosparql.configuration.GeoSPARQLConfig</code>. Additional methods
for building, loading and saving Spatial Indexes are provided in
<code>org.apache.jena.geosparql.spatial.SpatialIndex</code>.</p>
<h3 id="units-uri">Units URI</h3>
<p>Spatial/coordinate reference systems use a variety of measuring systems for
defining distances. These can be specified using a URI identifier, as either
URL or URN, with conversion undertaken automatically as required. It should be
noted that there is error inherent in spatial reference systems and some
variation in values may occur between different systems.</p>
<p>The following table gives some examples of units that are supported (additional
units can be added to the <code>UnitsRegistry</code> using the <code>javax.measure.Unit</code> API).
These URIs are all in the namespace <code>http://www.opengis.net/def/uom/OGC/1.0/</code> and
here use the prefix <code>units</code>.</p>
<table>
<thead>
<tr>
<th>URI</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>units:kilometre or units:kilometer</td>
<td>Kilometres</td>
</tr>
<tr>
<td>units:metre or units:meter</td>
<td>Metres</td>
</tr>
<tr>
<td>units:mile or units:statuteMile</td>
<td>Miles</td>
</tr>
<tr>
<td>units:degree</td>
<td>Degrees</td>
</tr>
<tr>
<td>units:radian</td>
<td>Radians</td>
</tr>
</tbody>
</table>
<p>Full listing of default Units can be found in
<code>org.apache.jena.geosparql.implementation.vocabulary.Unit_URI</code>.</p>
<h2 id="geography-markup-language-support-gml">Geography Markup Language Support (GML)</h2>
<p>The supported GML profile is GML 2.0 Simple Features Profile (10-100r3), which
is a profile of GML 3.2.1 (07-036r1). The profile restricts the geometry shapes
permitted in GML 3.2.1 to a subset, see 10-100r3 page 22. The profile supports
Points, LineString and Polygon shapes used in WKT. There are also additional
shape serialisations available in the profile that do not exist in WKT or JTS to
provide simplified representations which would otherwise use LineStrings or
Polygons. Curves can be described by LineStringSegment, Arc, Circle and
CircleByCenterPoint. Surfaces can be formed similarly to Polygons or using
Curves. These additional shapes can be read as part of a dataset or query but
will not be produced if the SRS of the shape is transformed, instead a
LineString or Polygon representation will be produced.</p>
<p>Details of the GML structure for these shapes can be found in the
<a href="http://www.datypic.com/sc/niem21/s-geometryPrimitives.xsd.html">geometryPrimitives.xsd</a>,
<a href="http://www.datypic.com/sc/niem21/s-geometryBasic0d1d.xsd.html">geometryBasic0d1d.xsd</a>,
<a href="http://www.datypic.com/sc/niem21/s-geometryBasic2d.xsd.html">geometryBasic2d.xsd</a>
and
<a href="http://www.datypic.com/sc/niem21/s-geometryAggregates.xsd.html">geometryAggregates.xsd</a>
schemas.</p>
<p>The labelling of collections is as follows:</p>
<table>
<thead>
<tr>
<th>Collection</th>
<th>Geometry</th>
</tr>
</thead>
<tbody>
<tr>
<td>MultiPoint</td>
<td>Point</td>
</tr>
<tr>
<td>MultiCurve</td>
<td>LineString, Curve</td>
</tr>
<tr>
<td>MultiSurface</td>
<td>Polygon, Surface</td>
</tr>
<tr>
<td>MultiGeometry</td>
<td>Point, LineString, Curve, Polygon, Surface</td>
</tr>
</tbody>
</table>
<h2 id="apache-jena-spatial-functionswgs84-geo-predicates">Apache Jena Spatial Functions/WGS84 Geo Predicates</h2>
<p>The <code>jena-spatial</code> module contains several SPARQL functions for querying
datasets using the WGS84 Geo predicates for latitude
(<code>http://www.w3.org/2003/01/geo/wgs84_pos#lat</code>) and longitude
(<code>http://www.w3.org/2003/01/geo/wgs84_pos#long</code>). These <code>jena-spatial</code>
functions are supported for both Geo predicates and Geometry Literals, i.e. a
GeoSPARQL dataset. Additional SPARQL filter functions have been provided to
convert Geo predicate properties into WKT strings and calculate Great Circle and
Euclidean distances. The <code>jena-spatial</code>functions require setting up a Spatial
Index for the target Dataset,
e.g. <code>GeoSPARQLConfig.setupSpatialIndex(dataset);</code>, see Spatial Index section.</p>
<h3 id="supported-features">Supported Features</h3>
<p>The Geo predicate form of spatial representation is restricted to only &lsquo;Point&rsquo;
shapes in the WGS84 spatial/coordinate reference system. The Geo predicates are
properties of the <code>Feature</code> and do not use the properties and structure of the
GeoSPARQL standard, including Geometry Literals. Methods are available to
convert datasets from Geo predicates to GeoSPARQL structure, see:
<code>org.apache.jena.geosparql.configuration.GeoSPARQLOperations</code></p>
<p>The spatial relations and query re-writing of GeoSPARQL outlined previously has been implemented for Geo predicates.
However, only certain spatial relations are valid for <code>Point</code> to <code>Point</code> relationships.
Refer to pages 8-10 of 11-052r4 GeoSPARQL standard for more details.</p>
<p>Geo predicates can be converted to Geometry Literals in query and then used with the GeoSPARQL filter functions.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sparql" data-lang="sparql"><span style="display:flex;"><span><span style="color:#b8860b">?subj</span> <span style="color:#00f;font-weight:bold">wgs</span>:<span style="color:#008000;font-weight:bold">lat</span> <span style="color:#b8860b">?lat</span> .
</span></span><span style="display:flex;"><span><span style="color:#b8860b">?subj</span> <span style="color:#00f;font-weight:bold">wgs</span>:<span style="color:#008000;font-weight:bold">long</span> <span style="color:#b8860b">?lon</span> .
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">BIND</span>(<span style="color:#00f;font-weight:bold">spatialF</span>:<span style="color:#008000;font-weight:bold">convertLatLon</span>(<span style="color:#b8860b">?lat</span>, <span style="color:#b8860b">?lon</span>) <span style="color:#a2f;font-weight:bold">as</span> <span style="color:#b8860b">?point</span>) .
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic">#Coordinate order is Lon/Lat without stated SRS URI.</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">BIND</span>(<span style="color:#b44">&#34;POLYGON((...))&#34;</span><span style="color:#666">^^</span><span style="color:#a0a000">&lt;http://www.opengis.net/ont/geosparql#wktLiteral&gt;</span> <span style="color:#a2f;font-weight:bold">AS</span> <span style="color:#b8860b">?box</span>) .
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">FILTER</span>(<span style="color:#00f;font-weight:bold">geof</span>:<span style="color:#008000;font-weight:bold">sfContains</span>(<span style="color:#b8860b">?box</span>, <span style="color:#b8860b">?point</span>))
</span></span></code></pre></div><p>Alternatively, utilising more shapes, relations and spatial reference systems
can be achieved by converting the dataset to the GeoSPARQL structure.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sparql" data-lang="sparql"><span style="display:flex;"><span><span style="color:#b8860b">?subj</span> <span style="color:#00f;font-weight:bold">geo</span>:<span style="color:#008000;font-weight:bold">hasGeometry</span> <span style="color:#b8860b">?geom</span> .
</span></span><span style="display:flex;"><span><span style="color:#b8860b">?geom</span> <span style="color:#00f;font-weight:bold">geo</span>:<span style="color:#008000;font-weight:bold">hasSerialization</span> <span style="color:#b8860b">?geomLit</span> .
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic">#Coordinate order is Lon/Lat without stated SRS URI.</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">BIND</span>(<span style="color:#b44">&#34;POLYGON((...))&#34;</span><span style="color:#666">^^</span><span style="color:#a0a000">&lt;http://www.opengis.net/ont/geosparql#wktLiteral&gt;</span> <span style="color:#a2f;font-weight:bold">AS</span> <span style="color:#b8860b">?box</span>) .
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">FILTER</span>(<span style="color:#00f;font-weight:bold">geof</span>:<span style="color:#008000;font-weight:bold">sfContains</span>(<span style="color:#b8860b">?box</span>, <span style="color:#b8860b">?geomLit</span>))
</span></span></code></pre></div><p>Datasets can contain both Geo predicates and Geometry Literals without
interference. However, a dataset containing both types will only examine those
<code>Features</code> which have Geometry Literals for spatial relations, i.e. the check
for Geo predicates is a fallback when Geometry Literals aren&rsquo;t found.
Therefore, it is <strong>not</strong> recommended to insert new Geo predicate properties
after a dataset has been converted to GeoSPARQL structure (unless corresponding
Geometry and Geometry Literals are included).</p>
<h3 id="filter-functions">Filter Functions</h3>
<p>These filter functions are available in the
<code>http://jena.apache.org/function/spatial#</code> namespace and here use the prefix
<code>spatialF</code>.</p>
<table>
<thead>
<tr>
<th>Function Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><em>?wktString</em> <strong>spatialF:convertLatLon</strong>(<em>?lat</em>, <em>?lon</em>)</td>
<td>Converts Lat and Lon double values into WKT string of a Point with WGS84 SRS.</td>
</tr>
<tr>
<td><em>?wktString</em> <strong>spatialF:convertLatLonBox</strong>(<em>?latMin</em>, <em>?lonMin</em>, <em>?latMax</em>, <em>?lonMax</em>)</td>
<td>Converts Lat and Lon double values into WKT string of a Polygon forming a box with WGS84 SRS.</td>
</tr>
<tr>
<td><em>?boolean</em> <strong>spatialF:equals</strong>(<em>?geomLit1</em>, <em>?geomLit2</em>)</td>
<td>True, if <em>geomLit1</em> is spatially equal to <em>geomLit2</em>.</td>
</tr>
<tr>
<td><em>?boolean</em> <strong>spatialF:nearby</strong>(<em>?geomLit1</em>, <em>?geomLit2</em>, <em>?distance</em>, <em>?unitsURI</em>)</td>
<td>True, if <em>geomLit1</em> is within <em>distance</em> of <em>geomLit2</em> using the distance <em>units</em>.</td>
</tr>
<tr>
<td><em>?boolean</em> <strong>spatialF:withinCircle</strong>(<em>?geomLit1</em>, <em>?geomLit2</em>, <em>?distance</em>, <em>?unitsURI</em>)</td>
<td>True, if <em>geomLit1</em> is within <em>distance</em> of <em>geomLit2</em> using the distance <em>units</em>.</td>
</tr>
<tr>
<td><em>?radians</em> <strong>spatialF:angle</strong>(<em>?x1</em>, <em>?y1</em>, <em>?x2</em>, <em>?y2</em>)</td>
<td>Angle clockwise from y-axis from Point(x1,y1) to Point (x2,y2) in 0 to 2Ï€ radians.</td>
</tr>
<tr>
<td><em>?degrees</em> <strong>spatialF:angleDeg</strong>(<em>?x</em>, <em>?y1</em>, <em>?x2</em>, <em>?y2</em>)</td>
<td>Angle clockwise from y-axis from Point(x1,y1) to Point (x2,y2) in 0 to 360 degrees.</td>
</tr>
<tr>
<td><em>?distance</em> <strong>spatialF:distance</strong>(<em>?geomLit1</em>, <em>?geomLit2</em>, <em>?unitsURI</em>)</td>
<td>Distance between two Geometry Literals in distance <em>units</em>. Chooses distance measure based on SRS type. Great Circle distance for Geographic SRS and Euclidean otherwise.</td>
</tr>
<tr>
<td><em>?radians</em> <strong>spatialF:azimuth</strong>(<em>?lat1</em>, <em>?lon1</em>, <em>?lat2</em>, <em>?lon2</em>)</td>
<td>Forward azimuth clockwise from North between two Lat/Lon Points in 0 to 2Ï€ radians.</td>
</tr>
<tr>
<td><em>?degrees</em> <strong>spatialF:azimuthDeg</strong>(<em>?lat1</em>, <em>?lon1</em>, <em>?lat2</em>, <em>?lon2</em>)</td>
<td>Forward azimuth clockwise from North between two Lat/Lon Points in 0 to 360 degrees.</td>
</tr>
<tr>
<td><em>?distance</em> <strong>spatialF:greatCircle</strong>(<em>?lat1</em>, <em>?lon1</em>, <em>?lat2</em>, <em>?lon2</em>, <em>?unitsURI</em>)</td>
<td>Great Circle distance (Vincenty formula) between two Lat/Lon Points in distance <em>units</em>.</td>
</tr>
<tr>
<td><em>?distance</em> <strong>spatialF:greatCircleGeom</strong>(<em>?geomLit1</em>, <em>?geomLit2</em>, <em>?unitsURI</em>)</td>
<td>Great Circle distance (Vincenty formula) between two Geometry Literals in distance <em>units</em>. Use <code>http://www.opengis.net/def/function/geosparql/distance</code> from GeoSPARQL standard for Euclidean distance.</td>
</tr>
<tr>
<td><em>?geomLit2</em> <strong>spatialF:transform</strong>(<em>?geomLit1</em>, <em>?datatypeURI</em>, <em>?srsURI</em>)</td>
<td>Transform Geometry Literal by Datatype and SRS.</td>
</tr>
<tr>
<td><em>?geomLit2</em> <strong>spatialF:transformDatatype</strong>(<em>?geomLit1</em>, <em>?datatypeURI</em>)</td>
<td>Transform Geometry Literal by Datatype.</td>
</tr>
<tr>
<td><em>?geomLit2</em> <strong>spatialF:transformSRS</strong>(<em>?geomLit1</em>, <em>?srsURI</em>)</td>
<td>Transform Geometry Literal by SRS.</td>
</tr>
</tbody>
</table>
<h3 id="property-functions">Property Functions</h3>
<p>These property functions are available in the <code>http://jena.apache.org/spatial#</code>
namespace and here use the prefix <code>spatial</code>. This is the same namespace as the
<code>jena-spatial</code> functions utilise and these form direct replacements. The
subject <code>Feature</code> may be bound, to test the pattern is true, or unbound, to find
all cases the pattern is true. These property functions require a <code>Spatial Index</code> to be setup for the dataset.</p>
<p>The optional <em>?limit</em> parameter restricts the number of results returned. The
default value is -1 which returns all results. No guarantee is given for
ordering of results. The optional <em>?unitsURI</em> parameter specifies the units of
a distance. The default value is kilometres through the string or resource
<code>http://www.opengis.net/def/uom/OGC/1.0/kilometre</code>.</p>
<p>The <code>spatial:equals</code> property function behaves the same way as the main
GeoSPARQL property functions. Either, both or neither of the subject and object
can be bound. A <code>Spatial Index</code> is <strong>not</strong> required for the dataset with the
<code>spatial:equals</code> property function.</p>
<table>
<thead>
<tr>
<th>Function Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><em>?spatialObject1</em> <strong>spatial:equals</strong> <em>?spatialObject2</em></td>
<td>Find <em>spatialObjects</em> (i.e. <em>features</em> or <em>geometries</em>) that are spatially equal.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:intersectBox</strong>(<em>?latMin</em> <em>?lonMin</em> <em>?latMax</em> <em>?lonMax</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that intersect the provided box, up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:intersectBoxGeom</strong>(<em>?geomLit1</em> <em>?geomLit2</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that intersect the provided box, up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:withinBox</strong>(<em>?latMin</em> <em>?lonMin</em> <em>?latMax</em> <em>?lonMax</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that intersect the provided box, up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:withinBoxGeom</strong>(<em>?geomLit1</em> <em>?geomLit2</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that are within the provided box, up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:nearby</strong>(<em>?lat</em> <em>?lon</em> <em>?radius</em> [ <em>?unitsURI</em> [ <em>?limit</em>]])</td>
<td>Find <em>features</em> that are within <em>radius</em> of the <em>distance</em> units, up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:nearbyGeom</strong>(<em>?geomLit</em> <em>?radius</em> [ <em>?unitsURI</em> [ <em>?limit</em>]])</td>
<td>Find <em>features</em> that are within <em>radius</em> of the <em>distance</em> units, up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:withinCircle</strong>(<em>?lat</em> <em>?lon</em> <em>?radius</em> [ <em>?unitsURI</em> [ <em>?limit</em>]])</td>
<td>Find <em>features</em> that are within <em>radius</em> of the <em>distance</em> units, up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:withinCircleGeom</strong>(<em>?geomLit</em> <em>?radius</em> [ <em>?unitsURI</em> [ <em>?limit</em>]])</td>
<td>Find <em>features</em> that are within <em>radius</em> of the <em>distance</em> units, up to the <em>limit</em>.</td>
</tr>
</tbody>
</table>
<p>The Cardinal Functions find all <code>Features</code> that are present in the specified
direction. In Geographic spatial reference systems (SRS), e.g. WGS84 and CRS84,
the East/West directions wrap around. Therefore, a search is made from the
shape&rsquo;s edge for up to half the range of the SRS (i.e. 180 degrees in WGS84) and
will continue across the East/West boundary if necessary. In other SRS,
e.g. Projected onto a flat plane, the East/West check is made from the shape&rsquo;s
edge to the farthest limit of the SRS range, i.e. there is no wrap around.</p>
<table>
<thead>
<tr>
<th>Cardinal Function Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><em>?feature</em> <strong>spatial:north</strong>(<em>?lat</em> <em>?lon</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that are North of the Lat/Lon point (point to +90 degrees), up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:northGeom</strong>(<em>?geomLit</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that are North of the Geometry Literal, up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:south</strong>(<em>?lat</em> <em>?lon</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that are South of the Lat/Lon point (point to -90 degrees), up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:southGeom</strong>(<em>?geomLit</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that are South of the Geometry Literal, up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:east</strong>(<em>?lat</em> <em>?lon</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that are East of the Lat/Lon point (point plus 180 degrees longitude, wrapping round), up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:eastGeom</strong>(<em>?geomLit</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that are East of the Geometry Literal, up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:west</strong>(<em>?lat</em> <em>?lon</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that are West of the Lat/Lon point (point minus 180 degrees longitude, wrapping round), up to the <em>limit</em>.</td>
</tr>
<tr>
<td><em>?feature</em> <strong>spatial:westGeom</strong>(<em>?geomLit</em> [ <em>?limit</em>])</td>
<td>Find <em>features</em> that are West of the Geometry Literal, up to the <em>limit</em>.</td>
</tr>
</tbody>
</table>
<h2 id="geometry-property-filter-functions">Geometry Property Filter Functions</h2>
<p>The GeoSPARQL standard provides a set of properties related to geometries, see
Section 8.4. These are applied on the Geometry resource and are automatically
determined if not asserted in the data. However, it may be necessary to
retrieve the properties of a Geometry Literal directly without an associated
Geometry resource. Filter functions to do this have been included as part of
the <code>http://www.opengis.net/def/function/geosparql/</code> namespace as a minor
variation to the GeoSPARQL standard. The relevant functions using the <code>geof</code>
prefix are:</p>
<table>
<thead>
<tr>
<th>Geometry Property Filter Function Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><em>?integer</em> <strong>geof:dimension</strong>(<em>?geometryLiteral</em>)</td>
<td>Topological dimension, e.g. 0 for Point, 1 for LineString and 2 for Polygon.</td>
</tr>
<tr>
<td><em>?integer</em> <strong>geof:coordinateDimension</strong>(<em>?geometryLiteral</em>)</td>
<td>Coordinate dimension, e.g. 2 for XY coordinates and 4 for XYZM coordinates.</td>
</tr>
<tr>
<td><em>?integer</em> <strong>geof:spatialDimension</strong>(<em>?geometryLiteral</em>)</td>
<td>Spatial dimension, e.g. 2 for XY coordinates and 3 for XYZM coordinates.</td>
</tr>
<tr>
<td><em>?boolean</em> <strong>geof:isEmpty</strong>(<em>?geometryLiteral</em>)</td>
<td>True, if geometry is empty.</td>
</tr>
<tr>
<td><em>?boolean</em> <strong>geof:isSimple</strong>(<em>?geometryLiteral</em>)</td>
<td>True, if geometry is simple.</td>
</tr>
<tr>
<td><em>?boolean</em> <strong>geof:isValid</strong>(<em>?geometryLiteral</em>)</td>
<td>True, if geometry is topologically valid.</td>
</tr>
</tbody>
</table>
<p>A dataset that follows the GeoSPARQL Feature-Geometry-GeometryLiteral can have
simpler SPARQL queries without needing to use these functions by taking
advantage of the Query Rewriting functionality. The <code>geof:isValid</code> filter
function and <code>geo:isValid</code> property for a Geometry resource are not part of the
GeoSPARQL standard but have been included as a minor variation.</p>
<h2 id="future-work">Future Work</h2>
<ul>
<li>Implementing GeoJSON as a <code>GeometryLiteral</code> serialisation (<a href="https://tools.ietf.org/html/rfc7946">https://tools.ietf.org/html/rfc7946</a>).
Producing GeoJSON is already possible with <strong>geof:asGeoJSON</strong>(<em>?geometryLiteral</em>).</li>
</ul>
<h2 id="contributors">Contributors</h2>
<p>The following individuals have made contributions to this project:</p>
<ul>
<li>Greg Albiston</li>
<li>Haozhe Chen</li>
<li>Taha Osman</li>
</ul>
<h2 id="why-use-this-implementation">Why Use This Implementation?</h2>
<p>There are several implementations of the GeoSPARQL standard. The conformance
and completeness of these implementations is difficult to ascertain and varies
between features.</p>
<p>However, the following may be of interest when considering whether to use this
implementation based on reviewing several alternatives.</p>
<table>
<thead>
<tr>
<th>This Implementation</th>
<th>Other Implementations</th>
</tr>
</thead>
<tbody>
<tr>
<td>Implements all six components of the GeoSPARQL standard.</td>
<td>Generally partially implement the Geometry Topology and Geometry Extensions. Do not implement the Query Rewrite Extension.</td>
</tr>
<tr>
<td>Pure Java and does not require a supporting relational database. Configuration requires a single line of code (although Apache SIS may need some setting up, see above).</td>
<td>Require setting up a database, configuring a geospatial extension and setting environment variables.</td>
</tr>
<tr>
<td>Uses Jena, which conforms to the W3C standards for RDF and SPARQL. New versions of the standards will quickly feed through.</td>
<td>Not fully RDF and SPARQL compliant, e.g. RDFS/OWL inferencing or SPARQL syntax. Adding your own schema may not produce inferences.</td>
</tr>
<tr>
<td>Automatically determines geometry properties and handles mixed cases of units or coordinate reference systems. The GeoSPARQL standard suggests this approach but does not require it.</td>
<td>Tend to produce errors or no results in these situations.</td>
</tr>
<tr>
<td>Performs indexing and caching on-demand which reduces set-up time and only performs calculations that are required.</td>
<td>Perform indexing in the data loading phase and initialisation phase, which can lead to lengthy delays (even on relatively small datasets).</td>
</tr>
<tr>
<td>Uses JTS which does not truncate coordinate precision and applies spatial equality.</td>
<td>May truncate coordinate precision and apply lexical equality, which is quicker but does not comply with the GeoSPARQL standard.</td>
</tr>
</tbody>
</table>
</article>
<aside class="text-muted align-self-start mb-3 mb-xl-5 p-0 d-none d-xl-flex flex-column sticky-top">
<h2 class="h6 sticky-top m-0 p-2 bg-body-tertiary">On this page</h2>
<nav id="TableOfContents">
<ul>
<li><a href="#getting-started">Getting Started</a></li>
<li><a href="#features">Features</a></li>
<li><a href="#additional-features">Additional Features</a>
<ul>
<li><a href="#sparql-query-configuration">SPARQL Query Configuration</a></li>
<li><a href="#querying-datasets--models-with-sparql">Querying Datasets &amp; Models with SPARQL</a></li>
<li><a href="#api-the-library-can-be-used-as-an-api-in-java--the-main-class-to-handle">API The library can be used as an API in Java. The main class to handle</a></li>
</ul>
</li>
<li><a href="#key-dependencies">Key Dependencies</a>
<ul>
<li><a href="#geosparql">GeoSPARQL</a></li>
<li><a href="#apache-sissis_data-environment-variable">Apache SIS/SIS_DATA Environment Variable</a></li>
<li><a href="#java-topology-suite">Java Topology Suite</a></li>
</ul>
</li>
<li><a href="#note">Note</a>
<ul>
<li><a href="#geosparql-schema">GeoSPARQL Schema</a></li>
<li><a href="#spatial-relations">Spatial Relations</a></li>
<li><a href="#spatial-relations-and-geometry-shapestypes">Spatial Relations and Geometry Shapes/Types</a></li>
<li><a href="#equals-relations">Equals Relations</a></li>
<li><a href="#query-rewrite-extension">Query Rewrite Extension</a></li>
<li><a href="#dataset-conversion">Dataset Conversion</a></li>
<li><a href="#spatial-index">Spatial Index</a></li>
<li><a href="#units-uri">Units URI</a></li>
</ul>
</li>
<li><a href="#geography-markup-language-support-gml">Geography Markup Language Support (GML)</a></li>
<li><a href="#apache-jena-spatial-functionswgs84-geo-predicates">Apache Jena Spatial Functions/WGS84 Geo Predicates</a>
<ul>
<li><a href="#supported-features">Supported Features</a></li>
<li><a href="#filter-functions">Filter Functions</a></li>
<li><a href="#property-functions">Property Functions</a></li>
</ul>
</li>
<li><a href="#geometry-property-filter-functions">Geometry Property Filter Functions</a></li>
<li><a href="#future-work">Future Work</a></li>
<li><a href="#contributors">Contributors</a></li>
<li><a href="#why-use-this-implementation">Why Use This Implementation?</a></li>
</ul>
</nav>
</aside>
</main>
</div>
</div>
</div>
<footer class="bd-footer py-4 py-md-5 mt-4 mt-lg-5 bg-body-tertiary">
<div class="container" style="font-size:80%" >
<p>
Copyright &copy; 2011&ndash;2024 The Apache Software Foundation, Licensed under the
<a href="https://www.apache.org/licenses/LICENSE-2.0">Apache License, Version 2.0</a>.
</p>
<p>
Apache Jena, Jena, the Apache Jena project logo, Apache and the Apache feather logos are trademarks of
The Apache Software Foundation.
<br/>
<a href="https://privacy.apache.org/policies/privacy-policy-public.html"
>Apache Software Foundation Privacy Policy</a>.
</p>
</div>
</footer>
<script src="/js/popper.min.js.js" type="text/javascript"></script>
<script src="/js/bootstrap.min.js" type="text/javascript"></script>
<script src="/js/improve.js" type="text/javascript"></script>
<script type="text/javascript">
(function() {
'use strict'
const links = document.querySelectorAll(`a[href="${window.location.pathname}"]`)
if (links !== undefined && links !== null) {
for (const link of links) {
link.classList.add('active')
let parentElement = link.parentElement
let count = 0
const levelsLimit = 4
while (['UL', 'LI'].includes(parentElement.tagName) && count <= levelsLimit) {
if (parentElement.tagName === 'LI') {
parentElement.querySelector('a:first-child').classList.add('active')
}
parentElement = parentElement.parentElement
count++
}
}
}
})()
</script>
</body>
</html>