Search: Allow to filter out docs based on a minimum score, closes #719.

This commit is contained in:
kimchy 2011-02-24 06:55:16 +02:00
parent a0fd47159e
commit 8a03ca1114
8 changed files with 146 additions and 1 deletions

View File

@ -229,6 +229,14 @@ public class SearchRequestBuilder extends BaseRequestBuilder<SearchRequest, Sear
return this;
}
/**
* Sets the minimum score below which docs will be filtered out.
*/
public SearchRequestBuilder setMinScore(float minScore) {
sourceBuilder().minScore(minScore);
return this;
}
/**
* From index to start the search from. Defaults to <tt>0</tt>.
*/

View File

@ -0,0 +1,66 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search licenses this
* file to you 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.elasticsearch.common.lucene;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.ScoreCachingWrappingScorer;
import org.apache.lucene.search.Scorer;
import java.io.IOException;
/**
*
*/
public class MinimumScoreCollector extends Collector {
private final Collector collector;
private final float minimumScore;
private Scorer scorer;
public MinimumScoreCollector(Collector collector, float minimumScore) {
this.collector = collector;
this.minimumScore = minimumScore;
}
@Override public void setScorer(Scorer scorer) throws IOException {
if (!(scorer instanceof ScoreCachingWrappingScorer)) {
scorer = new ScoreCachingWrappingScorer(scorer);
}
this.scorer = scorer;
collector.setScorer(scorer);
}
@Override public void collect(int doc) throws IOException {
if (scorer.score() > minimumScore) {
collector.collect(doc);
}
}
@Override public void setNextReader(IndexReader reader, int docBase) throws IOException {
collector.setNextReader(reader, docBase);
}
@Override public boolean acceptsDocsOutOfOrder() {
return collector.acceptsDocsOutOfOrder();
}
}

View File

@ -41,7 +41,8 @@ public class MultiCollector extends Collector {
}
@Override public void setScorer(Scorer scorer) throws IOException {
if (collectors.length > 0) {
// always wrap it in a scorer wrapper
if (!(scorer instanceof ScoreCachingWrappingScorer)) {
scorer = new ScoreCachingWrappingScorer(scorer);
}
collector.setScorer(scorer);

View File

@ -88,6 +88,8 @@ public class SearchSourceBuilder implements ToXContent {
private boolean trackScores = false;
private Float minScore;
private List<String> fieldNames;
private List<ScriptField> scriptFields;
@ -176,6 +178,14 @@ public class SearchSourceBuilder implements ToXContent {
return this;
}
/**
* Sets the minimum score below which docs will be filtered out.
*/
public SearchSourceBuilder minScore(float minScore) {
this.minScore = minScore;
return this;
}
/**
* An optional query parser name to use.
*/
@ -434,6 +444,10 @@ public class SearchSourceBuilder implements ToXContent {
}
}
if (minScore != null) {
builder.field("min_score", minScore);
}
if (version != null) {
builder.field("version", version);
}

View File

@ -23,6 +23,7 @@ import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.*;
import org.elasticsearch.common.collect.Lists;
import org.elasticsearch.common.collect.Maps;
import org.elasticsearch.common.lucene.MinimumScoreCollector;
import org.elasticsearch.common.lucene.MultiCollector;
import org.elasticsearch.common.lucene.search.ExtendedIndexSearcher;
import org.elasticsearch.common.lucene.search.FilteredCollector;
@ -147,6 +148,11 @@ public class ContextIndexSearcher extends ExtendedIndexSearcher {
collector = new MultiCollector(collector, collectors.toArray(new Collector[collectors.size()]));
}
}
// apply the minimum score after multi collector so we filter facets as well
if (searchContext.minimumScore() != null) {
collector = new MinimumScoreCollector(collector, searchContext.minimumScore());
}
// we only compute the doc id set once since within a context, we execute the same query always...
if (searchContext.timeout() != null) {
searchContext.queryResult().searchTimedOut(false);

View File

@ -115,6 +115,8 @@ public class SearchContext implements Releasable {
private Sort sort;
private Float minimumScore;
private boolean trackScores = false; // when sorting, track scores as well...
private String queryParserName;
@ -302,6 +304,15 @@ public class SearchContext implements Releasable {
return timeout;
}
public SearchContext minimumScore(float minimumScore) {
this.minimumScore = minimumScore;
return this;
}
public Float minimumScore() {
return this.minimumScore;
}
public SearchContext sort(Sort sort) {
this.sort = sort;
return this;

View File

@ -0,0 +1,37 @@
/*
* Licensed to Elastic Search and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Elastic Search licenses this
* file to you 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.elasticsearch.search.query;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.search.SearchParseElement;
import org.elasticsearch.search.internal.SearchContext;
/**
* @author kimchy (shay.banon)
*/
public class MinScoreParseElement implements SearchParseElement {
@Override public void parse(XContentParser parser, SearchContext context) throws Exception {
XContentParser.Token token = parser.currentToken();
if (token.isValue()) {
context.minimumScore(parser.floatValue());
}
}
}

View File

@ -67,6 +67,8 @@ public class QueryPhase implements SearchPhase {
.put("sort", new SortParseElement())
.put("trackScores", new TrackScoresParseElement())
.put("track_scores", new TrackScoresParseElement())
.put("min_score", new MinScoreParseElement())
.put("minScore", new MinScoreParseElement())
.putAll(facetPhase.parseElements());
return parseElements.build();
}