Java tutorial
/* * Copyright 2013 SFB 632. * * Licensed 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 annis.ql.parser; import annis.model.QueryNode; import annis.sqlgen.model.Dominance; import annis.sqlgen.model.Identical; import annis.model.Join; import annis.sqlgen.model.PointingRelation; import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; /** * Fix queries where a node is contained in two linguistic relations that could * query different components. * * The normalization is needed since our SQL generation does not work well on * database tuples from different components which represent the same node. E.g. * a query like * <pre> * node & node & #1 > #2 & #1 ->dep #2 * </pre> must be normalized to * <pre> * node & node & node & node * & #1 > #2 & #3 ->dep #4 * & #1 = #3 & #2 = #4 * </pre> in order to actually get the results the user expects. * * @author Thomas Krause <krauseto@hu-berlin.de> */ public class ComponentSearchRelationNormalizer implements QueryDataTransformer { @Override public QueryData transform(QueryData data) { String originalAQL = data.toAQL(); AtomicLong maxID = new AtomicLong(); for (List<QueryNode> alternative : data.getAlternatives()) { for (QueryNode n : alternative) { maxID.set(Math.max(maxID.get(), n.getId())); } } for (List<QueryNode> alternative : data.getAlternatives()) { int disasterCounter = 0; while (checkForViolation(alternative, maxID)) { // repeat disasterCounter++; Preconditions.checkArgument(disasterCounter < 5000, "Possible endless loop in component search relation normalization for query " + originalAQL); } data.setMaxWidth(Math.max(data.getMaxWidth(), alternative.size())); } return data; } private boolean checkForViolation(List<QueryNode> nodes, AtomicLong maxID) { Multimap<QueryNode, Join> joins = createJoinMap(nodes); LinkedList<QueryNode> nodeCopy = new LinkedList<>(nodes); for (QueryNode n : nodeCopy) { if (joins.get(n).size() > 1) { Iterator<Join> itJoinsForNode = joins.get(n).iterator(); Join joinToSplit = itJoinsForNode.next(); if (joinToSplit.getTarget().getId() == n.getId()) { replicateFromJoinTarget(joinToSplit, n, nodes, maxID); } else { replicateFromJoinSource(joinToSplit, n, nodes, maxID); } return true; } } return false; } private void replicateFromJoinTarget(Join join, QueryNode targetNode, List<QueryNode> nodes, AtomicLong maxID) { QueryNode newTargetNode = new QueryNode(maxID.incrementAndGet(), targetNode, false); newTargetNode.setArtificial(true); newTargetNode.setVariable("x" + targetNode.getVariable()); newTargetNode.setThisNodeAsTarget(join); Identical identJoin = new Identical(newTargetNode); targetNode.addOutgoingJoin(identJoin); nodes.add(newTargetNode); } private void replicateFromJoinSource(Join join, QueryNode sourceNode, List<QueryNode> nodes, AtomicLong maxID) { Preconditions.checkState(sourceNode.removeOutgoingJoin(join), "The join was not attached to the source node."); QueryNode newNode = new QueryNode(maxID.incrementAndGet(), sourceNode, false); newNode.setVariable("x" + sourceNode.getVariable()); newNode.addOutgoingJoin(join); newNode.setArtificial(true); Identical identJoin = new Identical(newNode); sourceNode.addOutgoingJoin(identJoin); nodes.add(newNode); } private Multimap<QueryNode, Join> createJoinMap(List<QueryNode> nodes) { Multimap<QueryNode, Join> result = HashMultimap.create(); for (QueryNode n : nodes) { for (Join j : n.getOutgoingJoins()) { if (j instanceof Dominance || j instanceof PointingRelation) { if (j.getTarget() != null) { result.put(n, j); result.put(j.getTarget(), j); } } } } return result; } }