/*
* Copyright 2003-2010 Tufts University Licensed under the
* Educational Community 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.osedu.org/licenses/ECL-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.
*/
/**
* A Class to support coplex queries throught sparql
* It supports boolean AND / OR operation
* and REGEX MODE
* By default the query is limitimg, which means it returns results that match
* all the criteria
* @author akumar03
*
*/
package edu.tufts.vue.rdf;
import java.util.*;
import tufts.Util;
import tufts.vue.DEBUG;
/**
* Query utility class for VUE to provide a simple API for building up a SPARQL query.
* Could probably skip this and just an existing impl of com.hp.hpl.jena.query.Query
*
* Note that this class is poorly encapsulated: the literal values in the query it constructs:
* e.g., "resource" / "keyword", or "rid" / "val", or whatever they are, have to be hardcoded
* elsewhere in processing the results of QuerySolution(s).
*
* This class might better be called something like QueryBuilder or SPARQLBuilder
* -- can cause confusion with com.hp.hpl.jena.query.Query.
*/
public class Query {
private static final org.apache.log4j.Logger Log = org.apache.log4j.Logger.getLogger(Query.class);
public enum Qualifier { STARTS_WITH, CONTAINS,MATCH, WITHOUT,MATCH_CASE };
// These appear to have never been used.
//public enum Operation { AND , OR }
//private boolean regex = true;
//private Operation oper = Operation.AND;
private final List<Criteria> criteriaList = new ArrayList<Criteria>();
/** Creates a new instance of Query */
public Query() {}
public void addCriteria(String key,String value) {
if (DEBUG.SEARCH) Log.debug("addCriteria " + key + "=" + Util.tags(value));
Criteria criteria = new Criteria(key,value);
criteriaList.add(criteria);
}
public void addCriteria(String key, String value, String condition){
if (DEBUG.SEARCH) Log.debug("addCriteria " + key + "=" + Util.tags(value) + " cond=" + Util.tags(condition));
Criteria criteria = new Criteria(key,value,Qualifier.valueOf(condition));
criteriaList.add(criteria);
}
//private static final String QueryExprFmt = "?resource <%s> ?keyword%d FILTER regex(?keyword%d, \"%s%s\", \"i\") .";
//private static final String QueryExprFmt = "?rid <%s> ?val%d FILTER regex(?val%d, \"%s%s\", \"i\") .";
private static final String QueryStart = "PREFIX vue: <"+RDFIndex.VUE_ONTOLOGY+">" + "\nSELECT ?rid ?val WHERE { ";
private static final String QueryForProperty = "?rid <%s> ?val FILTER regex(?val, \"%s%s\", \"i\") .";
// "i" means case-independent
// Todo: would be nice to be able to handle stuff like: FILTER (?age >= 24)
public String createSPARQLQuery() {
final StringBuilder query = new StringBuilder(QueryStart.length() + QueryForProperty.length() + 16);
final boolean multiLine = true; // criteriaList.size() > 1; // for diagnostic readability
query.append(QueryStart);
if (multiLine) query.append('\n');
int i = 0;
for (Criteria criteria : criteriaList) {
i++;
final String encodedPropertyKey = RDFIndex.getEncodedKey(criteria.key); // better done at critera construct time?
final String regexPrefix;
// if (encodedKey.startsWith(RDFIndex.VUE_ONTOLOGY))
// encodedKey = "vue:" + encodedKey.substring(RDFIndex.VUE_ONTOLOGY.length()); // remove angle brackets as well?
switch (criteria.qualifier) {
case STARTS_WITH: regexPrefix = "^"; break;
default: regexPrefix = "";
}
if (multiLine) query.append(" ");
query.append(String.format(QueryForProperty, encodedPropertyKey, regexPrefix, criteria.value));
//query.append(String.format(QueryExprFmt,encodedPropertyKey, i,i, regexPrefix, criteria.value));
// Sequentially naming the query vars is just another way to distinguish what was found in the results.
if (multiLine) query.append('\n');
}
query.append('}');
return query.toString();
}
class Criteria {
String key;
Qualifier qualifier;
String value;
public Criteria(String key, String value) {
this(key,value,Qualifier.CONTAINS);
}
public Criteria(String key, String value, Qualifier qualifier) {
this.key = key;
this.value = value;
this.qualifier = qualifier;
}
// public String toString() {
// return "Criteria[" + key + "=" + value + "]; qual=" + qualifier;
// }
}
}