diff --git a/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java b/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java index 5828965262702d36937192e32573faaaf6729bd9..b042100eba563d15f68592972a57aca6e5a2e0db 100644 --- a/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java +++ b/dbrepo-semantics-service/rest-service/src/main/java/at/tuwien/endpoints/QueryEndpoint.java @@ -15,6 +15,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; +import jakarta.ws.rs.PathParam; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -42,7 +43,7 @@ public class QueryEndpoint { this.ontologyService = ontologyService; } - @PostMapping("/ontology/{id}/query") + @GetMapping("/ontology/{id}/find/label/{label}") @PreAuthorize("hasAuthority('execute-semantic-query')") @Timed(value = "semantics.sparql.execute", description = "Time needed to execute a sparql query") @Operation(summary = "Register a new ontology", security = @SecurityRequirement(name = "bearerAuth")) @@ -52,22 +53,50 @@ public class QueryEndpoint { content = {@Content( mediaType = "application/json")}), }) - public ResponseEntity<List<EntityDto>> query(@NotNull @PathVariable("id") Long id, - @NotNull @Valid @RequestBody EntitySearchDto data) + public ResponseEntity<List<EntityDto>> findByLabel(@NotNull @PathVariable("id") Long id, + @NotNull @PathVariable("label") String label) throws OntologyNotFoundException, QueryMalformedException { - log.debug("endpoint execute query, id={}", id); + log.debug("endpoint execute query, id={}, label={}", id, label); final Ontology ontology = ontologyService.find(id); final List<EntityDto> dtos; if (ontology.getSparqlEndpoint() != null) { - log.debug("ontology with id {} has SPARQL endpoint", ontology.getId()); - dtos = sparqlService.find(ontology, data); + log.trace("ontology with id {} has SPARQL endpoint", ontology.getId()); + dtos = sparqlService.findByLabel(ontology, label); } else { - log.debug("ontology with id {} has RDF fallback", ontology.getId()); - dtos = rdfService.find(ontology, data); + log.trace("ontology with id {} has RDF fallback", ontology.getId()); + dtos = rdfService.findByLabel(ontology, label); } log.trace("create ontology resulted in dtos {}", dtos); return ResponseEntity.ok() .body(dtos); } + @GetMapping("/ontology/{id}/find/uri/{uri}") + @PreAuthorize("hasAuthority('execute-semantic-query')") + @Timed(value = "semantics.sparql.execute", description = "Time needed to execute a sparql query") + @Operation(summary = "Register a new ontology", security = @SecurityRequirement(name = "bearerAuth")) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Executed sparql query successfully", + content = {@Content( + mediaType = "application/json")}), + }) + public ResponseEntity<EntityDto> findByUri(@NotNull @PathVariable("id") Long id, + @NotNull @PathVariable("uri") String uri) + throws OntologyNotFoundException, QueryMalformedException { + log.debug("endpoint execute query, id={}, uri={}", id, uri); + final Ontology ontology = ontologyService.find(id); + final EntityDto dto; + if (ontology.getSparqlEndpoint() != null) { + log.trace("ontology with id {} has SPARQL endpoint", ontology.getId()); + dto = sparqlService.findByUri(ontology, uri); + } else { + log.trace("ontology with id {} has RDF fallback", ontology.getId()); + dto = rdfService.findByUri(ontology, uri); + } + log.trace("create ontology resulted in dto {}", dto); + return ResponseEntity.ok() + .body(dto); + } + } diff --git a/dbrepo-semantics-service/rest-service/src/main/resources/application-local.yml b/dbrepo-semantics-service/rest-service/src/main/resources/application-local.yml index cea3a41bb4f0e062040fe0eaa35a95246d66a0ae..ae658af3d756b555661d9aaf2d9ddcdf9858821e 100644 --- a/dbrepo-semantics-service/rest-service/src/main/resources/application-local.yml +++ b/dbrepo-semantics-service/rest-service/src/main/resources/application-local.yml @@ -43,7 +43,7 @@ logging: fda: ready.path: ./ready jwt: - issuer: http://localhost/realms/dbrepo + issuer: http://localhost:8080/realms/dbrepo public_key: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqqnHQ2BWWW9vDNLRCcxD++xZg/16oqMo/c1l+lcFEjjAIJjJp/HqrPYU/U9GvquGE6PbVFtTzW1KcKawOW+FJNOA3CGo8Q1TFEfz43B8rZpKsFbJKvQGVv1Z4HaKPvLUm7iMm8Hv91cLduuoWx6Q3DPe2vg13GKKEZe7UFghF+0T9u8EKzA/XqQ0OiICmsmYPbwvf9N3bCKsB/Y10EYmZRb8IhCoV9mmO5TxgWgiuNeCTtNCv2ePYqL/U0WvyGFW0reasIK8eg3KrAUj8DpyOgPOVBn3lBGf+3KFSYi+0bwZbJZWqbC/Xlk20Go1YfeJPRIt7ImxD27R/lNjgDO/MwIDAQAB client_secret: client-secret client_id: dbrepo-client diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/QueryService.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/QueryService.java index 71e4e5bf6643c17539202113a839be0893213eb1..3877665ac70769fdafad9aa10f1e7e7c00763c3b 100644 --- a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/QueryService.java +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/QueryService.java @@ -9,7 +9,9 @@ import java.util.List; public interface QueryService { - List<EntityDto> find(Ontology ontology, EntitySearchDto query) throws QueryMalformedException; + List<EntityDto> findByLabel(Ontology ontology, String label) throws QueryMalformedException; - List<EntityDto> find(Ontology ontology, EntitySearchDto query, Integer limit) throws QueryMalformedException; + List<EntityDto> findByLabel(Ontology ontology, String label, Integer limit) throws QueryMalformedException; + + EntityDto findByUri(Ontology ontology, String uri) throws QueryMalformedException; } diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/RdfServiceImpl.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/RdfServiceImpl.java index 632325569d1ab75fe981e446f9a768f873f85dce..2442878e07aeaa63a7a0939ed9f687bd1916fa3f 100644 --- a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/RdfServiceImpl.java +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/RdfServiceImpl.java @@ -8,10 +8,12 @@ import at.tuwien.service.QueryService; import lombok.extern.log4j.Log4j2; import org.apache.jena.query.*; import org.apache.jena.rdfconnection.RDFConnection; +import org.apache.jena.riot.RiotException; import org.apache.jena.shared.JenaException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -27,16 +29,16 @@ public class RdfServiceImpl implements QueryService { } @Override - public List<EntityDto> find(Ontology ontology, EntitySearchDto query) throws QueryMalformedException { - return find(ontology, query, 10); + public List<EntityDto> findByLabel(Ontology ontology, String label) throws QueryMalformedException { + return findByLabel(ontology, label, 10); } @Override - public List<EntityDto> find(Ontology ontology, EntitySearchDto query, Integer limit) throws QueryMalformedException { + public List<EntityDto> findByLabel(Ontology ontology, String label, Integer limit) throws QueryMalformedException { final String statement = String.join("\n", "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>", "SELECT ?o ?label {", - " ?o rdfs:label \"" + query.getLabel().replace("\"", "") + "\"@en .", + " ?o rdfs:label \"" + label.replace("\"", "") + "\"@en .", " ?o rdfs:label ?label .", " FILTER (langMatches(lang(?label), \"EN\" ) )", "} LIMIT " + limit); @@ -59,4 +61,36 @@ public class RdfServiceImpl implements QueryService { throw new QueryMalformedException("Failed to parse query: " + e.getMessage(), e); } } + + @Override + public EntityDto findByUri(Ontology ontology, String uri) throws QueryMalformedException { + final String statement = String.join("\n", + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>", + "SELECT ?label {", + " <" + uri + "> rdfs:label ?label .", + " FILTER (langMatches(lang(?label), \"EN\" ) )", + "} LIMIT 1"); + log.trace("compiled local query {}", statement); + final RDFConnection conn = RDFConnection.connect(this.dataset); + conn.load(ontology.getLocal()); + final List<EntityDto> results = new LinkedList<>(); + try { + conn.querySelect(statement, (qs) -> { + final EntityDto entity = EntityDto.builder() + .uri(qs.getResource("o").toString()) + .label(qs.getLiteral("label").getLexicalForm()) + .build(); + results.add(entity); + }); + conn.close(); + } catch (JenaException e) { + log.error("Failed to parse query: {}", e.getMessage()); + throw new QueryMalformedException("Failed to parse query: " + e.getMessage(), e); + } + if (results.size() != 1) { + log.error("Failed to find label: did not produce a result for uri {}", uri); + throw new QueryMalformedException("Failed to find uri: did not produce a result for uri " + uri); + } + return results.get(0); + } } diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/SparqlServiceImpl.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/SparqlServiceImpl.java index 321755731a12fde68c9ce9aa7063c51b5cbfc9a4..c4e156bd3aeb5eb0163225e45312bf16ee3e34f9 100644 --- a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/SparqlServiceImpl.java +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/SparqlServiceImpl.java @@ -1,7 +1,6 @@ package at.tuwien.service.impl; import at.tuwien.api.semantics.EntityDto; -import at.tuwien.api.semantics.EntitySearchDto; import at.tuwien.entities.semantics.Ontology; import at.tuwien.exception.QueryMalformedException; import at.tuwien.repository.jpa.OntologyRepository; @@ -53,18 +52,18 @@ public class SparqlServiceImpl implements QueryService { } @Override - public List<EntityDto> find(Ontology ontology, EntitySearchDto query) throws QueryMalformedException { - return find(ontology, query, 10); + public List<EntityDto> findByLabel(Ontology ontology, String label) throws QueryMalformedException { + return findByLabel(ontology, label, 10); } @Override - public List<EntityDto> find(Ontology ontology, EntitySearchDto query, Integer limit) throws QueryMalformedException { + public List<EntityDto> findByLabel(Ontology ontology, String label, Integer limit) throws QueryMalformedException { final String statement = String.join("\n", "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>", "SELECT * {", " SERVICE <" + ontology.getSparqlEndpoint() + "> {", " SELECT ?o ?label {", - " ?o rdfs:label \"" + query.getLabel().replace("\"", "") + "\"@en .", + " ?o rdfs:label \"" + label.replace("\"", "") + "\"@en .", " ?o rdfs:label ?label .", " FILTER (langMatches(lang(?label), \"EN\" ) )", " } LIMIT " + limit, @@ -89,4 +88,35 @@ public class SparqlServiceImpl implements QueryService { return results; } + @Override + public EntityDto findByUri(Ontology ontology, String uri) throws QueryMalformedException { + final String statement = String.join("\n", + "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>", + "SELECT * {", + " SERVICE <" + ontology.getSparqlEndpoint() + "> {", + " SELECT ?label {", + " <" + uri + "> rdfs:label ?label .", + " FILTER (langMatches(lang(?label), \"EN\" ) )", + " } LIMIT 1", + " }", + "}"); + log.trace("compiled remote query {}", statement); + try (QueryExecution execution = QueryExecutionFactory.create(statement, this.dataset.getDefaultModel())) { + final Iterator<QuerySolution> resultSet = execution.execSelect(); + while (resultSet.hasNext()) { + final QuerySolution solution = resultSet.next(); + final EntityDto entity = EntityDto.builder() + .uri(solution.get("o").toString()) + .label(solution.get("label").asLiteral().getLexicalForm()) + .build(); + return entity; + } + } catch (QueryParseException | IllegalArgumentException | RiotException e) { + log.error("Failed to parse query: {}", e.getMessage()); + throw new QueryMalformedException("Failed to parse query: " + e.getMessage(), e); + } + log.error("Failed to find label: did not produce a result for uri {}", uri); + throw new QueryMalformedException("Failed to find uri: did not produce a result for uri " + uri); + } + } diff --git a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java index cbb71ba6b49608ac6de102c84f2d49cf6dc5b5c9..5debf7f0975fee3de90b97f3b4701d793b51cd9c 100644 --- a/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java +++ b/dbrepo-semantics-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java @@ -54,12 +54,9 @@ public class TableServiceImpl implements TableService { final Table table = find(databaseId, tableId); final List<TableColumnEntityDto> suggestions = new LinkedList<>(); for (TableColumn column : table.getColumns()) { - final EntitySearchDto search = EntitySearchDto.builder() - .label(column.getName()) - .build(); for (Ontology ontology : ontologyService.findAll()) { final QueryService service = ontology.getSparqlEndpoint() != null ? sparqlService : rdfService; - suggestions.addAll(service.find(ontology, search, 3) + suggestions.addAll(service.findByLabel(ontology, column.getName(), 3) .stream() .map(e -> TableColumnEntityDto.builder() .databaseId(databaseId)