Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experiment Initialization failure handling #453

Merged
merged 12 commits into from
Jun 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ export
datadump.nt
indexes
dependency-reduced-pom.xml
.idea
25 changes: 17 additions & 8 deletions src/main/java/org/aksw/gerbil/Experimenter.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@
*/
package org.aksw.gerbil;

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

import org.aksw.gerbil.database.ExperimentDAO;
import org.aksw.gerbil.datatypes.ExperimentTaskConfiguration;
import org.aksw.gerbil.evaluate.EvaluatorFactory;
import org.aksw.gerbil.exceptions.FaultyConfigurationException;
import org.aksw.gerbil.execute.AnnotatorOutputWriter;
import org.aksw.gerbil.execute.ExperimentTask;
import org.aksw.gerbil.semantic.sameas.SameAsRetriever;
Expand All @@ -43,7 +46,7 @@ public class Experimenter implements Runnable {

/**
* Constructor
*
*
* @deprecated Please use the other constructor and provide an
* {@link EvaluatorFactory}.
*/
Expand All @@ -68,11 +71,12 @@ public Experimenter(Overseer overseer, ExperimentDAO experimentDAO, SameAsRetrie
}

@Override
public void run() {
public void run() throws FaultyConfigurationException{
Arrays.sort(configs, new ExpTaskConfigComparator());
try {
int taskId;
for (int i = 0; i < configs.length; ++i) {
List<ExperimentTaskConfiguration> faultyConfigs = new ArrayList<ExperimentTaskConfiguration>();
int taskId;
for (int i = 0; i < configs.length; ++i) {
try{
if (couldHaveCachedResult(configs[i])) {
taskId = experimentDAO.connectCachedResultOrCreateTask(configs[i].annotatorConfig.getName(),
configs[i].datasetConfig.getName(), configs[i].type.name(), configs[i].matching.name(),
Expand All @@ -88,12 +92,17 @@ public void run() {
ExperimentTask task = new ExperimentTask(taskId, experimentDAO, globalRetriever, evFactory,
configs[i]);
task.setAnnotatorOutputWriter(annotatorOutputWriter);
overseer.startTask(task);
overseer.startTask(task);
}
}catch (Exception e){
faultyConfigs.add(configs[i]);
}
}
if(faultyConfigs.isEmpty()){
LOGGER.info("Experimenter finished the creation of tasks for experiment \"" + experimentId + "\"");
} catch (Exception e) {
LOGGER.error("Got an Exception while trying to start all needed tasks. Aborting the experiment.", e);
}else{
LOGGER.error("Got few Exception while trying to start some needed tasks.");
throw new FaultyConfigurationException(faultyConfigs);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* This file is part of General Entity Annotator Benchmark.
*
* General Entity Annotator Benchmark is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* General Entity Annotator Benchmark is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with General Entity Annotator Benchmark. If not, see <http://www.gnu.org/licenses/>.
*/
package org.aksw.gerbil.exceptions;

import org.aksw.gerbil.datatypes.ExperimentTaskConfiguration;

import java.util.List;

/**
* Exception thrown when faulty configurations are encountered.
*/
public class FaultyConfigurationException extends RuntimeException{
MichaelRoeder marked this conversation as resolved.
Show resolved Hide resolved
private final List<ExperimentTaskConfiguration> faultyConfigs;

/**
* Constructs a new FaultyConfigurationException with the specified list of faulty configurations.
* @param faultyConfigs the list of faulty configurations that caused this exception
*/
public FaultyConfigurationException(List<ExperimentTaskConfiguration> faultyConfigs) {
super("Faulty configurations encountered: " + faultyConfigs);
this.faultyConfigs = faultyConfigs;
}

/**
* @return the list of faulty configurations that caused this exception.
*/
public List<ExperimentTaskConfiguration> getFaultyConfigs() {
return faultyConfigs;
}
}
32 changes: 25 additions & 7 deletions src/main/java/org/aksw/gerbil/web/MainController.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aksw.gerbil.Experimenter;
import org.aksw.gerbil.config.GerbilConfiguration;
import org.aksw.gerbil.database.ExperimentDAO;
Expand All @@ -35,12 +37,14 @@
import org.aksw.gerbil.datatypes.ExperimentTaskStatus;
import org.aksw.gerbil.datatypes.ExperimentType;
import org.aksw.gerbil.evaluate.EvaluatorFactory;
import org.aksw.gerbil.exceptions.FaultyConfigurationException;
import org.aksw.gerbil.execute.AnnotatorOutputWriter;
import org.aksw.gerbil.matching.Matching;
import org.aksw.gerbil.semantic.sameas.SameAsRetriever;
import org.aksw.gerbil.utils.IDCreator;
import org.aksw.gerbil.web.config.AdapterManager;
import org.aksw.gerbil.web.config.RootConfig;
import org.aksw.gerbil.web.response.execution.ExperimentExecutionResponse;
import org.aksw.simba.topicmodeling.concurrent.overseers.Overseer;
import org.apache.commons.io.FileUtils;
import org.json.simple.JSONArray;
Expand All @@ -50,8 +54,12 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
Expand Down Expand Up @@ -139,12 +147,12 @@ public ModelAndView index() {
/**
* expects a string like {"type":"A2KB","matching": "Mw - weak annotation match"
* ,"annotator":["A2KB one","A2KB two" ],"dataset":["datasets"]}
*
*
* @param experimentData
* @return
*/
@RequestMapping("/execute")
public @ResponseBody String execute(@RequestParam(value = "experimentData") String experimentData) {
@GetMapping(value = "/execute")
public ResponseEntity<String> execute(@RequestParam(value = "experimentData") String experimentData) throws JsonProcessingException {
LOGGER.debug("Got request on /execute with experimentData={}", experimentData);
Object obj = JSONValue.parse(experimentData);
JSONObject configuration = (JSONObject) obj;
Expand Down Expand Up @@ -180,9 +188,19 @@ public ModelAndView index() {
String experimentId = IDCreator.getInstance().createID();
Experimenter exp = new Experimenter(overseer, dao, globalRetriever, evFactory, configs, experimentId);
exp.setAnnotatorOutputWriter(annotatorOutputWriter);
exp.run();

return experimentId;
try{
exp.run();
}catch(FaultyConfigurationException e){
ObjectMapper objectMapper = new ObjectMapper();
if(e.getFaultyConfigs().size()==configs.length){
return ResponseEntity.badRequest().contentType(MediaType.APPLICATION_JSON).
body(objectMapper.writeValueAsString(new ExperimentExecutionResponse(e.getMessage())));
}else{
return ResponseEntity.badRequest().contentType(MediaType.APPLICATION_JSON).
body(objectMapper.writeValueAsString(new ExperimentExecutionResponse(experimentId,e.getMessage())));
}
}
return ResponseEntity.ok().contentType(MediaType.TEXT_PLAIN).body(experimentId);
}

@RequestMapping("/experiment")
Expand Down Expand Up @@ -305,7 +323,7 @@ public ModelAndView experiment(@RequestParam(value = "id") String id, HttpServle
/**
* This mapping is needed to authenticate us against Google Analytics. It reads
* the google file and sends it as String.
*
*
* @return The google analytics file as String or an empty String if the file
* couldn't be loaded.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* This file is part of General Entity Annotator Benchmark.
*
* General Entity Annotator Benchmark is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* General Entity Annotator Benchmark is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with General Entity Annotator Benchmark. If not, see <http://www.gnu.org/licenses/>.
*/
package org.aksw.gerbil.web.response.execution;

/**
* Response class representing the outcome of an experiment execution attempt.
*/
public class ExperimentExecutionResponse {
MichaelRoeder marked this conversation as resolved.
Show resolved Hide resolved

private String experimentId;
private final String errorMessage;
private String detailMessage;

/**
* Constructs a new ExperimentExecutionResponse with the specified experiment ID and detailed message.
* @param experimentId the ID of the experiment
* @param detailMessage detailed message describing the outcome or errors encountered
*/
public ExperimentExecutionResponse(String experimentId, String detailMessage) {
this.errorMessage = "Encountered errors while trying to start all needed tasks. " +
"Aborting the erroneous tasks and continuing the experiment.";
this.experimentId = experimentId;
this.detailMessage = detailMessage;
}

/**
* Constructs a new ExperimentExecutionResponse with the specified detailed message.
* @param detailMessage detailed message describing the outcome or errors encountered
*/
public ExperimentExecutionResponse(String detailMessage) {
this.errorMessage = "Encountered errors while trying to start all needed tasks. " +
"Aborting the experiment.";
this.detailMessage = detailMessage;
}

/**
* @return the ID of the experiment.
*/
public String getExperimentId() {
return experimentId;
}

/**
* @return the error message associated with this response.
*/
public String getErrorMessage() {
return errorMessage;
}

/**
* @return the detailed message associated with this response.
*/
public String getDetailMessage() {
return detailMessage;
}
}
40 changes: 30 additions & 10 deletions src/main/webapp/WEB-INF/views/config.jsp
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@
dataset.push($(this).text());
});

//check whether there is at least one dataset and at least one annotator
//check whether there is at least one dataset and at least one annotator
//and the disclaimer checkbox should be clicked
if (dataset.length > 0 && annotator.length > 0
&& $('#disclaimerCheckbox:checked').length == 1) {
Expand Down Expand Up @@ -439,22 +439,22 @@
$(document)
.ready(
function() {
// load dropdowns when document loaded
// load dropdowns when document loaded
$('#type').multiselect();
$('#matching').multiselect();
$('#annotator').multiselect();
$('#dataset').multiselect();

// listeners for dropdowns
// listeners for dropdowns
$('#type').change(loadMatching);
$('#type').change(loadAnnotator);
$('#type').change(loadDatasets);

loadExperimentTypes();

//supervise configuration of experiment and let it only run
//if everything is ok
//initially it is turned off
//if everything is ok
//initially it is turned off
$('#submit').attr("disabled", true);
//check showing run button if something is changed in dropdown menu
$('#annotator').change(function() {
Expand All @@ -467,12 +467,12 @@
checkExperimentConfiguration();
});

//if add button is clicked check whether there is a name and a uri
//if add button is clicked check whether there is a name and a uri
$('#warningEmptyAnnotator').hide();
$('#infoAnnotatorTest').hide();
$('#dangerAnnotatorTestError').hide();
$('#addAnnotator').click(defineNIFAnnotator);
//if add button is clicked check whether there is a name and a uri
//if add button is clicked check whether there is a name and a uri
$('#warningEmptyDataset').hide();
$('#fileupload').click(function() {
var name = $('#nameDataset').val();
Expand Down Expand Up @@ -577,8 +577,28 @@
link);
})
.fail(
function() {
alert("Error, insufficient parameters.");
function(res) {
$('#submit').remove();
res = res.responseJSON;
var errorSpan = '';
if (res && res.experimentId) {
var origin = window.location.origin;
var link = "<a href=\"/gerbil/experiment?id="
+ res.experimentId
+ "\">"
+ origin
+ "/gerbil/experiment?id="
+ res.experimentId
+ "</a>";
var span = "<span>Find your experimental data here: </span>";
$('#submitField').append(span);
$('#submitField').append(link);
errorSpan = "<br><div class=\"warning\" style=\"padding-top: 10px;\">Warning: "+res.errorMessage+"</div>";
} else {
errorSpan = "<br><div class=\"error\">Error: "+res.errorMessage+"</div>";
}
$('#submitField').append(errorSpan);
// alert("Error, insufficient parameters.");
});
});
});
Expand Down Expand Up @@ -634,4 +654,4 @@
.addClass($.support.fileInput ? undefined : 'disabled');
});
</script>
</body>
</body>
Loading