blob: 0e49cd63fd8d0d1e26699e3f3323f4e85161aa7f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.stanbol.enhancer.ldpath.function;
import static java.util.Collections.singletonMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map.Entry;
import org.apache.clerezza.rdf.core.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import at.newmedialab.ldpath.api.backend.RDFBackend;
import at.newmedialab.ldpath.api.functions.SelectorFunction;
import at.newmedialab.ldpath.api.selectors.NodeSelector;
import at.newmedialab.ldpath.model.transformers.IntTransformer;
import at.newmedialab.ldpath.model.transformers.StringTransformer;
public class SuggestionFunction implements SelectorFunction<Resource> {
private static final Comparator<Entry<Double,Resource>> SUGGESTION_COMPARATOR =
new Comparator<Entry<Double,Resource>>() {
@Override
public int compare(Entry<Double,Resource> e1, Entry<Double,Resource> e2) {
return e2.getKey().compareTo(e1.getKey());
}
};
private static final int MISSING_CONFIDENCE_FIRST = -1;
private static final int MISSING_CONFIDENCE_FILTER = 0;
private static final int MISSING_CONFIDENCE_LAST = -1;
private static final int DEFAULT_MISSING_CONFIDENCE_MODE = MISSING_CONFIDENCE_FILTER;
private static final Double MAX = Double.valueOf(Double.POSITIVE_INFINITY);
private static final Double MIN = Double.valueOf(Double.NEGATIVE_INFINITY);
// private static final String ANNOTATION_PROCESSING_MODE_SINGLE = "single";
// private static final String ANNOTATION_PROCESSING_MODE_UNION = "union";
// private static final String DEFAULT_ANNOTATION_PROCESSING_MODE = ANNOTATION_PROCESSING_MODE_SINGLE;
Logger log = LoggerFactory.getLogger(SuggestionFunction.class);
private final String name;
private final IntTransformer<Resource> intTransformer;
private final StringTransformer<Resource> stringTransformer;
private final NodeSelector<Resource> suggestionSelector;
private final NodeSelector<Resource> confidenceSelector;
private final NodeSelector<Resource> resultSelector;
public SuggestionFunction(String name,
NodeSelector<Resource> suggestionSelector,
NodeSelector<Resource> confidenceSelector){
this(name,null,suggestionSelector,confidenceSelector);
}
public SuggestionFunction(String name,
NodeSelector<Resource> suggestionSelector,
NodeSelector<Resource> confidenceSelector,
NodeSelector<Resource> resultSelector) {
intTransformer = new IntTransformer<Resource>();
stringTransformer = new StringTransformer<Resource>();
if(name == null || name.isEmpty()){
throw new IllegalArgumentException("The parsed function name MUST NOT be NULL nor empty!");
}
this.name = name;
if(suggestionSelector == null){
throw new IllegalArgumentException("The NodeSelector used to select the Suggestions for the parsed Context MUST NOT be NULL!");
}
this.suggestionSelector = suggestionSelector;
if(confidenceSelector == null){
throw new IllegalArgumentException("The NodeSelector used to select the Confidence for Suggestions MUST NOT be NULL!");
}
this.confidenceSelector = confidenceSelector;
this.resultSelector = resultSelector;
}
@Override
public Collection<Resource> apply(final RDFBackend<Resource> backend, Resource context, Collection<Resource>... args) throws IllegalArgumentException {
Integer limit = parseParamLimit(backend, args,1);
// final String processingMode = parseParamProcessingMode(backend, args,2);
final int missingConfidenceMode = parseParamMissingConfidenceMode(backend, args,2);
List<Resource> result = new ArrayList<Resource>();
// if(processingMode.equals(ANNOTATION_PROCESSING_MODE_UNION)){
processAnnotations(backend, args[0], limit, missingConfidenceMode, result);
// } else {
// for(Resource context : args[0]){
// processAnnotations(backend, singleton(context),
// limit, missingConfidenceMode, result);
// }
// }
return result;
}
/**
* Suggestions are selected by all Annotations returned by the parsed
* {@link #annotationSelector}.
* @param backend
* @param annotations suggestions are selected for the union of the parsed
* annotations - the {limit} most linked entities for the parsed
* list of annotations.
* @param limit the maximum number of suggestions for the parsed collection
* of annotations.
* @param missingConfidenceMode
* @param result results are added to this list.
*/
private void processAnnotations(final RDFBackend<Resource> backend,
Collection<Resource> annotations,
Integer limit,
final int missingConfidenceMode,
List<Resource> result) {
List<Entry<Double,Resource>> suggestions = new ArrayList<Entry<Double,Resource>>();
for(Resource annotation : annotations){
for(Resource suggestion : suggestionSelector.select(backend, annotation, null, null)){
Collection<Resource> cs = confidenceSelector.select(backend, suggestion, null, null);
Double confidence = !cs.isEmpty() ? backend.doubleValue(cs.iterator().next()) :
missingConfidenceMode == MISSING_CONFIDENCE_FILTER ?
null : missingConfidenceMode == MISSING_CONFIDENCE_FIRST ?
MAX : MIN;
if(confidence != null){
suggestions.add(singletonMap(confidence,suggestion).entrySet().iterator().next());
}
}
}
Collections.sort(suggestions, SUGGESTION_COMPARATOR);
int resultSize = limit != null ? Math.min(limit, suggestions.size()) : suggestions.size();
for(Entry<Double,Resource> suggestion : suggestions.subList(0, resultSize)){
if(resultSelector == null){
result.add(suggestion.getValue());
} else {
result.addAll(resultSelector.select(backend, suggestion.getValue(), null, null));
}
}
}
/*
* Helper Method to parse the parameter
*/
/**
* @param backend
* @param args
* @return
*/
private int parseParamMissingConfidenceMode(final RDFBackend<Resource> backend,
Collection<Resource>[] args, int index) {
final int missingConfidenceMode;
if(args.length > index && !args[index].isEmpty()){
String mode = stringTransformer.transform(backend, args[index].iterator().next());
if("first".equalsIgnoreCase(mode)){
missingConfidenceMode = MISSING_CONFIDENCE_FIRST;
} else if("last".equalsIgnoreCase(mode)){
missingConfidenceMode = MISSING_CONFIDENCE_LAST;
} else if("filter".equalsIgnoreCase(mode)){
missingConfidenceMode = MISSING_CONFIDENCE_FILTER;
} else {
missingConfidenceMode = DEFAULT_MISSING_CONFIDENCE_MODE;
log.warn("Unknown value for parameter 'missing confidence value mode' '{}'" +
"(supported: 'first','last','filter') use default: 'filter')",mode);
}
} else {
missingConfidenceMode = DEFAULT_MISSING_CONFIDENCE_MODE;
}
return missingConfidenceMode;
}
// /**
// * @param backend
// * @param args
// * @return
// */
// private String parseParamProcessingMode(final RDFBackend<Resource> backend, Collection<Resource>[] args, int index) {
// final String processingMode;
// if(args.length > index && !args[index].isEmpty()){
// String mode = stringTransformer.transform(backend, args[index].iterator().next());
// if(ANNOTATION_PROCESSING_MODE_SINGLE.equalsIgnoreCase(mode)){
// processingMode = ANNOTATION_PROCESSING_MODE_SINGLE;
// } else if(ANNOTATION_PROCESSING_MODE_UNION.equalsIgnoreCase(mode)) {
// processingMode = ANNOTATION_PROCESSING_MODE_UNION;
// } else {
// processingMode = DEFAULT_ANNOTATION_PROCESSING_MODE;
// log.warn("Unknown value for parameter 'annotation processing mode' '{}'" +
// "(supported: 'single','union') default: 'single')",mode);
// }
// } else {
// processingMode = DEFAULT_ANNOTATION_PROCESSING_MODE;
// }
// return processingMode;
// }
/**
* @param backend
* @param args
* @return
*/
private Integer parseParamLimit(final RDFBackend<Resource> backend, Collection<Resource>[] args,int index) {
Integer limit = null;
if(args.length > index && !args[index].isEmpty()){
Resource value = args[index].iterator().next();
try {
limit = intTransformer.transform(backend, value);
if(limit < 1){
limit = null;
}
} catch (RuntimeException e) {
log.warn("Unable to parse parameter 'limit' form the 2nd argument '{}'",value);
}
}
return limit;
}
@Override
public String getPathExpression(RDFBackend<Resource> backend) {
return name;
}
@Override
public String getSignature() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return null;
}
}