mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-07 21:48:39 +00:00
Fixed issue where 'fast' should filter can make documents that didn't match the must or must_not clause a match again. Relates to #2979
This commit is contained in:
parent
70355f693f
commit
52edc4c652
@ -31,9 +31,7 @@ import org.elasticsearch.common.lucene.docset.DocIdSets;
|
|||||||
import org.elasticsearch.common.lucene.docset.NotDocIdSet;
|
import org.elasticsearch.common.lucene.docset.NotDocIdSet;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to {@link org.apache.lucene.queries.BooleanFilter}.
|
* Similar to {@link org.apache.lucene.queries.BooleanFilter}.
|
||||||
@ -80,6 +78,7 @@ public class XBooleanFilter extends Filter implements Iterable<FilterClause> {
|
|||||||
boolean hasNonEmptyShouldClause = false;
|
boolean hasNonEmptyShouldClause = false;
|
||||||
boolean hasMustClauses = false;
|
boolean hasMustClauses = false;
|
||||||
boolean hasMustNotClauses = false;
|
boolean hasMustNotClauses = false;
|
||||||
|
boolean mustOrMustNotBeforeShould = false;
|
||||||
for (int i = 0; i < clauses.size(); i++) {
|
for (int i = 0; i < clauses.size(); i++) {
|
||||||
FilterClause clause = clauses.get(i);
|
FilterClause clause = clauses.get(i);
|
||||||
DocIdSet set = clause.getFilter().getDocIdSet(context, acceptDocs);
|
DocIdSet set = clause.getFilter().getDocIdSet(context, acceptDocs);
|
||||||
@ -89,6 +88,9 @@ public class XBooleanFilter extends Filter implements Iterable<FilterClause> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else if (clause.getOccur() == Occur.SHOULD) {
|
} else if (clause.getOccur() == Occur.SHOULD) {
|
||||||
|
if (!hasShouldClauses && (hasMustClauses || hasMustNotClauses)) {
|
||||||
|
mustOrMustNotBeforeShould = true;
|
||||||
|
}
|
||||||
hasShouldClauses = true;
|
hasShouldClauses = true;
|
||||||
if (DocIdSets.isEmpty(set)) {
|
if (DocIdSets.isEmpty(set)) {
|
||||||
continue;
|
continue;
|
||||||
@ -113,6 +115,32 @@ public class XBooleanFilter extends Filter implements Iterable<FilterClause> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mustOrMustNotBeforeShould) {
|
||||||
|
// Sort the clause only once if we encounter a should before a must or must_not clause
|
||||||
|
Collections.sort(clauses, new Comparator<FilterClause>() {
|
||||||
|
@Override
|
||||||
|
public int compare(FilterClause o1, FilterClause o2) {
|
||||||
|
if (o1.getOccur() != o2.getOccur()) {
|
||||||
|
return o1.getOccur() == Occur.SHOULD ? -1 : 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Because we sorted the clause we also need to sort the result clauses
|
||||||
|
Collections.sort(results, new Comparator<ResultClause>() {
|
||||||
|
@Override
|
||||||
|
public int compare(ResultClause o1, ResultClause o2) {
|
||||||
|
if (o1.clause.getOccur() != o2.clause.getOccur()) {
|
||||||
|
return o1.clause.getOccur() == Occur.SHOULD ? -1 : 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// now, go over the clauses and apply the "fast" ones...
|
// now, go over the clauses and apply the "fast" ones...
|
||||||
hasNonEmptyShouldClause = false;
|
hasNonEmptyShouldClause = false;
|
||||||
boolean hasBits = false;
|
boolean hasBits = false;
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
package org.elasticsearch.test.integration.search.query;
|
package org.elasticsearch.test.integration.search.query;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticSearchException;
|
import org.elasticsearch.ElasticSearchException;
|
||||||
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
|
|
||||||
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.action.search.SearchType;
|
import org.elasticsearch.action.search.SearchType;
|
||||||
@ -46,7 +45,6 @@ import static org.elasticsearch.index.query.FilterBuilders.*;
|
|||||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.anyOf;
|
import static org.hamcrest.Matchers.anyOf;
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.testng.Assert.assertTrue;
|
import static org.testng.Assert.assertTrue;
|
||||||
import static org.testng.Assert.fail;
|
import static org.testng.Assert.fail;
|
||||||
@ -1203,21 +1201,25 @@ public class SimpleQueryTests extends AbstractNodesTests {
|
|||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
client.prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject()
|
client.prepareIndex("test", "type1", "1").setSource(jsonBuilder().startObject()
|
||||||
|
.field("field1", "test1")
|
||||||
.field("num_long", 1)
|
.field("num_long", 1)
|
||||||
.endObject())
|
.endObject())
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
client.prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject()
|
client.prepareIndex("test", "type1", "2").setSource(jsonBuilder().startObject()
|
||||||
|
.field("field1", "test1")
|
||||||
.field("num_long", 2)
|
.field("num_long", 2)
|
||||||
.endObject())
|
.endObject())
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
client.prepareIndex("test", "type1", "3").setSource(jsonBuilder().startObject()
|
client.prepareIndex("test", "type1", "3").setSource(jsonBuilder().startObject()
|
||||||
|
.field("field1", "test2")
|
||||||
.field("num_long", 3)
|
.field("num_long", 3)
|
||||||
.endObject())
|
.endObject())
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
client.prepareIndex("test", "type1", "4").setSource(jsonBuilder().startObject()
|
client.prepareIndex("test", "type1", "4").setSource(jsonBuilder().startObject()
|
||||||
|
.field("field1", "test2")
|
||||||
.field("num_long", 4)
|
.field("num_long", 4)
|
||||||
.endObject())
|
.endObject())
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
@ -1238,6 +1240,16 @@ public class SimpleQueryTests extends AbstractNodesTests {
|
|||||||
).execute().actionGet();
|
).execute().actionGet();
|
||||||
|
|
||||||
assertThat(response.getHits().totalHits(), equalTo(4l));
|
assertThat(response.getHits().totalHits(), equalTo(4l));
|
||||||
|
|
||||||
|
// This made #2979 fail!
|
||||||
|
response = client.prepareSearch("test").setFilter(
|
||||||
|
FilterBuilders.boolFilter()
|
||||||
|
.must(FilterBuilders.termFilter("field1", "test1"))
|
||||||
|
.should(FilterBuilders.rangeFilter("num_long").from(1).to(2))
|
||||||
|
.should(FilterBuilders.rangeFilter("num_long").from(3).to(4))
|
||||||
|
).execute().actionGet();
|
||||||
|
|
||||||
|
assertThat(response.getHits().totalHits(), equalTo(2l));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // see #2926
|
@Test // see #2926
|
||||||
|
Loading…
x
Reference in New Issue
Block a user