package org.apache.lucene.queryparser.flexible.aqp.builders;
import java.util.List;
import org.apache.lucene.queryparser.flexible.messages.MessageImpl;
import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.core.builders.QueryBuilder;
import org.apache.lucene.queryparser.flexible.core.builders.QueryTreeBuilder;
import org.apache.lucene.queryparser.flexible.core.messages.QueryParserMessages;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpNearQueryNode;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.spans.SpanNearQuery;
import org.apache.lucene.search.spans.SpanQuery;
/**
* The builder for the {@link AqpNearQueryNode}, example query:
*
* <pre>
* dog NEAR/5 cat
* </pre>
*
* <p>
* After the AST tree was parsed, and synonyms were found,
* we may have the following tree:
*
*
* <pre>
* AqpNearQueryNode(5)
* |
* ------------------------------
* / \
* OR QueryNode(cat)
* |
* -----------------
* / \
* QueryNode(dog) QueryNode(canin)
*
* </pre>
*
*
* <p>
* Since Lucene cannot handle these queries, the flex builder
* must rewrite them, effectively producing
*
* <pre>
* SpanNear(SpanOr(dog | cat), SpanTerm(cat), 5)
* </pre>
*
*
* This builder does not know (yet) how to handle cases of
* mixed boolean operators, eg.
*
* <pre>
* (dog AND (cat OR fat)) NEAR/5 batman
* </pre>
*
* @see AqpNearQueryNode
*
*/
public class AqpNearQueryNodeBuilder implements QueryBuilder {
public AqpNearQueryNodeBuilder() {
// empty constructor
}
public Object build(QueryNode queryNode) throws QueryNodeException {
AqpNearQueryNode nearNode = (AqpNearQueryNode) queryNode;
SpanConverter converter = new SpanConverter();
List<QueryNode> children = nearNode.getChildren();
if (children != null) {
SpanQuery[] clauses = new SpanQuery[children.size()];
int i = 0;
for (QueryNode child : children) {
Object obj = child.getTag(QueryTreeBuilder.QUERY_TREE_BUILDER_TAGID);
if (obj != null) {
SpanQuery result = converter.getSpanQuery(new SpanConverterContainer((Query) obj, nearNode.getSlop(), nearNode.getInOrder()));
clauses[i++] = result;
//TODO: v6 - boost is gone, have to move it converter
//if (obj instanceof BoostQuery) {
// result = new BoostQuery(result, ((BoostQuery) obj).getBoost());
//}
} else {
throw new QueryNodeException(new MessageImpl(
QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR,
"One of the clauses inside AqpNearQueryNode is null"));
}
}
return new SpanNearQuery(clauses, nearNode.getSlop(),
nearNode.getInOrder());
}
throw new QueryNodeException(new MessageImpl(
QueryParserMessages.LUCENE_QUERY_CONVERSION_ERROR,
"Illegal state for: " + nearNode.toString()));
}
}