SQL: Preserve scoring in bool queries (#30730)
Make all bool constructs use match/should (that is a query context) as that is controlled and changed to a filter context by ES automatically based on the sort order (_doc, field vs _sort) and trackScores. Fix #29685
This commit is contained in:
parent
be8c0f27be
commit
dcf0f9f8dd
|
@ -5,8 +5,6 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.sql.execution.search;
|
package org.elasticsearch.xpack.sql.execution.search;
|
||||||
|
|
||||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
|
||||||
import org.elasticsearch.index.query.ConstantScoreQueryBuilder;
|
|
||||||
import org.elasticsearch.index.query.QueryBuilder;
|
import org.elasticsearch.index.query.QueryBuilder;
|
||||||
import org.elasticsearch.search.aggregations.AggregationBuilder;
|
import org.elasticsearch.search.aggregations.AggregationBuilder;
|
||||||
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder;
|
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder;
|
||||||
|
@ -28,6 +26,7 @@ import org.elasticsearch.xpack.sql.querydsl.container.Sort;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
||||||
import static org.elasticsearch.search.sort.SortBuilders.fieldSort;
|
import static org.elasticsearch.search.sort.SortBuilders.fieldSort;
|
||||||
import static org.elasticsearch.search.sort.SortBuilders.scoreSort;
|
import static org.elasticsearch.search.sort.SortBuilders.scoreSort;
|
||||||
import static org.elasticsearch.search.sort.SortBuilders.scriptSort;
|
import static org.elasticsearch.search.sort.SortBuilders.scriptSort;
|
||||||
|
@ -37,20 +36,23 @@ public abstract class SourceGenerator {
|
||||||
private static final List<String> NO_STORED_FIELD = singletonList(StoredFieldsContext._NONE_);
|
private static final List<String> NO_STORED_FIELD = singletonList(StoredFieldsContext._NONE_);
|
||||||
|
|
||||||
public static SearchSourceBuilder sourceBuilder(QueryContainer container, QueryBuilder filter, Integer size) {
|
public static SearchSourceBuilder sourceBuilder(QueryContainer container, QueryBuilder filter, Integer size) {
|
||||||
final SearchSourceBuilder source = new SearchSourceBuilder();
|
QueryBuilder finalQuery = null;
|
||||||
// add the source
|
// add the source
|
||||||
if (container.query() == null) {
|
if (container.query() != null) {
|
||||||
if (filter != null) {
|
if (filter != null) {
|
||||||
source.query(new ConstantScoreQueryBuilder(filter));
|
finalQuery = boolQuery().must(container.query().asBuilder()).filter(filter);
|
||||||
|
} else {
|
||||||
|
finalQuery = container.query().asBuilder();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (filter != null) {
|
if (filter != null) {
|
||||||
source.query(new BoolQueryBuilder().must(container.query().asBuilder()).filter(filter));
|
finalQuery = boolQuery().filter(filter);
|
||||||
} else {
|
|
||||||
source.query(container.query().asBuilder());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final SearchSourceBuilder source = new SearchSourceBuilder();
|
||||||
|
source.query(finalQuery);
|
||||||
|
|
||||||
SqlSourceBuilder sortBuilder = new SqlSourceBuilder();
|
SqlSourceBuilder sortBuilder = new SqlSourceBuilder();
|
||||||
// Iterate through all the columns requested, collecting the fields that
|
// Iterate through all the columns requested, collecting the fields that
|
||||||
// need to be retrieved from the result documents
|
// need to be retrieved from the result documents
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.sql.querydsl.query;
|
package org.elasticsearch.xpack.sql.querydsl.query;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
import org.elasticsearch.index.query.BoolQueryBuilder;
|
||||||
import org.elasticsearch.index.query.QueryBuilder;
|
import org.elasticsearch.index.query.QueryBuilder;
|
||||||
import org.elasticsearch.search.sort.NestedSortBuilder;
|
import org.elasticsearch.search.sort.NestedSortBuilder;
|
||||||
import org.elasticsearch.xpack.sql.tree.Location;
|
import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -63,9 +63,8 @@ public class BoolQuery extends Query {
|
||||||
public QueryBuilder asBuilder() {
|
public QueryBuilder asBuilder() {
|
||||||
BoolQueryBuilder boolQuery = boolQuery();
|
BoolQueryBuilder boolQuery = boolQuery();
|
||||||
if (isAnd) {
|
if (isAnd) {
|
||||||
// TODO are we throwing out score by using filter?
|
boolQuery.must(left.asBuilder());
|
||||||
boolQuery.filter(left.asBuilder());
|
boolQuery.must(right.asBuilder());
|
||||||
boolQuery.filter(right.asBuilder());
|
|
||||||
} else {
|
} else {
|
||||||
boolQuery.should(left.asBuilder());
|
boolQuery.should(left.asBuilder());
|
||||||
boolQuery.should(right.asBuilder());
|
boolQuery.should(right.asBuilder());
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.sql.execution.search;
|
package org.elasticsearch.xpack.sql.execution.search;
|
||||||
|
|
||||||
import org.elasticsearch.index.query.BoolQueryBuilder;
|
|
||||||
import org.elasticsearch.index.query.ConstantScoreQueryBuilder;
|
|
||||||
import org.elasticsearch.index.query.MatchQueryBuilder;
|
|
||||||
import org.elasticsearch.index.query.Operator;
|
import org.elasticsearch.index.query.Operator;
|
||||||
import org.elasticsearch.index.query.QueryBuilder;
|
import org.elasticsearch.index.query.QueryBuilder;
|
||||||
import org.elasticsearch.search.aggregations.AggregatorFactories.Builder;
|
import org.elasticsearch.search.aggregations.AggregatorFactories.Builder;
|
||||||
|
@ -28,6 +25,8 @@ import org.elasticsearch.xpack.sql.tree.Location;
|
||||||
import org.elasticsearch.xpack.sql.type.KeywordEsField;
|
import org.elasticsearch.xpack.sql.type.KeywordEsField;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
|
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
||||||
|
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
|
||||||
import static org.elasticsearch.search.sort.SortBuilders.fieldSort;
|
import static org.elasticsearch.search.sort.SortBuilders.fieldSort;
|
||||||
import static org.elasticsearch.search.sort.SortBuilders.scoreSort;
|
import static org.elasticsearch.search.sort.SortBuilders.scoreSort;
|
||||||
|
|
||||||
|
@ -42,22 +41,22 @@ public class SourceGeneratorTests extends ESTestCase {
|
||||||
public void testQueryNoFilter() {
|
public void testQueryNoFilter() {
|
||||||
QueryContainer container = new QueryContainer().with(new MatchQuery(Location.EMPTY, "foo", "bar"));
|
QueryContainer container = new QueryContainer().with(new MatchQuery(Location.EMPTY, "foo", "bar"));
|
||||||
SearchSourceBuilder sourceBuilder = SourceGenerator.sourceBuilder(container, null, randomIntBetween(1, 10));
|
SearchSourceBuilder sourceBuilder = SourceGenerator.sourceBuilder(container, null, randomIntBetween(1, 10));
|
||||||
assertEquals(new MatchQueryBuilder("foo", "bar").operator(Operator.OR), sourceBuilder.query());
|
assertEquals(matchQuery("foo", "bar").operator(Operator.OR), sourceBuilder.query());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNoQueryFilter() {
|
public void testNoQueryFilter() {
|
||||||
QueryContainer container = new QueryContainer();
|
QueryContainer container = new QueryContainer();
|
||||||
QueryBuilder filter = new MatchQueryBuilder("bar", "baz");
|
QueryBuilder filter = matchQuery("bar", "baz");
|
||||||
SearchSourceBuilder sourceBuilder = SourceGenerator.sourceBuilder(container, filter, randomIntBetween(1, 10));
|
SearchSourceBuilder sourceBuilder = SourceGenerator.sourceBuilder(container, filter, randomIntBetween(1, 10));
|
||||||
assertEquals(new ConstantScoreQueryBuilder(new MatchQueryBuilder("bar", "baz")), sourceBuilder.query());
|
assertEquals(boolQuery().filter(matchQuery("bar", "baz")), sourceBuilder.query());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testQueryFilter() {
|
public void testQueryFilter() {
|
||||||
QueryContainer container = new QueryContainer().with(new MatchQuery(Location.EMPTY, "foo", "bar"));
|
QueryContainer container = new QueryContainer().with(new MatchQuery(Location.EMPTY, "foo", "bar"));
|
||||||
QueryBuilder filter = new MatchQueryBuilder("bar", "baz");
|
QueryBuilder filter = matchQuery("bar", "baz");
|
||||||
SearchSourceBuilder sourceBuilder = SourceGenerator.sourceBuilder(container, filter, randomIntBetween(1, 10));
|
SearchSourceBuilder sourceBuilder = SourceGenerator.sourceBuilder(container, filter, randomIntBetween(1, 10));
|
||||||
assertEquals(new BoolQueryBuilder().must(new MatchQueryBuilder("foo", "bar").operator(Operator.OR))
|
assertEquals(boolQuery().must(matchQuery("foo", "bar").operator(Operator.OR)).filter(matchQuery("bar", "baz")),
|
||||||
.filter(new MatchQueryBuilder("bar", "baz")), sourceBuilder.query());
|
sourceBuilder.query());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testLimit() {
|
public void testLimit() {
|
||||||
|
|
|
@ -16,7 +16,6 @@ import org.elasticsearch.client.Request;
|
||||||
import org.elasticsearch.client.Response;
|
import org.elasticsearch.client.Response;
|
||||||
import org.elasticsearch.client.ResponseException;
|
import org.elasticsearch.client.ResponseException;
|
||||||
import org.elasticsearch.common.CheckedSupplier;
|
import org.elasticsearch.common.CheckedSupplier;
|
||||||
import org.elasticsearch.common.Strings;
|
|
||||||
import org.elasticsearch.common.collect.Tuple;
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
import org.elasticsearch.common.io.Streams;
|
import org.elasticsearch.common.io.Streams;
|
||||||
import org.elasticsearch.common.xcontent.XContentHelper;
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||||
|
@ -33,12 +32,11 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.sql.JDBCType;
|
import java.sql.JDBCType;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
import static java.util.Collections.emptyList;
|
import static java.util.Collections.emptyList;
|
||||||
import static java.util.Collections.emptyMap;
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static java.util.Collections.singletonMap;
|
import static java.util.Collections.singletonMap;
|
||||||
import static java.util.Collections.unmodifiableMap;
|
import static java.util.Collections.unmodifiableMap;
|
||||||
|
@ -396,19 +394,23 @@ public abstract class RestSqlTestCase extends ESRestTestCase implements ErrorsTe
|
||||||
assertNotNull(query);
|
assertNotNull(query);
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, Object> constantScore = (Map<String, Object>) query.get("constant_score");
|
Map<String, Object> bool = (Map<String, Object>) query.get("bool");
|
||||||
assertNotNull(constantScore);
|
assertNotNull(bool);
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, Object> filter = (Map<String, Object>) constantScore.get("filter");
|
List<Object> filter = (List<Object>) bool.get("filter");
|
||||||
assertNotNull(filter);
|
assertNotNull(filter);
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, Object> match = (Map<String, Object>) filter.get("match");
|
Map<String, Object> map = (Map<String, Object>) filter.get(0);
|
||||||
assertNotNull(match);
|
assertNotNull(map);
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, Object> matchQuery = (Map<String, Object>) match.get("test");
|
Map<String, Object> matchQ = (Map<String, Object>) map.get("match");
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> matchQuery = (Map<String, Object>) matchQ.get("test");
|
||||||
|
|
||||||
assertNotNull(matchQuery);
|
assertNotNull(matchQuery);
|
||||||
assertEquals("foo", matchQuery.get("query"));
|
assertEquals("foo", matchQuery.get("query"));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue