/** * */ package querqy.rewrite.commonrules; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; import querqy.model.AbstractNodeVisitor; import querqy.model.BooleanQuery; import querqy.model.DisjunctionMaxQuery; import querqy.model.ExpandedQuery; import querqy.model.InputSequenceElement; import querqy.model.Node; import querqy.model.QuerqyQuery; import querqy.model.Query; import querqy.model.Term; import querqy.rewrite.ContextAwareQueryRewriter; import querqy.rewrite.commonrules.model.Action; import querqy.rewrite.commonrules.model.InputBoundary; import querqy.rewrite.commonrules.model.Instruction; import querqy.rewrite.commonrules.model.Instructions; import querqy.rewrite.commonrules.model.PositionSequence; import querqy.rewrite.commonrules.model.RulesCollection; import querqy.rewrite.commonrules.model.InputBoundary.Type; /** * @author rene * */ public class CommonRulesRewriter extends AbstractNodeVisitor<Node> implements ContextAwareQueryRewriter { static final InputBoundary LEFT_BOUNDARY = new InputBoundary(Type.LEFT); static final InputBoundary RIGHT_BOUNDARY = new InputBoundary(Type.RIGHT); protected final RulesCollection rules; protected final LinkedList<PositionSequence<Term>> sequencesStack; protected ExpandedQuery expandedQuery; protected Map<String, Object> context; /** * */ public CommonRulesRewriter(RulesCollection rules) { this.rules = rules; sequencesStack = new LinkedList<>(); } @Override public ExpandedQuery rewrite(ExpandedQuery query) { throw new UnsupportedOperationException("This rewriter needs a query context"); } @Override public ExpandedQuery rewrite(ExpandedQuery query, Map<String, Object> context) { QuerqyQuery<?> userQuery = query.getUserQuery(); if (userQuery instanceof Query) { this.expandedQuery = query; this.context = context; sequencesStack.add(new PositionSequence<Term>()); super.visit((BooleanQuery) query.getUserQuery()); applySequence(sequencesStack.removeLast(), true); } return query; } @Override public Node visit(BooleanQuery booleanQuery) { sequencesStack.add(new PositionSequence<Term>()); super.visit(booleanQuery); applySequence(sequencesStack.removeLast(), false); return null; } protected void applySequence(PositionSequence<Term> sequence, boolean addBoundaries) { PositionSequence<InputSequenceElement> sequenceForLookUp = addBoundaries ? addBoundaries(sequence) : termSequenceToInputSequence(sequence); boolean isDebug = Boolean.TRUE.equals(context.get(CONTEXT_KEY_DEBUG_ENABLED)); List<String> actionsDebugInfo = (List<String>) context.get(CONTEXT_KEY_DEBUG_DATA); // prepare debug info context object if requested if (isDebug && actionsDebugInfo == null) { actionsDebugInfo = new LinkedList<>(); context.put(CONTEXT_KEY_DEBUG_DATA, actionsDebugInfo); } for (Action action : rules.getRewriteActions(sequenceForLookUp)) { if (isDebug) { actionsDebugInfo.add(action.toString()); } for (Instructions instructions : action.getInstructions()) { for (Instruction instruction : instructions) { instruction.apply(sequence, action.getTermMatches(), action.getStartPosition(), action.getEndPosition(), expandedQuery, context); } } } } protected PositionSequence<InputSequenceElement> termSequenceToInputSequence(PositionSequence<Term> sequence) { PositionSequence<InputSequenceElement> result = new PositionSequence<>(); for (List<Term> termList : sequence) { result.add(Collections.<InputSequenceElement>unmodifiableList(termList)); } return result; } protected PositionSequence<InputSequenceElement> addBoundaries(PositionSequence<Term> sequence) { PositionSequence<InputSequenceElement> result = new PositionSequence<>(); result.nextPosition(); result.addElement(LEFT_BOUNDARY); for (List<Term> termList : sequence) { result.add(Collections.<InputSequenceElement>unmodifiableList(termList)); } result.nextPosition(); result.addElement(RIGHT_BOUNDARY); return result; } @Override public Node visit(DisjunctionMaxQuery disjunctionMaxQuery) { sequencesStack.getLast().nextPosition(); return super.visit(disjunctionMaxQuery); } @Override public Node visit(Term term) { sequencesStack.getLast().addElement(term); return super.visit(term); } }