package org.apache.lucene.queryparser.flexible.aqp.processors; import java.util.ArrayList; import java.util.List; import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpBooleanQueryNode; import org.apache.lucene.queryparser.flexible.core.QueryNodeException; import org.apache.lucene.queryparser.flexible.core.nodes.BooleanQueryNode; import org.apache.lucene.queryparser.flexible.core.nodes.FieldableNode; import org.apache.lucene.queryparser.flexible.core.nodes.ModifierQueryNode; import org.apache.lucene.queryparser.flexible.core.nodes.ModifierQueryNode.Modifier; import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode; import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessor; import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessorImpl; /** * Optimizes the query tree - on root node - turns +whathever into whatever if * there is only one child (but only if Modifier is positive, MOD_REQ or * MOD_NONE) * */ public class AqpOptimizationProcessor extends QueryNodeProcessorImpl implements QueryNodeProcessor { @Override protected QueryNode preProcessNode(QueryNode node) throws QueryNodeException { if (node.getParent() == null && node.getChildren() != null && node.getChildren().size() == 1) { if (node instanceof BooleanQueryNode) { QueryNode c = node.getChildren().get(0); if (c instanceof ModifierQueryNode && ((ModifierQueryNode) c).getModifier() != Modifier.MOD_NOT) { return ((ModifierQueryNode) c).getChild(); } } } else if (node instanceof AqpBooleanQueryNode) { List<QueryNode> children = node.getChildren(); String thisOp = ((AqpBooleanQueryNode) node).getOperator(); boolean rewriteSafe = true; QueryNode subClause; QueryNode child; int counterOfElements = 0; for (int i = 0; i < children.size(); i++) { child = children.get(i); if (child.isLeaf()) { rewriteSafe = false; break; } subClause = getClauseIgnoreModifiers(child); // skips multiple modifier nodes if (subClause instanceof FieldableNode) { counterOfElements++; } else if (subClause instanceof AqpBooleanQueryNode && ((AqpBooleanQueryNode) subClause) .getOperator().equals(thisOp)) { counterOfElements = counterOfElements + subClause.getChildren().size() + 1; } else { rewriteSafe = false; break; } } if (rewriteSafe && counterOfElements > children.size()) { List<QueryNode> childrenList = new ArrayList<QueryNode>(); for (QueryNode ch: children) { subClause = getClauseIgnoreModifiers(ch); if (subClause instanceof AqpBooleanQueryNode) { for (QueryNode nod : subClause.getChildren()) { childrenList.add(nod); } } else { childrenList.add(ch); } } children.clear(); node.set(childrenList); } } return node; } private QueryNode getClauseIgnoreModifiers(QueryNode node) { Modifier om = null; if (node instanceof ModifierQueryNode) { om = ((ModifierQueryNode) node).getModifier(); } else { return node; } QueryNode ret = node; while (ret instanceof ModifierQueryNode) { if (ret.getChildren().size() != 1) break; QueryNode ch = ret.getChildren().get(0); if (ch.getChildren() == null) break; boolean safe = true; for (QueryNode child: ch.getChildren()) { if (child instanceof ModifierQueryNode && ((ModifierQueryNode)child).getModifier().equals(om)) { // pass } else { safe = false; break; } } if (safe) { ret = ch; } else { break; } } return ret; } private boolean oneOfChildrenBoolean(QueryNode node) { for (QueryNode n: node.getChildren()) { if (n instanceof AqpBooleanQueryNode) { return true; } } return false; } @Override protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException { return node; } @Override protected List<QueryNode> setChildrenOrder(List<QueryNode> children) throws QueryNodeException { return children; } }