use of annis.model.QueryNode in project ANNIS by korpling.
the class SemanticValidator method checkAlternative.
public void checkAlternative(QueryData data, List<QueryNode> alternative, int alternativeIndex, boolean queryWasNormalized) {
// check if there is at least one search expression
if (alternative.isEmpty()) {
throw new AnnisQLSemanticsException("Missing search expression.");
}
// there are not linguistic binary relations allowed if there is only one node
if (alternative.size() == 1) {
QueryNode n = alternative.get(0);
for (Join j : n.getOutgoingJoins()) {
if (j.getTarget() != null) {
throw new AnnisQLSemanticsException(j.getParseLocation(), "No binary linguistic relations allowed if there is only one node in query.");
}
}
}
// get all nodes connected to the first one
Multimap<Long, QueryNode> connected = calculateConnected(alternative);
Set<Long> transitiveHull = new HashSet<>();
transitiveHull.add(alternative.get(0).getId());
createTransitiveHull(alternative.get(0), connected, transitiveHull);
Multiset<String> variableNames = TreeMultiset.create();
Set<Long> unconnectedNodes = new HashSet<>();
for (QueryNode n : alternative) {
unconnectedNodes.add(n.getId());
variableNames.add(n.getVariable());
}
unconnectedNodes.removeAll(transitiveHull);
// check if each node is contained in the connected nodes
if (!unconnectedNodes.isEmpty()) {
List<AqlParseError> errors = new LinkedList<>();
for (QueryNode n : alternative) {
if (unconnectedNodes.contains(n.getId())) {
errors.add(new AqlParseError(n, "variable \"" + n.getVariable() + "\" not bound (use linguistic operators)"));
}
}
if (!errors.isEmpty()) {
if (queryWasNormalized) {
// add the normalized query as "error" so the user is able to see it
errors.add(new AqlParseError("Normalized query is: \n" + data.toAQL()));
}
throw new AnnisQLSemanticsException("Not all variables bound", errors);
}
}
// check if any variable name was given more than once
List<String> invalidNames = new LinkedList<>();
for (Multiset.Entry<String> e : variableNames.entrySet()) {
if (e.getCount() > 1) {
invalidNames.add(e.getElement());
}
}
if (!invalidNames.isEmpty()) {
throw new AnnisQLSemanticsException("The following variable names are " + "used for more than one node: " + Joiner.on(", ").join(invalidNames) + "\nNormalized Query is: \n" + data.toAQL());
}
// check no non-reflexive operator is used with the same operands
for (QueryNode source : alternative) {
for (Join join : source.getOutgoingJoins()) {
if (join instanceof Inclusion || join instanceof SameSpan || join instanceof Overlap || join instanceof RightOverlap || join instanceof LeftOverlap || join instanceof RightAlignment || join instanceof LeftAlignment) {
if (source.equals(join.getTarget())) {
throw new AnnisQLSemanticsException(join, "Not-reflexive operator used with the same node as argument.");
}
}
}
}
}
use of annis.model.QueryNode in project ANNIS by korpling.
the class SemanticValidator method calculateConnected.
private Multimap<Long, QueryNode> calculateConnected(List<QueryNode> nodes) {
Multimap<Long, QueryNode> result = HashMultimap.create();
for (QueryNode n : nodes) {
for (Join j : n.getOutgoingJoins()) {
if (j.getTarget() != null && !(j instanceof NonBindingJoin)) {
long left = n.getId();
long right = j.getTarget().getId();
result.put(left, j.getTarget());
result.put(right, n);
}
}
}
return result;
}
use of annis.model.QueryNode in project ANNIS by korpling.
the class DefaultWhereClauseGenerator method addNodeArityConditions.
@Override
protected void addNodeArityConditions(List<String> conditions, QueryData queryData, QueryNode node) {
// fugly
List<Long> corpusList = queryData.getCorpusList();
TableAccessStrategy tas = tables(null);
String id1 = tables(node).aliasedColumn(RANK_TABLE, "id");
String componentID1 = tables(node).aliasedColumn(COMPONENT_TABLE, "id");
String corpusRef1 = tables(node).aliasedColumn(NODE_TABLE, "corpus_ref");
String parent = TableAccessStrategy.column("children", tas.columnName(RANK_TABLE, "parent"));
String id = TableAccessStrategy.column("children", tas.columnName(RANK_TABLE, "id"));
String componentID = TableAccessStrategy.column("children", tas.columnName(COMPONENT_TABLE, "id"));
;
String corpusRef = TableAccessStrategy.column("children", tas.columnName(NODE_TABLE, "corpus_ref"));
;
String factsTable = SelectedFactsFromClauseGenerator.inheritedFactTables(corpusList, "");
StringBuffer sb = new StringBuffer();
sb.append("(SELECT count(DISTINCT " + id + ")\n");
sb.append("\tFROM " + factsTable + " AS children\n");
sb.append("\tWHERE " + parent + " = " + id1 + " AND " + componentID1 + " = " + componentID + " AND " + corpusRef1 + " = " + corpusRef + " AND toplevel_corpus IN(" + (corpusList.isEmpty() ? "NULL" : StringUtils.join(corpusList, ",")) + ")" + ")");
QueryNode.Range arity = node.getArity();
if (arity.getMin() == arity.getMax()) {
conditions.add(join("=", sb.toString(), String.valueOf(arity.getMin())));
} else {
conditions.add(between(sb.toString(), arity.getMin(), arity.getMax()));
}
}
use of annis.model.QueryNode in project ANNIS by korpling.
the class FindSqlGenerator method fromClause.
@Override
public String fromClause(QueryData queryData, List<QueryNode> alternative, String indent) {
StringBuilder sb = new StringBuilder();
sb.append(indent).append("(\n");
sb.append(solutionSqlGenerator.toSql(queryData, indent + TABSTOP));
sb.append(") AS solution \n");
Preconditions.checkArgument(!alternative.isEmpty(), "There must be at least one query node in the alternative");
// add the left joins with the annotation category table
int i = 0;
Iterator<QueryNode> itNodes = alternative.iterator();
while (itNodes.hasNext()) {
i++;
QueryNode n = itNodes.next();
sb.append(indent).append("LEFT JOIN annotation_category AS annotation_category").append(n.getId()).append(" ON (solution.toplevel_corpus = annotation_category").append(n.getId()).append(".toplevel_corpus").append(" AND solution.cat").append(i).append(" = annotation_category").append(n.getId()).append(".id").append(")");
if (!itNodes.hasNext()) {
sb.append(",");
}
sb.append("\n");
}
sb.append(indent).append("corpus AS c");
return sb.toString();
}
use of annis.model.QueryNode in project ANNIS by korpling.
the class TransitivePrecedenceOptimizer method createInitialJoinMap.
private Map<Long, Set<Precedence>> createInitialJoinMap(List<QueryNode> alternative) {
Map<Long, Set<Precedence>> result = new HashMap<>();
for (QueryNode node : alternative) {
Set<Precedence> joinList = new HashSet<>();
for (Join j : node.getOutgoingJoins()) {
if (j instanceof Precedence) {
joinList.add((Precedence) j);
}
}
result.put(node.getId(), joinList);
}
return result;
}
Aggregations