/*
* Copyright 2011 Stefan Partusch
*
* 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 de.spartusch.nasfvi.server;
import java.util.ArrayList;
import java.util.List;
import org.apache.lucene.queryParser.core.QueryNodeException;
import org.apache.lucene.queryParser.core.nodes.FieldQueryNode;
import org.apache.lucene.queryParser.core.nodes.ModifierQueryNode;
import org.apache.lucene.queryParser.core.nodes.QueryNode;
import org.apache.lucene.queryParser.core.nodes.SlopQueryNode;
import org.apache.lucene.queryParser.core.nodes.TokenizedPhraseQueryNode;
import org.apache.lucene.queryParser.core.processors.QueryNodeProcessorImpl;
import de.spartusch.StringMethods;
/**
* Replaces {@link org.apache.lucene.queryParser.core.nodes.FieldQueryNode
* FieldQueryNodes} with a {@link
* org.apache.lucene.queryParser.core.nodes.SlopQueryNode sloppy} {@link
* org.apache.lucene.queryParser.core.nodes.TokenizedPhraseQueryNode
* TokenizedPhraseQueryNode}.
* @author Stefan Partusch
*
*/
public class FieldsCollapsingProcessor extends QueryNodeProcessorImpl {
/** Names of the fields to replace. */
private String[] fieldsToCollapse;
/** Name of the TokenizedPhraseQueryNode to create. */
private String collapseTo;
/** Fields to replace. */
private List<QueryNode> collapsedNodes;
/** Fields to remove. A field is to be removed if it is replaced or
* if all of its children were removed. */
private List<QueryNode> nodesToRemove;
/** The slop to use. */
private int slop;
/**
* @param fieldsToCollapse Names of the fields to replace
* @param collapseTo Name of the TokenizedPhraseQueryNode to replace
* the fields with
* @param slop The slop to use for the TokenizedPhraseQueryNode
* @see {@link org.apache.lucene.queryParser.core.nodes.SlopQueryNode
* SlopQueryNode}
*/
public FieldsCollapsingProcessor(final String[] fieldsToCollapse,
final String collapseTo, final int slop) {
this.fieldsToCollapse = fieldsToCollapse;
this.collapseTo = collapseTo;
this.slop = slop;
collapsedNodes = new ArrayList<QueryNode>();
nodesToRemove = new ArrayList<QueryNode>();
}
@Override
public final QueryNode process(final QueryNode queryTree)
throws QueryNodeException {
collapsedNodes.clear();
nodesToRemove.clear();
// do preProcessNode and postProcessNode
QueryNode root = super.process(queryTree);
// create collapsed phrase query
if (!collapsedNodes.isEmpty()) {
TokenizedPhraseQueryNode phrase = new TokenizedPhraseQueryNode();
phrase.setField(collapseTo);
phrase.set(collapsedNodes);
SlopQueryNode slopNode = new SlopQueryNode(phrase, slop);
ModifierQueryNode mod = new ModifierQueryNode(slopNode,
ModifierQueryNode.Modifier.MOD_REQ);
if (root.getChildren().size() == 0) {
// all children are collapsed/removed
root = mod;
} else {
List<QueryNode> children = root.getChildren();
children.add(mod);
}
}
return root;
}
@Override
protected final QueryNode preProcessNode(final QueryNode node)
throws QueryNodeException {
if (node instanceof FieldQueryNode) {
FieldQueryNode fieldNode = (FieldQueryNode) node;
if (StringMethods.equalsOneOf(fieldNode.getFieldAsString(),
fieldsToCollapse)) {
fieldNode.setField(collapseTo); // rename field
collapsedNodes.add(fieldNode);
nodesToRemove.add(fieldNode);
}
}
return node;
}
@Override
protected final QueryNode postProcessNode(final QueryNode node)
throws QueryNodeException {
List<QueryNode> children = node.getChildren();
if (children != null && children.removeAll(nodesToRemove)) {
if (children.size() == 0) {
nodesToRemove.add(node);
}
}
return node;
}
@Override
protected final List<QueryNode>
setChildrenOrder(final List<QueryNode> children)
throws QueryNodeException {
return children;
}
}