p.getObject(),
p.getContext()
};
for(int i = 0; i<fields.length; i++) {
if(fields[i] != null && fields[i].isVariableField()) {
VariableField v = (VariableField)fields[i];
if(variableNames.get(v) == null) {
variableNames.put(v,"V"+ (++variableCount));
queryVariables.put(v,new LinkedList<String>());
}
String pName = patternNames.get(p);
String vName = variableNames.get(v);
queryVariables.get(v).add(pName + "_" + positions[i] + "_" + vName);
}
}
}
// build the select clause by projecting for each query variable the first name
StringBuilder selectClause = new StringBuilder();
final List<VariableField> selectVariables = new LinkedList<VariableField>();
for(Iterator<VariableField> it = queryVariables.keySet().iterator(); it.hasNext(); ) {
VariableField v = it.next();
String projectedName = variableNames.get(v);
String fromName = queryVariables.get(v).get(0);
selectClause.append(fromName);
selectClause.append(".id as ");
selectClause.append(projectedName);
if(it.hasNext()) {
selectClause.append(", ");
}
selectVariables.add(v);
}
if(justifications) {
// project also the ids of triples that have matched; we use it for building justifications
for(Iterator<Pattern> it = patterns.iterator(); it.hasNext(); ) {
Pattern p = it.next();
if(selectClause.length() > 0) {
selectClause.append(", ");
}
selectClause.append(patternNames.get(p));
selectClause.append(".id as ");
selectClause.append(patternNames.get(p));
}
}
// build the from-clause of the query; the from clause is constructed as follows:
// 1. for each pattern P, there will be a "KiWiTriple P" in the from clause
// 2. for each variable V in P occurring in
// - subject, there will be a "inner join P.subject as P_S_V" or "left outer join P.subject as P_S_V",
// depending on whether the "optional" parameter is false or true
// - property, there will be a "inner join P.property as P_P_V" or "left outer join p.property as P_P_V"
// - object, there will be a "inner join P.object as P_O_V" or "left outer join p.object as P_O_V"
// - context, there will be a "inner join P.context as P_C_V" or "left outer join p.context as P_C_V"
StringBuilder fromClause = new StringBuilder();
for(Iterator<Pattern> it = patterns.iterator(); it.hasNext(); ) {
Pattern p = it.next();
String pName = patternNames.get(p);
fromClause.append("triples "+pName);
Field[] fields = new Field[] {
p.getSubject(),
p.getProperty(),
p.getObject(),
p.getContext()
};
for(int i = 0; i<fields.length; i++) {
if(fields[i] != null && fields[i].isVariableField()) {
String vName = variableNames.get(fields[i]);
fromClause.append(" INNER JOIN nodes AS ");
fromClause.append(pName + "_"+positions[i]+"_" + vName);
fromClause.append(" ON " + pName + "." + positions[i] + " = ");
fromClause.append(pName + "_"+positions[i]+"_" + vName + ".id ");
}
}
if(it.hasNext()) {
fromClause.append(",\n ");
}
}
// build the where clause as follows:
// 1. iterate over all patterns and for each resource and literal field in subject,
// property, object, or context, and set a query condition according to the
// nodes given in the pattern
// 2. for each variable that has more than one occurrences, add a join condition
// 3. for each variable in the initialBindings, add a condition to the where clause
// list of where conditions that will later be connected by AND
List<String> whereConditions = new LinkedList<String>();
// 1. iterate over all patterns and for each resource and literal field in subject,
// property, object, or context, and set a query condition according to the
// nodes given in the pattern
for(Pattern p : patterns) {
String pName = patternNames.get(p);
Field[] fields = new Field[] {
p.getSubject(),
p.getProperty(),
p.getObject(),
p.getContext()
};
for(int i = 0; i<fields.length; i++) {
// find node id of the resource or literal field and use it in the where clause
// in this way we can avoid setting too many query parameters
Long nodeId = null;
if(fields[i] != null && fields[i].isLiteralField()) {
nodeId = ((KiWiNode)((LiteralField)fields[i]).getLiteral()).getId();
} else if(fields[i] != null && fields[i].isResourceField()) {
nodeId = ((KiWiNode)((ResourceField)fields[i]).getResource()).getId();
}
if(nodeId != null) {
String condition = pName+"."+positions[i]+" = " + nodeId;
whereConditions.add(condition);
}
}
}
// 2. for each variable that has more than one occurrences, add a join condition
for(VariableField v : queryVariables.keySet()) {
List<String> vNames = queryVariables.get(v);
for(int i = 1; i < vNames.size(); i++) {
String vName1 = vNames.get(i-1);
String vName2 = vNames.get(i);
whereConditions.add(vName1 + ".id = " + vName2 + ".id");
}
}
// 3. for each variable in the initialBindings, add a condition to the where clause setting it
// to the node given as binding
if(initialBindings != null) {
for(VariableField v : initialBindings.getBindings().keySet()) {
List<String> vNames = queryVariables.get(v);
if(vNames != null && vNames.size() > 0) {
String vName = vNames.get(0);
KiWiNode binding = initialBindings.getBindings().get(v);
whereConditions.add(vName+".id = "+binding.getId());
}
}
}
// 4. for each pattern, ensure that the matched triple is not marked as deleted
for(Pattern p : patterns) {
String pName = patternNames.get(p);
whereConditions.add(pName+".deleted = false");
}
// construct the where clause
StringBuilder whereClause = new StringBuilder();
for(Iterator<String> it = whereConditions.iterator(); it.hasNext(); ) {
whereClause.append(it.next());
whereClause.append("\n ");
if(it.hasNext()) {
whereClause.append("AND ");
}
}
// finally, construct the order by clause
StringBuilder orderByClause = new StringBuilder();
if(orderBy != null && orderBy.size() > 0) {
for(Iterator<VariableField> it = orderBy.iterator(); it.hasNext(); ) {
VariableField v = it.next();
String vName = variableNames.get(v);
orderByClause.append(vName);
if(it.hasNext()) {
orderByClause.append(", ");
}