Skip to content
This repository has been archived by the owner on Mar 7, 2024. It is now read-only.

Commit

Permalink
Merge pull request #45 from Informatievlaanderen/feat/crowdscan
Browse files Browse the repository at this point in the history
Feat/crowdscan
  • Loading branch information
pj-cegeka authored Nov 6, 2023
2 parents 93ed147 + a800588 commit db69874
Show file tree
Hide file tree
Showing 19 changed files with 416 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class EventStreamConfig {
private String versionOfPath;
private String timestampPath;
private String timezoneId;
private String geoLocationPath;
private Map<String, String> propertyPredicates;

public String getMemberType() {
Expand Down Expand Up @@ -60,4 +61,12 @@ public String getVersionOfPath() {
public void setVersionOfPath(String versionOfPath) {
this.versionOfPath = versionOfPath;
}

public String getGeoLocationPath() {
return geoLocationPath;
}

public void setGeoLocationPath(String geoLocationPath) {
this.geoLocationPath = geoLocationPath;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package be.informatievlaanderen.vsds.demonstrator.member.application.services;

import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.RDFNode;

import java.util.List;

public interface PropertyExtractor {

List<RDFNode> getProperties(Model model);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package be.informatievlaanderen.vsds.demonstrator.member.application.services;

import org.apache.jena.query.*;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.RDFNode;

import java.util.ArrayList;
import java.util.List;

public class PropertyPathExtractor implements PropertyExtractor {

private static final String OBJECT_VAR_NAME = "object";
private static final String IRI_OPENING_SYMBOL = "<";
private final String queryString;

private PropertyPathExtractor(String propertyPath) {
queryString = "SELECT * where { ?subject %s ?object }".formatted(propertyPath);
}

/**
* This factory method was provided for backwards compatibility.
* In the past we supported properties to be provided as strings in a non IRI
* format.
* When a property is provided as a plain string, we wrap it to an IRI.
* NOTE: Does not work with property paths -> ex:foo/ex:bar will not get auto
* wrapping.
*/
public static PropertyPathExtractor from(String propertyPath) {
return propertyPath.startsWith(IRI_OPENING_SYMBOL)
? new PropertyPathExtractor(propertyPath)
: new PropertyPathExtractor("<%s>".formatted(propertyPath));
}

@Override
public List<RDFNode> getProperties(Model model) {
final Query query = QueryFactory.create(queryString);
try (QueryExecution queryExecution = QueryExecutionFactory.create(query, model)) {
ResultSet resultSet = queryExecution.execSelect();

List<RDFNode> results = new ArrayList<>();
while (resultSet.hasNext()) {
results.add(resultSet.next().get(OBJECT_VAR_NAME));
}
return results;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import be.informatievlaanderen.vsds.demonstrator.member.application.config.EventStreamConfig;
import be.informatievlaanderen.vsds.demonstrator.member.application.exceptions.NoGeometryProvidedException;
import be.informatievlaanderen.vsds.demonstrator.member.application.services.PropertyPathExtractor;
import be.informatievlaanderen.vsds.demonstrator.member.domain.member.entities.Member;
import org.apache.jena.geosparql.implementation.GeometryWrapper;
import org.apache.jena.geosparql.implementation.vocabulary.SRS_URI;
Expand All @@ -15,6 +16,7 @@
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -42,7 +44,7 @@ public Model getModel() {
}

public Member getMember(EventStreamConfig eventStreamConfig) throws FactoryException, TransformException {
Geometry geometry = getGeometry();
Geometry geometry = getGeometry(eventStreamConfig);
String memberId = getMemberId(eventStreamConfig);
String isVersionOf = getIsVersionOf(eventStreamConfig);
String timestampString = getTimestamp(eventStreamConfig);
Expand All @@ -64,8 +66,14 @@ private LocalDateTime getTimestamp(ZoneId timezoneId, String timestampString) {
return timestamp;
}

private Geometry getGeometry() throws FactoryException, TransformException {
List<RDFNode> wktNodes = model.listObjectsOfProperty(model.createProperty("http://www.opengis.net/ont/geosparql#asWKT")).toList();
private Geometry getGeometry(EventStreamConfig config) throws FactoryException, TransformException {
List<RDFNode> wktNodes = new ArrayList<>();
if(config.getGeoLocationPath() != null) {
wktNodes.addAll(PropertyPathExtractor.from(config.getGeoLocationPath()).getProperties(model));
}
else {
wktNodes.addAll(model.listObjectsOfProperty(model.createProperty("http://www.opengis.net/ont/geosparql#asWKT")).toList());
}
if (wktNodes.isEmpty()) {
throw new NoGeometryProvidedException();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@ protected void initRepo(RepositoryManager repositoryManager) {
} catch (Exception e) {
log.error("Could not create repository. Reason: {}", e.getMessage());
}
// possibly temp solution to separate locations from other members
try {
String locationsRepoId = "locations";
if(!repositoryManager.hasRepositoryConfig(locationsRepoId)) {
String indeces = "spoc,cspo";
NativeStoreConfig storeConfig = new NativeStoreConfig(indeces);
RepositoryImplConfig repositoryImplConfig = new SailRepositoryConfig(storeConfig);
RepositoryConfig config = new RepositoryConfig(locationsRepoId, repositoryImplConfig);
repositoryManager.addRepositoryConfig(config);
log.info("Created repository with id: {}", locationsRepoId);
}
} catch (Exception e) {
log.error("Could not create repository. Reason: {}", e.getMessage());
}
}

@Override
Expand Down
2 changes: 2 additions & 0 deletions backend/src/main/resources/crowdscan/crowdscan-locaties.nq
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<https://crowdscan.be/id/zone/${environment}/${zone}> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <https://crowdscan.be/ns/Zone> .
<https://crowdscan.be/id/zone/${environment}/${zone}> <http://www.opengis.net/ont/geosparql#asWKT> "${geometry}"^^<http://www.opengis.net/ont/geosparql#wktLiteral> .
5 changes: 5 additions & 0 deletions demonstrator.env
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ LDES_STREAMS_BLUEBIKES_PROPERTYPREDICATES_FULLNAME=http://schema.org/name
#LDES_STREAMS_BLUEBIKES_PROPERTYPREDICATES_CAPACITY=http://schema.mobivoc.org/#totalCapacity
LDES_STREAMS_BLUEBIKES_PROPERTYPREDICATES_AVAILABLE=http://schema.mobivoc.org/#currentValue
#LDES_STREAMS_BLUEBIKES_PROPERTYPREDICATES_USED=https://w3id.org/gbfs#bikes_in_use
LDES_STREAMS_CROWDSCAN_MEMBERTYPE=http://def.isotc211.org/iso19156/2011/Observation#OM_Observation
LDES_STREAMS_CROWDSCAN_TIMESTAMPPATH=http://www.w3.org/ns/prov#generatedAtTime
LDES_STREAMS_CROWDSCAN_VERSIONOFPATH=http://purl.org/dc/terms/isVersionOf
LDES_STREAMS_CROWDSCAN_GEOLOCATIONPATH=<http://def.isotc211.org/iso19156/2011/SamplingSurface#SF_SamplingSurface.shape>/<http://www.opengis.net/ont/geosparql#asWKT>
LDES_STREAMS_CROWDSCAN_PROPERTYPREDICATES_DENSITY=http://schema.org/value
GRAPHDB_URL=http://rdf4j-server:8080/rdf4j-server/repositories/
GRAPHDB_REPOSITORYID=test
SERVER_PORT=8080
4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
services:

data-provider:
image: ghcr.io/informatievlaanderen/ldi-orchestrator:20230927142432
image: ghcr.io/informatievlaanderen/ldi-orchestrator:latest
container_name: demonstrator-data-provider
ports:
- 8082:8080
volumes:
- ./gipod.config.yml:/ldio/application.yml:ro
- ./rml:/ldio/rml:ro
- ./sparql:/ldio/sparql:ro
- ./jsonld:/ldio/jsonld:ro
depends_on:
rdf4j-server:
condition: service_healthy
Expand Down Expand Up @@ -64,6 +65,7 @@ services:
networks:
- demonstrator


networks:
demonstrator:
driver: bridge
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/components/map/composables/usePopup.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ export function usePopup(collection, properties) {
<img class="popup-grid-icon popup-bluebike-icon" src="${bikeIcon}">
<span class="popup-title body-small-regular">${properties.fullname}</span>
<span>${properties.available}</span><b>beschikbare ${getBikeString(properties.available)}</b>
</div>`
case "crowdscan":
return `<div class="popup-grid body body-xxsmall-regular">
<span>personen dichtheid: ${properties.density}</span>
</div>`

}
Expand Down
5 changes: 5 additions & 0 deletions frontend/streams.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
"id": "bluebikes",
"fullName": "Blue Bikes",
"color": "#05c"
},
{
"id": "crowdscan",
"fullName": "CrowdScan",
"color": "#A4E2EB"
}
]
}
45 changes: 44 additions & 1 deletion gipod.config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,47 @@ orchestrator:
- name: be.vlaanderen.informatievlaanderen.ldes.ldio.LdioHttpOut
config:
endpoint: http://host.docker.internal:8084/api/bluebikes/members
content-type: application/n-quads
content-type: application/n-quads
- name: crowdscan-observations-pipeline
input:
name: be.vlaanderen.informatievlaanderen.ldes.ldi.client.LdioLdesClient
config:
url: https://azure.crowdscan.be/ldes-scewc/observations
transformers:
- name: be.vlaanderen.informatievlaanderen.ldes.ldi.SparqlConstructTransformer
config:
query: ./sparql/crowdscan.add-query.rq
infer: true
- name: be.vlaanderen.informatievlaanderen.ldes.ldio.LdioHttpEnricher
config:
url-property-path: https://crowdscan.be/ns/HttpRequest.url
body-property-path: https://crowdscan.be/ns/HttpRequest.body
http-method-property-path: https://crowdscan.be/ns/HttpRequest.method
header-property-path: https://crowdscan.be/ns/HttpRequest.header
adapter:
name: be.vlaanderen.informatievlaanderen.ldes.ldi.RdfAdapter
- name: be.vlaanderen.informatievlaanderen.ldes.ldi.SparqlConstructTransformer
config:
query: ./sparql/crowdscan.remove-query.rq
infer: false
outputs:
- name: be.vlaanderen.informatievlaanderen.ldes.ldi.RepositoryMaterialiser
config:
sparql-host: http://rdf4j-server:8080/rdf4j-server
repository-id: test
named-graph: http://crowdscan
- name: be.vlaanderen.informatievlaanderen.ldes.ldio.LdioHttpOut
config:
endpoint: http://host.docker.internal:8084/api/crowdscan/members
content-type: application/n-quads
- name: crowdscan-locations-pipeline
input:
name: be.vlaanderen.informatievlaanderen.ldes.ldi.client.LdioLdesClient
config:
url: https://azure.crowdscan.be/ldes-scewc/zones
outputs:
- name: be.vlaanderen.informatievlaanderen.ldes.ldi.RepositoryMaterialiser
config:
sparql-host: http://rdf4j-server:8080/rdf4j-server
repository-id: locations
named-graph: http://crowdscan-locations
14 changes: 14 additions & 0 deletions jsonld/count.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"@context": {
"@vocab": "https://www.crowdscan.be/ns/count#",
"time": {
"@type": "http://www.w3.org/2001/XMLSchema#DateTime"
},
"timedelta": {
"@type": "http://www.w3.org/2001/XMLSchema#int"
},
"regions": {
"@container": "@list"
}
}
}
11 changes: 11 additions & 0 deletions jsonld/map.jsonld
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"@context": [
{
"@vocab": "https://www.crowdscan.be/ns/map#",
"last_updated": {
"@type": "http://www.w3.org/2001/XMLSchema#DateTime"
}
},
"http://geojson.org/geojson-ld/geojson-context.jsonld"
]
}
50 changes: 50 additions & 0 deletions sparql/count.to-observation.rq
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX schema: <http://schema.org/>
PREFIX time: <http://www.w3.org/2006/time#>
PREFIX : <https://www.crowdscan.be/ns/count#>

CONSTRUCT {

GRAPH ?observation {
?observation a :Observation ;
:time ?time ;
:value ?value ;
:environment ?environment ;
:timedelta ?delta ;
:region ?zone .
}

} WHERE {

?header :environment ?environment .
?header :time ?time .
?header :timedelta ?timedelta .
bind(strdt(concat("-PT", str(?timedelta), "M"), xsd:duration) as ?delta) .

?payload :payload ?regions .
{
SELECT (count(?first) as ?zoneCount) WHERE { ?list rdf:first ?first . }
}

OPTIONAL { filter(?zoneCount = 1)
?list rdf:first ?value .
bind(0 as ?zone) .
}

OPTIONAL { filter(?zoneCount > 1)
{
SELECT ?value (count(?mid) as ?zone)
WHERE
{
?regions rdf:rest* ?mid .
?mid rdf:rest ?node .
?node rdf:first ?value .
}
GROUP BY ?node ?value
}
}

bind(uri(concat("https://crowdscan.be/id/observation/", ?environment, "/", str(?zone))) as ?observation) .

}
30 changes: 30 additions & 0 deletions sparql/crowdscan.add-query.rq
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>

PREFIX : <https://crowdscan.be/ns/>
PREFIX http: <https://crowdscan.be/ns/HttpRequest.>
PREFIX obs: <http://def.isotc211.org/iso19156/2011/Observation#>
PREFIX prov: <http://www.w3.org/ns/prov#>

CONSTRUCT {
?request a :HttpRequest .
?request http:url ?url .
?request http:body ?body .
?request http:method "POST" .
?request http:header ?type .
?request http:header ?accept .
} WHERE {
?obs rdf:type obs:OM_Observation .
?obs obs:OM_Observation.featureOfInterest ?loc .
?obs prov:generatedAtTime ?obstime .


bind(concat(replace(replace(str(?loc), "www.crowdscan.be", "crowdscan.be"),"box4","beacon"), "/") as ?locpart) .

# set HTTP request parameters
bind(bnode() as ?request) .
bind("http://rdf4j-server:8080/rdf4j-server/repositories/locations" as ?url) .
bind(concat("describe ?zone From <http://crowdscan-locations> Where { { select (max(?t) as ?max) Where { ?z <http://www.w3.org/ns/prov#generatedAtTime> ?time . Filter(?t < \"", str(?obstime), "\") . bind(str(?time) as ?t) . } } bind(IRI(concat(\"", ?locpart, "\", ?max)) as ?zone) . }") as ?body) .
bind("Content-Type: application/sparql-query" as ?type) .
bind("Accept: application/n-quads" as ?accept) .
}
15 changes: 15 additions & 0 deletions sparql/crowdscan.remove-query.rq
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
PREFIX : <https://crowdscan.be/ns/>


CONSTRUCT {
?s ?p ?o .
}
WHERE {
?s ?p ?o .

{SELECT ?request
WHERE {
?request a :HttpRequest .
}}
FILTER(?s != ?request)
}
Loading

0 comments on commit db69874

Please sign in to comment.