Skip to content

Commit

Permalink
Update QAnswer components (#315)
Browse files Browse the repository at this point in the history
* update QB QAnswer Wrapper for new QAnswer API

Remove redundant functionality and exclusively return (and annotate)
SPARQL result query candidates, alongside a possibly enhanced text
question.

Split SPARQL INSERT annotations for ImprovedQuestion and AnswerSPARQL.

* update QBE QAnswer wrapper to use new QAnswer API

* small changes to README files
  • Loading branch information
heinpa authored Oct 10, 2023
1 parent c5d4415 commit ecdaf49
Show file tree
Hide file tree
Showing 15 changed files with 228 additions and 324 deletions.
1 change: 0 additions & 1 deletion qanary-component-QB-QAnswer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ Consequently, your request to the QAnswer API might be more precise.
## Background

[QAnswer](https://www.qanswer.eu/) is an API capable of retrieving data from different knowledge graphs.
An example is available at [https://qanswer-frontend.univ-st-etienne.fr/](https://qanswer-frontend.univ-st-etienne.fr/).

## Examples

Expand Down
4 changes: 2 additions & 2 deletions qanary-component-QB-QAnswer/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>eu.wdaqua.qanary.component</groupId>
<artifactId>qanary-component-QB-QAnswer</artifactId>
<version>3.1.6</version>
<version>4.0.0</version>

<parent>
<groupId>org.springframework.boot</groupId>
Expand All @@ -13,7 +13,7 @@
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>11</java.version>
<java.version>17</java.version>
<qanary.version>[3.7.1,4.0.0)</qanary.version>
<spring-boot-admin.version>2.7.10</spring-boot-admin.version>
<docker.image.prefix>qanary</docker.image.prefix>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import java.util.List;
import java.util.Map;

import org.apache.jena.datatypes.xsd.XSDDatatype;
import org.apache.jena.query.QuerySolution;
import org.apache.jena.query.QuerySolutionMap;
import org.apache.jena.query.ResultSet;
Expand All @@ -23,21 +22,18 @@
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import com.google.gson.JsonObject;

import eu.wdaqua.qanary.commons.QanaryExceptionNoOrMultipleQuestions;
import eu.wdaqua.qanary.commons.QanaryMessage;
import eu.wdaqua.qanary.commons.QanaryQuestion;
import eu.wdaqua.qanary.commons.QanaryUtils;
import eu.wdaqua.qanary.commons.triplestoreconnectors.QanaryTripleStoreConnector;
import eu.wdaqua.qanary.communications.RestTemplateWithCaching;
import eu.wdaqua.qanary.component.QanaryComponent;
import eu.wdaqua.qanary.component.qanswer.qb.messages.QAnswerRequest;
import eu.wdaqua.qanary.component.qanswer.qb.messages.QAnswerResult;
import eu.wdaqua.qanary.component.qanswer.qb.messages.QAnswerResult.QAnswerQueryCandidate;
import eu.wdaqua.qanary.exceptions.SparqlQueryFailed;
import net.minidev.json.JSONObject;

Expand Down Expand Up @@ -110,7 +106,7 @@ public URI getEndpoint() {
/**
* starts the annotation process
*
* @throws SparqlQueryFailed
* @throws Exception
*/
@Override
public QanaryMessage process(QanaryMessage myQanaryMessage) throws Exception {
Expand Down Expand Up @@ -143,17 +139,29 @@ public QanaryMessage process(QanaryMessage myQanaryMessage) throws Exception {
List<NamedEntity> retrievedNamedEntities = getNamedEntitiesOfQuestion(myQanaryQuestion,
myQanaryQuestion.getInGraph());

// STEP 2: enriching of query and fetching SPARQL query candidates from the
// QAnswer API
String questionStringWithResources = computeQuestionStringWithReplacedResources(questionString,
retrievedNamedEntities, threshold);

// STEP 2: compute new information about the question

// enriching of query, based on recognized resources
String questionStringWithResources = computeQuestionStringWithReplacedResources(
questionString, retrievedNamedEntities, threshold);
// fetching SPARQL query candidates from the QAnswer API
QAnswerResult result = requestQAnswerWebService(endpoint, questionStringWithResources, lang, knowledgeBaseId, user);

// STEP 3: add new information to Qanary triplestore
String sparql = getSparqlInsertQuery(myQanaryQuestion.getOutGraph(), result);
logger.debug("created SPARQL query: {}", sparql);
QanaryTripleStoreConnector connector = myQanaryUtils.getQanaryTripleStoreConnector();
connector.update(sparql);
// STEP 3: add the new information to Qanary triplestore

// get sparql insert for improved question
URI graph = myQanaryQuestion.getOutGraph();
URI questionUri = myQanaryQuestion.getUri();
String sparqlImprovedQuestion = getSparqlInsertQueryForImprovedQuestion(graph, questionUri, result);
logger.debug("created SPARQL query for improved question: {}", sparqlImprovedQuestion);
myQanaryUtils.getQanaryTripleStoreConnector().update(sparqlImprovedQuestion);

List<String> sparqlQueryCandidates = getSparqlInsertQueriesForQueryCandidates(graph, questionUri, result);
for (String sparql : sparqlQueryCandidates) {
logger.debug("created SPARQL query for query candidate: {}", sparql);
myQanaryUtils.getQanaryTripleStoreConnector().update(sparql);
}

return myQanaryMessage;
}
Expand Down Expand Up @@ -197,13 +205,13 @@ protected List<NamedEntity> getNamedEntitiesOfQuestion(QanaryQuestion<String> my
LinkedList<NamedEntity> namedEntities = new LinkedList<>();

QuerySolutionMap bindingsForSelectAnnotations = new QuerySolutionMap();
bindingsForSelectAnnotations.add("GRAPH", ResourceFactory.createResource(myQanaryQuestion.getOutGraph().toASCIIString()));
bindingsForSelectAnnotations.add("QUESTION_URI", ResourceFactory.createResource(myQanaryQuestion.getUri().toASCIIString()));
bindingsForSelectAnnotations.add("GRAPH", ResourceFactory.createResource(myQanaryQuestion.getOutGraph().toASCIIString()));
bindingsForSelectAnnotations.add("QUESTION_URI", ResourceFactory.createResource(myQanaryQuestion.getUri().toASCIIString()));

// get the template of the SELECT query
String sparqlGetAnnotations = this.loadQueryFromFile(FILENAME_GET_ANNOTATED_ENTITIES, bindingsForSelectAnnotations);
logger.info("SPARQL query: {}", sparqlGetAnnotations);

// get the template of the SELECT query
String sparqlGetAnnotations = this.loadQueryFromFile(FILENAME_GET_ANNOTATED_ENTITIES, bindingsForSelectAnnotations);
logger.info("SPARQL query: {}", sparqlGetAnnotations);
boolean ignored = false;
Float score;
int start;
Expand Down Expand Up @@ -245,9 +253,9 @@ protected List<NamedEntity> getNamedEntitiesOfQuestion(QanaryQuestion<String> my
return namedEntities;
}

private String loadQueryFromFile(String filenameWithRelativePath, QuerySolutionMap bindings) throws IOException {
return QanaryTripleStoreConnector.readFileFromResourcesWithMap(filenameWithRelativePath, bindings);
}
private String loadQueryFromFile(String filenameWithRelativePath, QuerySolutionMap bindings) throws IOException {
return QanaryTripleStoreConnector.readFileFromResourcesWithMap(filenameWithRelativePath, bindings);
}

/**
* create a QAnswer-compatible format of the question
Expand Down Expand Up @@ -298,73 +306,45 @@ private String cleanStringForSparqlQuery(String myString) {
return myString.replaceAll("\"", "\\\"").replaceAll("\n", "");
}

/**
* creates the SPARQL query for inserting the data into Qanary triplestore
* <p>
* data can be retrieved via SPARQL 1.1 from the Qanary triplestore using:
*
* <pre>
*
* SELECT * FROM <YOURGRAPHURI> WHERE {
* ?s ?p ?o ;
* a ?type.
* VALUES ?t {
* qa:AnnotationOfAnswerSPARQL qa:SparqlQuery
* qa:AnnotationOfImprovedQuestion qa:ImprovedQuestion
* qa:AnnotationAnswer qa:Answer
* qa:AnnotationOfAnswerType qa:AnswerType
* }
* }
* ORDER BY ?type
* </pre>
*
* @param outgraph
* @param result
* @return
* @throws QanaryExceptionNoOrMultipleQuestions
* @throws URISyntaxException
* @throws SparqlQueryFailed
*/
String getSparqlInsertQuery(URI outgraph, QAnswerResult result)
throws QanaryExceptionNoOrMultipleQuestions, URISyntaxException, SparqlQueryFailed {
public List<String> getSparqlInsertQueriesForQueryCandidates(
URI graph, URI questionUri, QAnswerResult result)
throws QanaryExceptionNoOrMultipleQuestions, URISyntaxException, SparqlQueryFailed, IOException {

// the computed answer's SPARQL query needs to be cleaned
String improvedQuestion = cleanStringForSparqlQuery(result.getQuestion());
List<String> insertQueries = new LinkedList<>();

for (QAnswerQueryCandidate queryCandidate : result.getQueryCandidates()) {
// define the parameters for the SPARQL INSERT query
QuerySolutionMap bindings = new QuerySolutionMap();
// use the variable names defined in method insertAnnotationOfAnswerSPARQL
bindings.add("graph", ResourceFactory.createResource(graph.toASCIIString()));
bindings.add("targetQuestion", ResourceFactory.createResource(questionUri.toASCIIString()));
bindings.add("selectQueryThatShouldComputeTheAnswer", ResourceFactory.createStringLiteral(queryCandidate.getQueryString()));
bindings.add("confidence", ResourceFactory.createTypedLiteral(queryCandidate.getScore()));
bindings.add("application", ResourceFactory.createResource("urn:qanary:" + this.applicationName));

int counter = 0; // starts at 0
String annotationsToBeInserted = "";
String bindForInsert = "";
for (JsonObject answer : result.getValues()) {

logger.debug("{}. QAnswer query candidate: {}", counter, answer.toString());

annotationsToBeInserted += "" //
+ "\n" //
+ " ?annotationSPARQL" + counter + " a qa:AnnotationOfAnswerSPARQL ; \n" //
+ " oa:hasTarget ?question ; \n" //
+ " oa:hasBody ?sparql" + counter + " ; \n" //
+ " oa:annotatedBy ?service ; \n" //
+ " oa:annotatedAt ?time ; \n" //
+ " qa:score \"" + answer.get("confidence").getAsDouble() + "\"^^xsd:double . \n" //
//
+ " ?sparql" + counter + " a qa:SparqlQuery ; \n" //
+ " qa:hasPosition \"" + counter + "\"^^xsd:nonNegativeInteger ; \n" //
+ " rdf:value \"\"\"" + answer.get("query").getAsString() + "\"\"\"^^xsd:string . \n"; //
bindForInsert += " BIND (IRI(str(RAND())) AS ?annotationSPARQL" + counter + ") . \n" //
+ " BIND (IRI(str(RAND())) AS ?sparql" + counter + ") . \n"; //

counter++;
// get the template of the INSERT query
String sparql = QanaryTripleStoreConnector.insertAnnotationOfAnswerSPARQL(bindings);
logger.info("SPARQL insert for adding data to Qanary triplestore: {}", sparql);

insertQueries.add(sparql);
}

return insertQueries;
}

public String getSparqlInsertQueryForImprovedQuestion(
URI graph, URI questionUri, QAnswerResult result) throws QanaryExceptionNoOrMultipleQuestions, URISyntaxException, SparqlQueryFailed {

// the computed answer's SPARQL query needs to be cleaned
String improvedQuestion = cleanStringForSparqlQuery(result.getQuestion());

String sparql = "" //
+ "PREFIX qa: <http://www.wdaqua.eu/qa#> \n" //
+ "PREFIX oa: <http://www.w3.org/ns/openannotation/core/> \n" //
+ "PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> \n" //
+ "PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> \n" //
+ "INSERT { \n" //
+ "GRAPH <" + outgraph.toASCIIString() + "> { \n" //
+ annotationsToBeInserted //
//
+ "GRAPH ?graph { \n" //
// improved question
+ " ?annotationImprovedQuestion a qa:AnnotationOfImprovedQuestion ; \n" //
+ " oa:hasTarget ?question ; \n" //
Expand All @@ -378,19 +358,17 @@ String getSparqlInsertQuery(URI outgraph, QAnswerResult result)
+ " }\n" // end: GRAPH
+ "}\n" // end: insert
+ "WHERE { \n" //
+ bindForInsert //
//
+ " BIND (IRI(str(RAND())) AS ?annotationImprovedQuestion) . \n" //
+ " BIND (IRI(str(RAND())) AS ?improvedQuestion) . \n" //
//
+ " BIND (now() AS ?time) . \n" //
+ " BIND (<" + outgraph.toASCIIString() + "> AS ?question) . \n" //
+ " BIND (<" + graph.toASCIIString() + "> AS ?graph) . \n" //
+ " BIND (<" + questionUri.toASCIIString() + "> AS ?question) . \n" //
+ " BIND (<urn:qanary:" + this.applicationName + "> AS ?service ) . \n" //
+ " BIND (\"\"\"" + improvedQuestion + "\"\"\"^^xsd:string AS ?improvedQuestionText ) . \n" //
//
+ "} \n"; // end: where

logger.debug("SPARQL insert for adding data to Qanary triplestore:\n{}", sparql);
return sparql;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package eu.wdaqua.qanary.component.qanswer.qb;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -151,14 +153,21 @@ protected QAnswerResult requestQAnswerWebService(URI qanaryApiUri, String questi
+ "\"Is Berlin the capital of Germany\" " //
)
public QAnswerQanaryWrapperResult requestDemoResultWebService(@RequestBody QAnswerRequest request)
throws URISyntaxException, MalformedURLException, QanaryExceptionNoOrMultipleQuestions, SparqlQueryFailed {
throws URISyntaxException, QanaryExceptionNoOrMultipleQuestions, SparqlQueryFailed, IOException {
logger.info("requestDemoResultWebService: {} ", request);
request.replaceNullValuesWithDefaultValues(this.getEndpoint(), this.getLangFallback(),
this.getKnowledgeBaseDefault(), this.getUserDefault());
QAnswerResult result = this.requestQAnswerWebService(request);
String sparqQuery = myQAnswerQueryBuilderAndExecutor.getSparqlInsertQuery(endpoint, result);

URI demoGraph = new URI("urn:demo:graph");
URI demoQuestionUri = new URI("urn:demo:question");

String sparqlImprovedQuestion = myQAnswerQueryBuilderAndExecutor.getSparqlInsertQueryForImprovedQuestion(demoGraph, demoQuestionUri, result);
List<String> sparqlQueryCandidates = myQAnswerQueryBuilderAndExecutor.getSparqlInsertQueriesForQueryCandidates(demoGraph, demoQuestionUri, result);

String sparqQuery = "this is a test query";
logger.info("received sparqQuery: {}", sparqQuery);
return new QAnswerQanaryWrapperResult(result, sparqQuery);
return new QAnswerQanaryWrapperResult(result, sparqlImprovedQuestion, sparqlQueryCandidates);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.net.URI;
import java.util.List;

@Deprecated
public class ProcessedResult {

private final String type;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
package eu.wdaqua.qanary.component.qanswer.qb.messages;

import java.util.List;

public class QAnswerQanaryWrapperResult {

private final QAnswerResult result;
private final String sparqlQuery;
private final String sparqlImprovedQuestion;
private final List<String> sparqlQueryCandidates;

public QAnswerQanaryWrapperResult(QAnswerResult result, String sparqQuery) {
public QAnswerQanaryWrapperResult(QAnswerResult result, String sparqlImprovedQuestion, List<String> sparqlQueryCandidates) {
this.result = result;
this.sparqlQuery = sparqQuery;
this.sparqlImprovedQuestion = sparqlImprovedQuestion;
this.sparqlQueryCandidates = sparqlQueryCandidates;
}

public QAnswerResult getResult() {
return result;
}

public String getSparqlQuery() {
return sparqlQuery;
public String getSparqlImprovedQuestion() {
return sparqlImprovedQuestion;
}

public List<String> getSparqlQueryCandidates() {
return sparqlQueryCandidates;
}
}
Loading

0 comments on commit ecdaf49

Please sign in to comment.