Skip to content

Commit beb22d8

Browse files
committed
percolator: Take matchAllDocs and verified of the sub result into account when analyzing a function_score query.
Before the `matchAllDocs` was ignored and this could lead to percolator queries not matching when the inner query was a match_all query and min_score was specified. Before when `verified` was not taken into account if the function_score query wrapped an unverified query this could lead to matching percolator queries that shouldn't match at all.
1 parent 0f95636 commit beb22d8

File tree

3 files changed

+62
-2
lines changed

3 files changed

+62
-2
lines changed

modules/percolator/src/main/java/org/elasticsearch/percolator/QueryAnalyzer.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -465,12 +465,17 @@ private static BiFunction<Query, Version, Result> functionScoreQuery() {
465465
return (query, version) -> {
466466
FunctionScoreQuery functionScoreQuery = (FunctionScoreQuery) query;
467467
Result result = analyze(functionScoreQuery.getSubQuery(), version);
468+
468469
// If min_score is specified we can't guarantee upfront that this percolator query matches,
469470
// so in that case we set verified to false.
470471
// (if it matches with the percolator document matches with the extracted terms.
471472
// Min score filters out docs, which is different than the functions, which just influences the score.)
472-
boolean verified = functionScoreQuery.getMinScore() == null;
473-
return new Result(verified, result.extractions, result.minimumShouldMatch);
473+
boolean verified = result.verified && functionScoreQuery.getMinScore() == null;
474+
if (result.matchAllDocs) {
475+
return new Result(result.matchAllDocs, verified);
476+
} else {
477+
return new Result(verified, result.extractions, result.minimumShouldMatch);
478+
}
474479
};
475480
}
476481

modules/percolator/src/test/java/org/elasticsearch/percolator/CandidateQueryTests.java

+37
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import org.apache.lucene.search.IndexSearcher;
5656
import org.apache.lucene.search.MatchAllDocsQuery;
5757
import org.apache.lucene.search.MatchNoDocsQuery;
58+
import org.apache.lucene.search.PhraseQuery;
5859
import org.apache.lucene.search.PrefixQuery;
5960
import org.apache.lucene.search.Query;
6061
import org.apache.lucene.search.Scorer;
@@ -77,6 +78,7 @@
7778
import org.elasticsearch.common.bytes.BytesArray;
7879
import org.elasticsearch.common.bytes.BytesReference;
7980
import org.elasticsearch.common.compress.CompressedXContent;
81+
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
8082
import org.elasticsearch.common.geo.ShapeRelation;
8183
import org.elasticsearch.common.settings.Settings;
8284
import org.elasticsearch.common.xcontent.XContentFactory;
@@ -220,6 +222,16 @@ public void testDuel() throws Exception {
220222
}
221223
return new DisjunctionMaxQuery(clauses, 0.01f);
222224
});
225+
queryFunctions.add(() -> {
226+
Float minScore = randomBoolean() ? null : (float) randomIntBetween(1, 1000);
227+
Query innerQuery;
228+
if (randomBoolean()) {
229+
innerQuery = new TermQuery(new Term(field1, randomFrom(stringContent.get(field1))));
230+
} else {
231+
innerQuery = new PhraseQuery(field1, randomFrom(stringContent.get(field1)), randomFrom(stringContent.get(field1)));
232+
}
233+
return new FunctionScoreQuery(innerQuery, minScore, 1f);
234+
});
223235

224236
List<ParseContext.Document> documents = new ArrayList<>();
225237
for (Supplier<Query> queryFunction : queryFunctions) {
@@ -679,6 +691,31 @@ public void testPercolateMatchAll() throws Exception {
679691
assertEquals(4, topDocs.scoreDocs[2].doc);
680692
}
681693

694+
public void testFunctionScoreQuery() throws Exception {
695+
List<ParseContext.Document> docs = new ArrayList<>();
696+
addQuery(new FunctionScoreQuery(new TermQuery(new Term("field", "value")), null, 1f), docs);
697+
addQuery(new FunctionScoreQuery(new TermQuery(new Term("field", "value")), 10f, 1f), docs);
698+
addQuery(new FunctionScoreQuery(new MatchAllDocsQuery(), null, 1f), docs);
699+
addQuery(new FunctionScoreQuery(new MatchAllDocsQuery(), 10F, 1f), docs);
700+
701+
indexWriter.addDocuments(docs);
702+
indexWriter.close();
703+
directoryReader = DirectoryReader.open(directory);
704+
IndexSearcher shardSearcher = newSearcher(directoryReader);
705+
shardSearcher.setQueryCache(null);
706+
707+
MemoryIndex memoryIndex = new MemoryIndex();
708+
memoryIndex.addField("field", "value", new WhitespaceAnalyzer());
709+
IndexSearcher percolateSearcher = memoryIndex.createSearcher();
710+
PercolateQuery query = (PercolateQuery) fieldType.percolateQuery("_name", queryStore,
711+
Collections.singletonList(new BytesArray("{}")), percolateSearcher, Version.CURRENT);
712+
TopDocs topDocs = shardSearcher.search(query, 10, new Sort(SortField.FIELD_DOC), true, true);
713+
assertEquals(2L, topDocs.totalHits);
714+
assertEquals(2, topDocs.scoreDocs.length);
715+
assertEquals(0, topDocs.scoreDocs[0].doc);
716+
assertEquals(2, topDocs.scoreDocs[1].doc);
717+
}
718+
682719
public void testPercolateSmallAndLargeDocument() throws Exception {
683720
List<ParseContext.Document> docs = new ArrayList<>();
684721
BooleanQuery.Builder builder = new BooleanQuery.Builder();

modules/percolator/src/test/java/org/elasticsearch/percolator/QueryAnalyzerTests.java

+18
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,24 @@ public void testFunctionScoreQuery() {
811811
assertTermsEqual(result.extractions, new Term("_field", "_value"));
812812
}
813813

814+
public void testFunctionScoreQuery_withMatchAll() {
815+
MatchAllDocsQuery innerQuery = new MatchAllDocsQuery();
816+
FunctionScoreQuery functionScoreQuery1 = new FunctionScoreQuery(innerQuery, new RandomScoreFunction(0, 0, null));
817+
Result result = analyze(functionScoreQuery1, Version.CURRENT);
818+
assertThat(result.verified, is(true));
819+
assertThat(result.minimumShouldMatch, equalTo(0));
820+
assertThat(result.matchAllDocs, is(true));
821+
assertThat(result.extractions.isEmpty(), is(true));
822+
823+
FunctionScoreQuery functionScoreQuery2 =
824+
new FunctionScoreQuery(innerQuery, new RandomScoreFunction(0, 0, null), CombineFunction.MULTIPLY, 1f, 10f);
825+
result = analyze(functionScoreQuery2, Version.CURRENT);
826+
assertThat(result.verified, is(false));
827+
assertThat(result.minimumShouldMatch, equalTo(0));
828+
assertThat(result.matchAllDocs, is(true));
829+
assertThat(result.extractions.isEmpty(), is(true));
830+
}
831+
814832
public void testSelectBestExtraction() {
815833
Set<QueryExtraction> queryTerms1 = terms(new int[0], "12", "1234", "12345");
816834
Set<QueryAnalyzer.QueryExtraction> queryTerms2 = terms(new int[0], "123", "1234", "12345");

0 commit comments

Comments
 (0)