/**
* Copyright 2014 National University of Ireland, Galway.
*
* This file is part of the SIREn project. Project and contact information:
*
* https://github.com/rdelbru/SIREn
*
* 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 org.sindice.siren.search.node;
import java.io.IOException;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.Explanation;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Weight;
import org.apache.lucene.util.Bits;
/**
* Expert: A {@link NodeQuery} that filters nodes and return their ancestors.
*
* <p>
*
* Internal class that is created by the {@link TwigQuery} during query
* rewriting.
*/
class AncestorFilterQuery extends NodeQuery {
private final NodeQuery q;
private final int ancestorLevel;
/**
* Expert: constructs a AncestorFilterQuery that will use the
* provided {@link NodeQuery} and that will filter matching nodes to return
* their ancestor node based on the given ancestor level. */
public AncestorFilterQuery(final NodeQuery q, final int ancestorLevel) {
this.q = q;
this.ancestorLevel = ancestorLevel;
this.setLevelConstraint(ancestorLevel);
}
public NodeQuery getQuery() {
return q;
}
@Override
public Weight createWeight(final IndexSearcher searcher) throws IOException {
return new AncestorFilterWeight(searcher);
}
@Override
public String toString(final String field) {
return q.toString();
}
@Override
public boolean equals(final Object o) {
if (!(o instanceof AncestorFilterQuery)) {
return false;
}
final AncestorFilterQuery other = (AncestorFilterQuery) o;
return (this.getBoost() == other.getBoost()) &&
this.q.equals(other.q) &&
this.lowerBound == other.lowerBound &&
this.upperBound == other.upperBound &&
this.levelConstraint == other.levelConstraint;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + Float.floatToIntBits(this.getBoost());
result = prime * result + q.hashCode();
result = prime * result + lowerBound;
result = prime * result + upperBound;
result = prime * result + levelConstraint;
return result;
}
protected class AncestorFilterWeight extends Weight {
final Weight weight;
public AncestorFilterWeight(final IndexSearcher searcher) throws IOException {
this.weight = q.createWeight(searcher);
}
@Override
public String toString() {
return "weight(" + AncestorFilterQuery.this + ")";
}
@Override
public Query getQuery() {
return AncestorFilterQuery.this;
}
@Override
public float getValueForNormalization() throws IOException {
return weight.getValueForNormalization();
}
@Override
public void normalize(final float queryNorm, final float topLevelBoost) {
weight.normalize(queryNorm, topLevelBoost);
}
@Override
public Scorer scorer(final AtomicReaderContext context,
final boolean scoreDocsInOrder,
final boolean topScorer, final Bits acceptDocs)
throws IOException {
final NodeScorer scorer = (NodeScorer) weight.scorer(context,
scoreDocsInOrder, topScorer, acceptDocs);
if (scorer == null) {
return null;
}
return new AncestorFilterScorer(scorer, ancestorLevel);
}
@Override
public Explanation explain(final AtomicReaderContext context, final int doc)
throws IOException {
return weight.explain(context, doc);
}
}
}