Skip to content

Commit e34f76d

Browse files
MathiasVDACopilot
andauthored
feat: resolve geof:distance issues (#1)
* feat: trying to get metric distance calculation to work * feat: added even more dependencies * feat: use pom file and maven * fixed * Update Dockerfile Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent ffb4087 commit e34f76d

File tree

7 files changed

+178
-55
lines changed

7 files changed

+178
-55
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
data/
2+
lib/
3+
.vscode/

Dockerfile

Lines changed: 30 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
# Based on https://github.com/SemanticComputing/fuseki-docker/blob/master/Dockerfile
2-
# Optimized to download JAR files from Apache repositories
32

43
FROM eclipse-temurin:21-jre-alpine AS base
54

6-
# Allow version to be overridden during build
5+
# Allow versions to be overridden during build
76
ARG JENA_VERSION=5.4.0
87
ENV JENA_VERSION=${JENA_VERSION}
98

10-
# jq needed for tdb2.xloader, wget for downloading files, unzip for SIS datasets
11-
RUN apk add --update bash ca-certificates coreutils findutils jq pwgen ruby wget unzip && rm -rf /var/cache/apk/*
9+
ARG SIS_VERSION=1.4
10+
ENV SIS_VERSION=${SIS_VERSION}
11+
12+
ARG DERBY_VERSION=10.15.2.0
13+
ENV DERBY_VERSION=${DERBY_VERSION}
14+
15+
# Install Maven and required tools
16+
# jq needed for tdb2.xloader, unzip for SIS datasets
17+
RUN apk add --no-cache --update bash ca-certificates coreutils findutils jq pwgen ruby unzip maven && rm -rf /var/cache/apk/*
1218

1319
# Config and data
1420
ENV FUSEKI_BASE=/fuseki-base
@@ -20,64 +26,24 @@ ENV JENA_HOME=/jena
2026
ENV JENA_BIN=$JENA_HOME/bin
2127

2228
WORKDIR /tmp
23-
# Download, extract and install Fuseki
24-
RUN echo "Downloading Apache Jena Fuseki ${JENA_VERSION}..." && \
25-
wget -O fuseki.tar.gz "https://dlcdn.apache.org/jena/binaries/apache-jena-fuseki-${JENA_VERSION}.tar.gz" && \
26-
echo "Extracting Fuseki..." && \
27-
tar zxf fuseki.tar.gz && \
28-
mv apache-jena-fuseki* $FUSEKI_HOME && \
29-
rm fuseki.tar.gz && \
30-
cd $FUSEKI_HOME && rm -rf fuseki.war && \
31-
echo "Fuseki installation completed"
32-
33-
# Download the GeoSPARQL extension JAR
34-
RUN echo "Downloading GeoSPARQL extension ${JENA_VERSION}..." && \
35-
wget -O $FUSEKI_HOME/jena-fuseki-geosparql-${JENA_VERSION}.jar \
36-
"https://repo1.maven.org/maven2/org/apache/jena/jena-fuseki-geosparql/${JENA_VERSION}/jena-fuseki-geosparql-${JENA_VERSION}.jar" && \
37-
echo "GeoSPARQL extension downloaded"
3829

3930
# Download and install Apache SIS binary distribution
4031
ENV SIS_HOME=/apache-sis
41-
ENV SIS_VERSION=1.4
42-
ENV SIS_DATA=$FUSEKI_BASE/SIS_DATA
43-
RUN echo "Downloading Apache SIS binary distribution ${SIS_VERSION}..." && \
44-
wget -O /tmp/apache-sis-${SIS_VERSION}-bin.zip \
45-
"https://dlcdn.apache.org/sis/${SIS_VERSION}/apache-sis-${SIS_VERSION}-bin.zip" && \
46-
echo "Extracting Apache SIS..." && \
47-
cd /tmp && \
48-
unzip -q apache-sis-${SIS_VERSION}-bin.zip && \
49-
mv apache-sis-${SIS_VERSION} $SIS_HOME && \
50-
rm apache-sis-${SIS_VERSION}-bin.zip && \
51-
mkdir -p $SIS_DATA && \
52-
echo "Apache SIS binary distribution installed"
32+
ENV SIS_DATA=$FUSEKI_BASE/sis_data
33+
RUN mkdir -p $SIS_DATA && mkdir -p $SIS_HOME && mkdir -p $SIS_HOME/log
5334

5435
ENV PATH=$PATH:$SIS_HOME/bin
5536

56-
# Download, extract and install Jena tools
57-
RUN echo "Downloading Apache Jena ${JENA_VERSION}..." && \
58-
wget -O jena.tar.gz "https://dlcdn.apache.org/jena/binaries/apache-jena-${JENA_VERSION}.tar.gz" && \
59-
echo "Extracting Jena tools..." && \
60-
tar zxf jena.tar.gz && \
61-
mkdir -p $JENA_BIN && \
62-
mv apache-jena*/lib $JENA_HOME && \
63-
mv apache-jena*/bin/tdb1.xloader apache-jena*/bin/xload-* $JENA_BIN && \
64-
mv apache-jena*/bin/tdb2.xloader $JENA_BIN && \
65-
rm -rf apache-jena* && \
66-
rm jena.tar.gz && \
67-
echo "Jena tools installation completed"
68-
69-
# As "localhost" is often inaccessible within Docker container,
70-
# we'll enable basic-auth with a random admin password
71-
# (which we'll generate on start-up)
37+
# Use Maven to download all dependencies as JARs
38+
COPY pom.xml /tmp/pom.xml
39+
RUN mkdir -p /javalibs && \
40+
mvn dependency:copy-dependencies -DoutputDirectory=/javalibs -f /tmp/pom.xml && \
41+
echo "All dependencies downloaded to /javalibs"
42+
7243
COPY config/shiro.ini /jena-fuseki/shiro.ini
7344
COPY config/docker-entrypoint.sh /
7445
RUN chmod 755 /docker-entrypoint.sh
7546

76-
# SeCo extensions (commented out - file not found in current setup)
77-
# If you need this extension, place the JAR file in a bin/ directory and uncomment the line below
78-
# COPY bin/silk-arq-1.0.0-SNAPSHOT-with-dependencies.jar /javalibs/
79-
RUN mkdir -p /javalibs
80-
8147
# Fuseki config
8248
ENV ASSEMBLER=$FUSEKI_BASE/configuration/assembler.ttl
8349
COPY config/assembler.ttl $ASSEMBLER
@@ -90,7 +56,10 @@ RUN chgrp -R 0 $FUSEKI_BASE \
9056
&& chmod -R g+rwX $FUSEKI_BASE \
9157
&& chgrp -R 0 $SIS_HOME \
9258
&& chmod -R g+rX $SIS_HOME \
93-
&& chmod -R g+rwX $SIS_HOME/log
59+
&& chmod -R g+rwX $SIS_HOME/log \
60+
&& mkdir -p $FUSEKI_BASE/derby-logs \
61+
&& chgrp -R 0 $FUSEKI_BASE/derby-logs \
62+
&& chmod -R g+rwX $FUSEKI_BASE/derby-logs
9463

9564
# Tools for loading data
9665
ENV JAVA_CMD='java -cp "$FUSEKI_HOME/fuseki-server.jar:/javalibs/*"'
@@ -106,5 +75,12 @@ WORKDIR /jena-fuseki
10675
EXPOSE 3030
10776
USER 9008
10877

78+
# Healthcheck: check if Fuseki is responding on port 3030
79+
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
80+
CMD wget --spider --no-verbose http://localhost:3030/ || exit 1
81+
10982
ENTRYPOINT ["/docker-entrypoint.sh"]
110-
CMD ["java", "-cp", "*:/javalibs/*", "org.apache.jena.fuseki.main.cmds.FusekiServerCmd"]
83+
CMD ["java", "-cp", "*:/javalibs/*", "org.apache.jena.fuseki.main.cmds.FusekiServerCmd"]
84+
#CMD ["java", "-cp", "*:/javalibs/*", "-Dlog4j.configurationFile=/fuseki-base/log4j2.properties", "org.apache.jena.fuseki.main.cmds.FusekiServerCmd"]
85+
#CMD ["java", "-cp", "*:/javalibs/*", "-Dlog4j.configurationFile=/fuseki-base/log4j2.properties", "-DSIS_DATA=/fuseki-base/SIS_DATA", "-Dorg.apache.sis.referencing.factory.sql.EPSG.embedded=true", "-Dderby.stream.error.file=/fuseki-base/derby-logs/derby.log", "-Dderby.system.home=/fuseki-base/derby-logs", "org.apache.jena.fuseki.main.cmds.FusekiServerCmd"]
86+
#CMD ["java", "-cp", "*:/javalibs/*", "-Dlog4j.configurationFile=/fuseki-base/log4j2.properties", "-Dderby.stream.error.file=/fuseki-base/derby-logs/derby.log", "-DSIS_DATA=/fuseki-base/sis_data", "org.apache.jena.fuseki.main.cmds.FusekiServerCmd"]

README.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ This Docker container provides Apache Jena Fuseki with built-in GeoSPARQL suppor
2727

2828
More information about the GeoSPARQL implementation of Apache Jena Fuseki can be found in the [official documentation](https://jena.apache.org/documentation/geosparql/).
2929

30-
**Note**: This container includes Apache SIS command line tools to enable download of EPSG datasets. The SIS_DATA environment variable is configured to a directory inside /fuseki-base (recommended to as docker volume). It seems that this is insufficient for Jena Fuseki to properly transform coordinates or calculate metric distances for WGS84 coordinates.
30+
**Note**: This container includes Apache SIS command line tools to enable download of EPSG datasets. The SIS_DATA environment variable is configured to a directory inside /fuseki-base (recommended to mount as a docker volume).
31+
32+
**Note 2**: The GeoSPARQL extension of Apache Jena Fuseki 5.4.0 currently does not support geof:distance with a metric unit from a source EPSG that is not metric. You still need to use the vendor function spatialF:distance for this. Please see the example queries.
3133

3234
## Usage
3335

@@ -164,6 +166,27 @@ SELECT ?relation ?geometry1_label ?geometry2_label ?result WHERE {
164166
ORDER BY ?relation ?geometry1_label
165167
```
166168

169+
```sparql
170+
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
171+
PREFIX geof: <http://www.opengis.net/def/function/geosparql/>
172+
PREFIX uom: <http://www.opengis.net/def/uom/OGC/1.0/>
173+
PREFIX spatialf: <http://jena.apache.org/function/spatial#>
174+
175+
# Test GeoSPARQL distance calculation between two cities
176+
SELECT ?city1 ?city2 ?distance_km WHERE {
177+
VALUES (?city1 ?point1 ?city2 ?point2) {
178+
("London" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(-0.1276 51.5074)"^^geo:wktLiteral "Paris" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(2.3522 48.8566)"^^geo:wktLiteral)
179+
("New York" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(-74.0060 40.7128)"^^geo:wktLiteral "Boston" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(-71.0588 42.3601)"^^geo:wktLiteral)
180+
("Amsterdam" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(4.9041 52.3676)"^^geo:wktLiteral "Brussels" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(4.3517 50.8503)"^^geo:wktLiteral)
181+
}
182+
183+
# Calculate distance in kilometers
184+
# implementation of geof:distance in v5.4 does not support coordinate transformation to uom:metre for non-metric EPSG, so we use spatialf:distance
185+
BIND(spatialf:distance(?point1, ?point2, uom:metre) / 1000 AS ?distance_km)
186+
}
187+
ORDER BY ?distance_km
188+
```
189+
167190
## Building from Source
168191

169192
```bash
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
2+
PREFIX geof: <http://www.opengis.net/def/function/geosparql/>
3+
PREFIX uom: <http://www.opengis.net/def/uom/OGC/1.0/>
4+
5+
# Test basic GeoSPARQL geometry functions without UOM
6+
SELECT ?test_name ?point ?buffer_geom ?envelope_geom WHERE {
7+
8+
VALUES (?test_name ?lat ?lon ?buffer_distance) {
9+
("Amsterdam Central" 52.3791 4.9003 0.01)
10+
("Rotterdam Port" 51.9225 4.4792 0.02)
11+
("Utrecht Center" 52.0907 5.1214 0.015)
12+
}
13+
# Create point geometry from coordinates
14+
BIND(STRDT(CONCAT("<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(", STR(?lon), " ", STR(?lat), ")"), geo:wktLiteral) AS ?point)
15+
16+
# Create a buffer around the point (simple circular buffer)
17+
BIND(geof:buffer(?point, ?buffer_distance, uom:degree) AS ?buffer_geom)
18+
19+
# Get the envelope (bounding box) of the buffered geometry
20+
BIND(geof:envelope(?buffer_geom) AS ?envelope_geom)
21+
}
22+
ORDER BY ?test_name
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
2+
PREFIX geof: <http://www.opengis.net/def/function/geosparql/>
3+
PREFIX uom: <http://www.opengis.net/def/uom/OGC/1.0/>
4+
PREFIX spatialf: <http://jena.apache.org/function/spatial#>
5+
6+
# Test GeoSPARQL distance calculation between two cities
7+
SELECT ?city1 ?city2 ?distance_km WHERE {
8+
VALUES (?city1 ?point1 ?city2 ?point2) {
9+
("London" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(-0.1276 51.5074)"^^geo:wktLiteral "Paris" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(2.3522 48.8566)"^^geo:wktLiteral)
10+
("New York" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(-74.0060 40.7128)"^^geo:wktLiteral "Boston" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(-71.0588 42.3601)"^^geo:wktLiteral)
11+
("Amsterdam" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(4.9041 52.3676)"^^geo:wktLiteral "Brussels" "<http://www.opengis.net/def/crs/EPSG/0/4326> POINT(4.3517 50.8503)"^^geo:wktLiteral)
12+
}
13+
14+
# Calculate distance in kilometers
15+
BIND(spatialf:distance(?point1, ?point2, uom:metre) / 1000 AS ?distance_km)
16+
}
17+
ORDER BY ?distance_km
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
2+
PREFIX geof: <http://www.opengis.net/def/function/geosparql/>
3+
4+
# Test GeoSPARQL spatial relationships without UOM namespace
5+
# This query tests contains, intersects, and within relationships
6+
SELECT ?relation ?geometry1_label ?geometry2_label ?result WHERE {
7+
8+
# Define test geometries
9+
VALUES (?geometry1_label ?geometry1 ?geometry2_label ?geometry2 ?relation) {
10+
# Point within polygon test
11+
("City Center" "POINT(4.9041 52.3676)"^^geo:wktLiteral "Amsterdam Bounds" "POLYGON((4.8 52.3, 5.0 52.3, 5.0 52.4, 4.8 52.4, 4.8 52.3))"^^geo:wktLiteral "within")
12+
13+
# Line intersects polygon test
14+
("Highway" "LINESTRING(4.85 52.32, 4.95 52.38)"^^geo:wktLiteral "Amsterdam Bounds" "POLYGON((4.8 52.3, 5.0 52.3, 5.0 52.4, 4.8 52.4, 4.8 52.3))"^^geo:wktLiteral "intersects")
15+
16+
# Polygon contains point test
17+
("Large Area" "POLYGON((4.7 52.2, 5.1 52.2, 5.1 52.5, 4.7 52.5, 4.7 52.2))"^^geo:wktLiteral "Small Point" "POINT(4.9 52.35)"^^geo:wktLiteral "contains")
18+
19+
# Buffer test (point with buffer intersects line)
20+
("Station" "POINT(4.9 52.37)"^^geo:wktLiteral "Train Line" "LINESTRING(4.88 52.36, 4.92 52.38)"^^geo:wktLiteral "intersects")
21+
}
22+
23+
# Test the spatial relationship based on the relation type
24+
BIND(
25+
IF(?relation = "within", geof:sfWithin(?geometry1, ?geometry2),
26+
IF(?relation = "intersects", geof:sfIntersects(?geometry1, ?geometry2),
27+
IF(?relation = "contains", geof:sfContains(?geometry1, ?geometry2),
28+
false))) AS ?result
29+
)
30+
}
31+
ORDER BY ?relation ?geometry1_label

pom.xml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
<groupId>org.example</groupId>
6+
<artifactId>jena-fuseki-geosparql</artifactId>
7+
<version>1.0-SNAPSHOT</version>
8+
<dependencies>
9+
<dependency>
10+
<groupId>org.apache.jena</groupId>
11+
<artifactId>apache-jena-fuseki</artifactId>
12+
<type>pom</type>
13+
<version>${jena.version}</version>
14+
</dependency>
15+
<dependency>
16+
<groupId>org.apache.jena</groupId>
17+
<artifactId>jena-fuseki-geosparql</artifactId>
18+
<version>${jena.version}</version>
19+
</dependency>
20+
<dependency>
21+
<groupId>org.apache.jena</groupId>
22+
<artifactId>jena-geosparql</artifactId>
23+
<version>${jena.version}</version>
24+
</dependency>
25+
<dependency>
26+
<groupId>org.apache.jena</groupId>
27+
<artifactId>jena-core</artifactId>
28+
<version>${jena.version}</version>
29+
</dependency>
30+
31+
<dependency>
32+
<groupId>org.apache.jena</groupId>
33+
<artifactId>jena-arq</artifactId>
34+
<version>${jena.version}</version>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.apache.sis.non-free</groupId>
38+
<artifactId>sis-embedded-data</artifactId>
39+
<version>${sis.version}</version>
40+
</dependency>
41+
<dependency>
42+
<groupId>org.apache.sis.core</groupId>
43+
<artifactId>sis-referencing</artifactId>
44+
<version>${sis.version}</version>
45+
</dependency>
46+
</dependencies>
47+
<properties>
48+
<jena.version>5.4.0</jena.version>
49+
<sis.version>1.4</sis.version>
50+
</properties>
51+
</project>

0 commit comments

Comments
 (0)