Search: Allow to filter out docs based on a minimum score, closes #719.
This commit is contained in:
parent
a0fd47159e
commit
8a03ca1114
|
@ -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>.
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue