package org.apache.lucene.queryparser.flexible.aqp.processors;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.queryparser.flexible.aqp.ADSEscapeQuerySyntaxImpl;
import org.apache.lucene.queryparser.flexible.aqp.builders.AqpFunctionQueryBuilder;
import org.apache.lucene.queryparser.flexible.aqp.config.AqpAdsabsQueryConfigHandler;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpAdsabsRegexQueryNode;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpAdsabsSynonymQueryNode;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpFunctionQueryNode;
import org.apache.lucene.queryparser.flexible.aqp.nodes.AqpNonAnalyzedQueryNode;
import org.apache.lucene.queryparser.flexible.aqp.processors.AqpQProcessor.OriginalInput;
import org.apache.lucene.queryparser.flexible.core.QueryNodeException;
import org.apache.lucene.queryparser.flexible.core.config.QueryConfigHandler;
import org.apache.lucene.queryparser.flexible.core.messages.QueryParserMessages;
import org.apache.lucene.queryparser.flexible.core.nodes.FieldQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.FieldableNode;
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.QuotedFieldQueryNode;
import org.apache.lucene.queryparser.flexible.core.nodes.SlopQueryNode;
import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessor;
import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessorImpl;
import org.apache.lucene.queryparser.flexible.messages.MessageImpl;
import org.apache.lucene.queryparser.flexible.standard.processors.AnalyzerQueryNodeProcessor;
import org.apache.lucene.queryparser.flexible.standard.processors.MultiFieldQueryNodeProcessor;
/**
* This processor wraps fields with the 'null' value into edismax
* search. This is the solution for the unfielded search
*
* @see FieldableNode
* @see MultiFieldQueryNodeProcessor
* @see AnalyzerQueryNodeProcessor
*
*/
public class AqpUnfieldedSearchProcessor extends QueryNodeProcessorImpl implements
QueryNodeProcessor {
ADSEscapeQuerySyntaxImpl escaper = new ADSEscapeQuerySyntaxImpl();
@Override
protected QueryNode postProcessNode(QueryNode node)
throws QueryNodeException {
if (node instanceof FieldQueryNode && !(node instanceof AqpAdsabsRegexQueryNode)) {
QueryConfigHandler config = getQueryConfigHandler();
if (!((FieldQueryNode) node).getField().equals(
config.get(AqpAdsabsQueryConfigHandler.ConfigurationKeys.UNFIELDED_SEARCH_FIELD))) {
return node;
}
if (!config.has(AqpAdsabsQueryConfigHandler.ConfigurationKeys.FUNCTION_QUERY_BUILDER_CONFIG)) {
throw new QueryNodeException(new MessageImpl(
"Invalid configuration",
"Missing FunctionQueryBuilder provider"));
}
String funcName = "edismax_combined_aqp"; //"edismax_always_aqp"; //"edismax_combined_aqp";
String subQuery = ((FieldQueryNode) node).getTextAsString();
if (node instanceof AqpNonAnalyzedQueryNode) {
funcName = "edismax_nonanalyzed";
}
else {
//subQuery = (String) escaper.escape(subQuery, Locale.getDefault(), EscapeQuerySyntax.Type.NORMAL);
if (node instanceof QuotedFieldQueryNode) {
subQuery = "\"" + subQuery + "\"";
}
if (node.getParent() instanceof SlopQueryNode) {
subQuery = subQuery + "~" + ((SlopQueryNode) node.getParent()).getValue();
//if (node.getParent().getParent() instanceof BoostQueryNode) {
// subQuery = subQuery + "^" + ((BoostQueryNode) node.getParent().getParent()).getValue();
//}
}
/*else if (node.getParent() instanceof BoostQueryNode) {
//subQuery = subQuery + "^" + ((BoostQueryNode) node.getParent()).getValue();
if (node.getParent().getParent() != null) {
QueryNode root = node.getParent().getParent();
List<QueryNode> children = root.getChildren();
children.clear();
children.add(node);
root.set(children);
}
}*/
}
node.setTag("subQuery", subQuery);
AqpFunctionQueryBuilder builder = config.get(AqpAdsabsQueryConfigHandler.ConfigurationKeys.FUNCTION_QUERY_BUILDER_CONFIG)
.getBuilder(funcName, (QueryNode) node, config);
if (builder == null) {
throw new QueryNodeException(new MessageImpl(QueryParserMessages.INVALID_SYNTAX,
"Unknown function \"" + funcName +"\"" ));
}
// let adismax know that we want exact search
if (node.getTag("aqp.exact") != null ||
(node.getParent() instanceof AqpAdsabsSynonymQueryNode && ((AqpAdsabsSynonymQueryNode) node.getParent()).isActivated() == false)) {
subQuery = "{!adismax aqp.exact.search=true}" + subQuery;
}
List<OriginalInput> fValues = new ArrayList<OriginalInput>();
fValues.add(new OriginalInput(subQuery, -1, -1));
return new AqpFunctionQueryNode(funcName, builder, fValues);
}
return node;
}
@Override
protected QueryNode preProcessNode(QueryNode node)
throws QueryNodeException {
if (node instanceof AqpAdsabsSynonymQueryNode) {
applyTagToAllChildren(((AqpAdsabsSynonymQueryNode) node).getChild());
}
return node;
}
@Override
protected List<QueryNode> setChildrenOrder(List<QueryNode> children)
throws QueryNodeException {
return children;
}
private void applyTagToAllChildren(QueryNode node) {
if (node instanceof FieldQueryNode) {
node.setTag("aqp.exact", true);
}
if (node.getChildren() != null) {
for (QueryNode child : node.getChildren()) {
applyTagToAllChildren(child);
}
}
}
}