We were checking for loops in queries before, but we had an "off by one" error where we wouldn't notice the "top level" runtime field when detecting a loop. So the error message would be wrong. I also caught a few bugs with query generation caused by missing `@Override` annotations and fixed a few of them. There is a bug with `regexp` queries with match options that I'm not fixing in this PR but will get to later. Relates to #59332
This commit is contained in:
parent
0a7f335215
commit
e5ad3a41f1
|
@ -12,6 +12,7 @@ import org.apache.lucene.search.Query;
|
|||
import org.apache.lucene.search.spans.SpanMultiTermQueryWrapper;
|
||||
import org.apache.lucene.search.spans.SpanQuery;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.TriFunction;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.common.time.DateMathParser;
|
||||
import org.elasticsearch.common.unit.Fuzziness;
|
||||
|
@ -19,6 +20,7 @@ import org.elasticsearch.index.mapper.MappedFieldType;
|
|||
import org.elasticsearch.index.mapper.TextSearchInfo;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.search.lookup.SearchLookup;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.ZoneId;
|
||||
|
@ -31,12 +33,19 @@ import static org.elasticsearch.search.SearchService.ALLOW_EXPENSIVE_QUERIES;
|
|||
/**
|
||||
* Abstract base {@linkplain MappedFieldType} for scripted fields.
|
||||
*/
|
||||
abstract class AbstractScriptMappedFieldType extends MappedFieldType {
|
||||
abstract class AbstractScriptMappedFieldType<LeafFactory> extends MappedFieldType {
|
||||
protected final Script script;
|
||||
private final TriFunction<String, Map<String, Object>, SearchLookup, LeafFactory> factory;
|
||||
|
||||
AbstractScriptMappedFieldType(String name, Script script, Map<String, String> meta) {
|
||||
AbstractScriptMappedFieldType(
|
||||
String name,
|
||||
Script script,
|
||||
TriFunction<String, Map<String, Object>, SearchLookup, LeafFactory> factory,
|
||||
Map<String, String> meta
|
||||
) {
|
||||
super(name, false, false, TextSearchInfo.SIMPLE_MATCH_ONLY, meta);
|
||||
this.script = script;
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
protected abstract String runtimeType();
|
||||
|
@ -61,6 +70,26 @@ abstract class AbstractScriptMappedFieldType extends MappedFieldType {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a script leaf factory.
|
||||
*/
|
||||
protected final LeafFactory leafFactory(SearchLookup searchLookup) {
|
||||
return factory.apply(name(), script.getParams(), searchLookup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a script leaf factory for queries.
|
||||
*/
|
||||
protected final LeafFactory leafFactory(QueryShardContext context) {
|
||||
/*
|
||||
* Forking here causes us to count this field in the field data loop
|
||||
* detection code as though we were resolving field data for this field.
|
||||
* We're not, but running the query is close enough.
|
||||
*/
|
||||
return leafFactory(context.lookup().forkAndTrackFieldReferences(name()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Query termsQuery(List<?> values, QueryShardContext context);
|
||||
|
||||
@Override
|
||||
|
@ -149,8 +178,15 @@ abstract class AbstractScriptMappedFieldType extends MappedFieldType {
|
|||
}
|
||||
|
||||
private String unsupported(String query, String supported) {
|
||||
String thisField = "[" + name() + "] which is of type [script] with runtime_type [" + runtimeType() + "]";
|
||||
return "Can only use " + query + " queries on " + supported + " fields - not on " + thisField;
|
||||
return String.format(
|
||||
Locale.ROOT,
|
||||
"Can only use %s queries on %s fields - not on [%s] which is of type [%s] with runtime_type [%s]",
|
||||
query,
|
||||
supported,
|
||||
name(),
|
||||
RuntimeFieldMapper.CONTENT_TYPE,
|
||||
runtimeType()
|
||||
);
|
||||
}
|
||||
|
||||
protected final void checkAllowExpensiveQueries(QueryShardContext context) {
|
||||
|
|
|
@ -51,7 +51,7 @@ public final class RuntimeFieldMapper extends ParametrizedFieldMapper {
|
|||
|
||||
protected RuntimeFieldMapper(
|
||||
String simpleName,
|
||||
AbstractScriptMappedFieldType mappedFieldType,
|
||||
AbstractScriptMappedFieldType<?> mappedFieldType,
|
||||
MultiFields multiFields,
|
||||
CopyTo copyTo,
|
||||
String runtimeType,
|
||||
|
@ -86,7 +86,7 @@ public final class RuntimeFieldMapper extends ParametrizedFieldMapper {
|
|||
|
||||
public static class Builder extends ParametrizedFieldMapper.Builder {
|
||||
|
||||
static final Map<String, BiFunction<Builder, BuilderContext, AbstractScriptMappedFieldType>> FIELD_TYPE_RESOLVER =
|
||||
static final Map<String, BiFunction<Builder, BuilderContext, AbstractScriptMappedFieldType<?>>> FIELD_TYPE_RESOLVER =
|
||||
org.elasticsearch.common.collect.Map.of(BooleanFieldMapper.CONTENT_TYPE, (builder, context) -> {
|
||||
builder.formatAndLocaleNotSupported();
|
||||
BooleanScriptFieldScript.Factory factory = builder.scriptCompiler.compile(
|
||||
|
@ -199,7 +199,7 @@ public final class RuntimeFieldMapper extends ParametrizedFieldMapper {
|
|||
private final Parameter<String> format = Parameter.stringParam(
|
||||
"format",
|
||||
true,
|
||||
mapper -> ((AbstractScriptMappedFieldType) mapper.fieldType()).format(),
|
||||
mapper -> ((AbstractScriptMappedFieldType<?>) mapper.fieldType()).format(),
|
||||
null
|
||||
).setSerializer((b, n, v) -> {
|
||||
if (v != null && false == v.equals(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.pattern())) {
|
||||
|
@ -211,7 +211,7 @@ public final class RuntimeFieldMapper extends ParametrizedFieldMapper {
|
|||
true,
|
||||
() -> null,
|
||||
(n, c, o) -> o == null ? null : LocaleUtils.parse(o.toString()),
|
||||
mapper -> ((AbstractScriptMappedFieldType) mapper.fieldType()).formatLocale()
|
||||
mapper -> ((AbstractScriptMappedFieldType<?>) mapper.fieldType()).formatLocale()
|
||||
).setSerializer((b, n, v) -> {
|
||||
if (v != null && false == v.equals(Locale.ROOT)) {
|
||||
b.field(n, v.toString());
|
||||
|
@ -232,7 +232,7 @@ public final class RuntimeFieldMapper extends ParametrizedFieldMapper {
|
|||
|
||||
@Override
|
||||
public RuntimeFieldMapper build(BuilderContext context) {
|
||||
BiFunction<Builder, BuilderContext, AbstractScriptMappedFieldType> fieldTypeResolver = Builder.FIELD_TYPE_RESOLVER.get(
|
||||
BiFunction<Builder, BuilderContext, AbstractScriptMappedFieldType<?>> fieldTypeResolver = Builder.FIELD_TYPE_RESOLVER.get(
|
||||
runtimeType.getValue()
|
||||
);
|
||||
if (fieldTypeResolver == null) {
|
||||
|
|
|
@ -27,12 +27,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ScriptBooleanMappedFieldType extends AbstractScriptMappedFieldType {
|
||||
private final BooleanScriptFieldScript.Factory scriptFactory;
|
||||
|
||||
public class ScriptBooleanMappedFieldType extends AbstractScriptMappedFieldType<BooleanScriptFieldScript.LeafFactory> {
|
||||
ScriptBooleanMappedFieldType(String name, Script script, BooleanScriptFieldScript.Factory scriptFactory, Map<String, String> meta) {
|
||||
super(name, script, meta);
|
||||
this.scriptFactory = scriptFactory;
|
||||
super(name, script, scriptFactory::newFactory, meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,14 +68,10 @@ public class ScriptBooleanMappedFieldType extends AbstractScriptMappedFieldType
|
|||
return new ScriptBooleanFieldData.Builder(name(), leafFactory(searchLookup.get()));
|
||||
}
|
||||
|
||||
private BooleanScriptFieldScript.LeafFactory leafFactory(SearchLookup searchLookup) {
|
||||
return scriptFactory.newFactory(name(), script.getParams(), searchLookup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query existsQuery(QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new BooleanScriptFieldExistsQuery(script, leafFactory(context.lookup()), name());
|
||||
return new BooleanScriptFieldExistsQuery(script, leafFactory(context), name());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -149,7 +142,7 @@ public class ScriptBooleanMappedFieldType extends AbstractScriptMappedFieldType
|
|||
@Override
|
||||
public Query termQuery(Object value, QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new BooleanScriptFieldTermQuery(script, leafFactory(context.lookup()), name(), toBoolean(value));
|
||||
return new BooleanScriptFieldTermQuery(script, leafFactory(context), name(), toBoolean(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -176,11 +169,11 @@ public class ScriptBooleanMappedFieldType extends AbstractScriptMappedFieldType
|
|||
return existsQuery(context);
|
||||
}
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new BooleanScriptFieldTermQuery(script, leafFactory(context.lookup()), name(), true);
|
||||
return new BooleanScriptFieldTermQuery(script, leafFactory(context), name(), true);
|
||||
}
|
||||
if (falseAllowed) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new BooleanScriptFieldTermQuery(script, leafFactory(context.lookup()), name(), false);
|
||||
return new BooleanScriptFieldTermQuery(script, leafFactory(context), name(), false);
|
||||
}
|
||||
return new MatchNoDocsQuery("neither true nor false allowed");
|
||||
}
|
||||
|
|
|
@ -37,8 +37,7 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ScriptDateMappedFieldType extends AbstractScriptMappedFieldType {
|
||||
private final DateScriptFieldScript.Factory scriptFactory;
|
||||
public class ScriptDateMappedFieldType extends AbstractScriptMappedFieldType<DateScriptFieldScript.LeafFactory> {
|
||||
private final DateFormatter dateTimeFormatter;
|
||||
|
||||
ScriptDateMappedFieldType(
|
||||
|
@ -48,8 +47,7 @@ public class ScriptDateMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
DateFormatter dateTimeFormatter,
|
||||
Map<String, String> meta
|
||||
) {
|
||||
super(name, script, meta);
|
||||
this.scriptFactory = scriptFactory;
|
||||
super(name, script, (n, params, ctx) -> scriptFactory.newFactory(n, params, ctx, dateTimeFormatter), meta);
|
||||
this.dateTimeFormatter = dateTimeFormatter;
|
||||
}
|
||||
|
||||
|
@ -84,10 +82,6 @@ public class ScriptDateMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
return new ScriptDateFieldData.Builder(name(), leafFactory(lookup.get()));
|
||||
}
|
||||
|
||||
private DateScriptFieldScript.LeafFactory leafFactory(SearchLookup lookup) {
|
||||
return scriptFactory.newFactory(name(), script.getParams(), lookup, dateTimeFormatter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query distanceFeatureQuery(Object origin, String pivot, float boost, QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
|
@ -103,7 +97,7 @@ public class ScriptDateMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
TimeValue pivotTime = TimeValue.parseTimeValue(pivot, "distance_feature.pivot");
|
||||
return new LongScriptFieldDistanceFeatureQuery(
|
||||
script,
|
||||
leafFactory(context.lookup())::newInstance,
|
||||
leafFactory(context)::newInstance,
|
||||
name(),
|
||||
originLong,
|
||||
pivotTime.getMillis(),
|
||||
|
@ -115,7 +109,7 @@ public class ScriptDateMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
@Override
|
||||
public Query existsQuery(QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new LongScriptFieldExistsQuery(script, leafFactory(context.lookup())::newInstance, name());
|
||||
return new LongScriptFieldExistsQuery(script, leafFactory(context)::newInstance, name());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -139,7 +133,7 @@ public class ScriptDateMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
parser,
|
||||
context,
|
||||
DateFieldMapper.Resolution.MILLISECONDS,
|
||||
(l, u) -> new LongScriptFieldRangeQuery(script, leafFactory(context.lookup())::newInstance, name(), l, u)
|
||||
(l, u) -> new LongScriptFieldRangeQuery(script, leafFactory(context)::newInstance, name(), l, u)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -155,7 +149,7 @@ public class ScriptDateMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
DateFieldMapper.Resolution.MILLISECONDS
|
||||
);
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new LongScriptFieldTermQuery(script, leafFactory(context.lookup())::newInstance, name(), l);
|
||||
return new LongScriptFieldTermQuery(script, leafFactory(context)::newInstance, name(), l);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -179,7 +173,7 @@ public class ScriptDateMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
);
|
||||
}
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new LongScriptFieldTermsQuery(script, leafFactory(context.lookup())::newInstance, name(), terms);
|
||||
return new LongScriptFieldTermsQuery(script, leafFactory(context)::newInstance, name(), terms);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -29,12 +29,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ScriptDoubleMappedFieldType extends AbstractScriptMappedFieldType {
|
||||
private final DoubleScriptFieldScript.Factory scriptFactory;
|
||||
|
||||
public class ScriptDoubleMappedFieldType extends AbstractScriptMappedFieldType<DoubleScriptFieldScript.LeafFactory> {
|
||||
ScriptDoubleMappedFieldType(String name, Script script, DoubleScriptFieldScript.Factory scriptFactory, Map<String, String> meta) {
|
||||
super(name, script, meta);
|
||||
this.scriptFactory = scriptFactory;
|
||||
super(name, script, scriptFactory::newFactory, meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,14 +60,10 @@ public class ScriptDoubleMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
return new ScriptDoubleFieldData.Builder(name(), leafFactory(searchLookup.get()));
|
||||
}
|
||||
|
||||
private DoubleScriptFieldScript.LeafFactory leafFactory(SearchLookup searchLookup) {
|
||||
return scriptFactory.newFactory(name(), script.getParams(), searchLookup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query existsQuery(QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new DoubleScriptFieldExistsQuery(script, leafFactory(context.lookup()), name());
|
||||
return new DoubleScriptFieldExistsQuery(script, leafFactory(context), name());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,14 +82,14 @@ public class ScriptDoubleMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
upperTerm,
|
||||
includeLower,
|
||||
includeUpper,
|
||||
(l, u) -> new DoubleScriptFieldRangeQuery(script, leafFactory(context.lookup()), name(), l, u)
|
||||
(l, u) -> new DoubleScriptFieldRangeQuery(script, leafFactory(context), name(), l, u)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query termQuery(Object value, QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new DoubleScriptFieldTermQuery(script, leafFactory(context.lookup()), name(), NumberType.objectToDouble(value));
|
||||
return new DoubleScriptFieldTermQuery(script, leafFactory(context), name(), NumberType.objectToDouble(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,6 +102,6 @@ public class ScriptDoubleMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
terms.add(Double.doubleToLongBits(NumberType.objectToDouble(value)));
|
||||
}
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new DoubleScriptFieldTermsQuery(script, leafFactory(context.lookup()), name(), terms);
|
||||
return new DoubleScriptFieldTermsQuery(script, leafFactory(context), name(), terms);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,15 +37,9 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class ScriptIpMappedFieldType extends AbstractScriptMappedFieldType {
|
||||
|
||||
private final Script script;
|
||||
private final IpScriptFieldScript.Factory scriptFactory;
|
||||
|
||||
public final class ScriptIpMappedFieldType extends AbstractScriptMappedFieldType<IpScriptFieldScript.LeafFactory> {
|
||||
ScriptIpMappedFieldType(String name, Script script, IpScriptFieldScript.Factory scriptFactory, Map<String, String> meta) {
|
||||
super(name, script, meta);
|
||||
this.script = script;
|
||||
this.scriptFactory = scriptFactory;
|
||||
super(name, script, scriptFactory::newFactory, meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,14 +73,10 @@ public final class ScriptIpMappedFieldType extends AbstractScriptMappedFieldType
|
|||
return new ScriptIpFieldData.Builder(name(), leafFactory(searchLookup.get()));
|
||||
}
|
||||
|
||||
private IpScriptFieldScript.LeafFactory leafFactory(SearchLookup searchLookup) {
|
||||
return scriptFactory.newFactory(name(), script.getParams(), searchLookup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query existsQuery(QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new IpScriptFieldExistsQuery(script, leafFactory(context.lookup()), name());
|
||||
return new IpScriptFieldExistsQuery(script, leafFactory(context), name());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -107,7 +97,7 @@ public final class ScriptIpMappedFieldType extends AbstractScriptMappedFieldType
|
|||
includeUpper,
|
||||
(lower, upper) -> new IpScriptFieldRangeQuery(
|
||||
script,
|
||||
leafFactory(context.lookup()),
|
||||
leafFactory(context),
|
||||
name(),
|
||||
new BytesRef(InetAddressPoint.encode(lower)),
|
||||
new BytesRef(InetAddressPoint.encode(upper))
|
||||
|
@ -119,14 +109,18 @@ public final class ScriptIpMappedFieldType extends AbstractScriptMappedFieldType
|
|||
public Query termQuery(Object value, QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
if (value instanceof InetAddress) {
|
||||
return InetAddressPoint.newExactQuery(name(), (InetAddress) value);
|
||||
return inetAddressQuery((InetAddress) value, context);
|
||||
}
|
||||
String term = BytesRefs.toString(value);
|
||||
if (term.contains("/")) {
|
||||
return cidrQuery(term, context);
|
||||
}
|
||||
InetAddress address = InetAddresses.forString(term);
|
||||
return new IpScriptFieldTermQuery(script, leafFactory(context.lookup()), name(), new BytesRef(InetAddressPoint.encode(address)));
|
||||
return inetAddressQuery(address, context);
|
||||
}
|
||||
|
||||
private Query inetAddressQuery(InetAddress address, QueryShardContext context) {
|
||||
return new IpScriptFieldTermQuery(script, leafFactory(context), name(), new BytesRef(InetAddressPoint.encode(address)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -149,7 +143,7 @@ public final class ScriptIpMappedFieldType extends AbstractScriptMappedFieldType
|
|||
}
|
||||
cidrQueries.add(cidrQuery(term, context));
|
||||
}
|
||||
Query termsQuery = new IpScriptFieldTermsQuery(script, leafFactory(context.lookup()), name(), terms);
|
||||
Query termsQuery = new IpScriptFieldTermsQuery(script, leafFactory(context), name(), terms);
|
||||
if (cidrQueries == null) {
|
||||
return termsQuery;
|
||||
}
|
||||
|
@ -176,6 +170,6 @@ public final class ScriptIpMappedFieldType extends AbstractScriptMappedFieldType
|
|||
// Force the terms into IPv6
|
||||
BytesRef lowerBytes = new BytesRef(InetAddressPoint.encode(InetAddressPoint.decode(lower)));
|
||||
BytesRef upperBytes = new BytesRef(InetAddressPoint.encode(InetAddressPoint.decode(upper)));
|
||||
return new IpScriptFieldRangeQuery(script, leafFactory(context.lookup()), name(), lowerBytes, upperBytes);
|
||||
return new IpScriptFieldRangeQuery(script, leafFactory(context), name(), lowerBytes, upperBytes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,15 +36,9 @@ import java.util.function.Supplier;
|
|||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
public final class ScriptKeywordMappedFieldType extends AbstractScriptMappedFieldType {
|
||||
|
||||
private final Script script;
|
||||
private final StringScriptFieldScript.Factory scriptFactory;
|
||||
|
||||
public final class ScriptKeywordMappedFieldType extends AbstractScriptMappedFieldType<StringScriptFieldScript.LeafFactory> {
|
||||
ScriptKeywordMappedFieldType(String name, Script script, StringScriptFieldScript.Factory scriptFactory, Map<String, String> meta) {
|
||||
super(name, script, meta);
|
||||
this.script = script;
|
||||
this.scriptFactory = scriptFactory;
|
||||
super(name, script, scriptFactory::newFactory, meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -67,14 +61,10 @@ public final class ScriptKeywordMappedFieldType extends AbstractScriptMappedFiel
|
|||
return new ScriptStringFieldData.Builder(name(), leafFactory(searchLookup.get()));
|
||||
}
|
||||
|
||||
private StringScriptFieldScript.LeafFactory leafFactory(SearchLookup searchLookup) {
|
||||
return scriptFactory.newFactory(name(), script.getParams(), searchLookup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query existsQuery(QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new StringScriptFieldExistsQuery(script, leafFactory(context.lookup()), name());
|
||||
return new StringScriptFieldExistsQuery(script, leafFactory(context), name());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,7 +79,7 @@ public final class ScriptKeywordMappedFieldType extends AbstractScriptMappedFiel
|
|||
checkAllowExpensiveQueries(context);
|
||||
return StringScriptFieldFuzzyQuery.build(
|
||||
script,
|
||||
leafFactory(context.lookup()),
|
||||
leafFactory(context),
|
||||
name(),
|
||||
BytesRefs.toString(Objects.requireNonNull(value)),
|
||||
fuzziness.asDistance(BytesRefs.toString(value)),
|
||||
|
@ -101,7 +91,7 @@ public final class ScriptKeywordMappedFieldType extends AbstractScriptMappedFiel
|
|||
@Override
|
||||
public Query prefixQuery(String value, RewriteMethod method, org.elasticsearch.index.query.QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new StringScriptFieldPrefixQuery(script, leafFactory(context.lookup()), name(), value);
|
||||
return new StringScriptFieldPrefixQuery(script, leafFactory(context), name(), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -117,7 +107,7 @@ public final class ScriptKeywordMappedFieldType extends AbstractScriptMappedFiel
|
|||
checkAllowExpensiveQueries(context);
|
||||
return new StringScriptFieldRangeQuery(
|
||||
script,
|
||||
leafFactory(context.lookup()),
|
||||
leafFactory(context),
|
||||
name(),
|
||||
BytesRefs.toString(Objects.requireNonNull(lowerTerm)),
|
||||
BytesRefs.toString(Objects.requireNonNull(upperTerm)),
|
||||
|
@ -139,30 +129,25 @@ public final class ScriptKeywordMappedFieldType extends AbstractScriptMappedFiel
|
|||
if (matchFlags != 0) {
|
||||
throw new IllegalArgumentException("Match flags not yet implemented [" + matchFlags + "]");
|
||||
}
|
||||
return new StringScriptFieldRegexpQuery(script, leafFactory(context.lookup()), name(), value, syntaxFlags, maxDeterminizedStates);
|
||||
return new StringScriptFieldRegexpQuery(script, leafFactory(context), name(), value, syntaxFlags, maxDeterminizedStates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query termQuery(Object value, QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new StringScriptFieldTermQuery(
|
||||
script,
|
||||
leafFactory(context.lookup()),
|
||||
name(),
|
||||
BytesRefs.toString(Objects.requireNonNull(value))
|
||||
);
|
||||
return new StringScriptFieldTermQuery(script, leafFactory(context), name(), BytesRefs.toString(Objects.requireNonNull(value)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query termsQuery(List<?> values, QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
Set<String> terms = values.stream().map(v -> BytesRefs.toString(Objects.requireNonNull(v))).collect(toSet());
|
||||
return new StringScriptFieldTermsQuery(script, leafFactory(context.lookup()), name(), terms);
|
||||
return new StringScriptFieldTermsQuery(script, leafFactory(context), name(), terms);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query wildcardQuery(String value, RewriteMethod method, QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new StringScriptFieldWildcardQuery(script, leafFactory(context.lookup()), name(), value);
|
||||
return new StringScriptFieldWildcardQuery(script, leafFactory(context), name(), value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,12 +29,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ScriptLongMappedFieldType extends AbstractScriptMappedFieldType {
|
||||
private final LongScriptFieldScript.Factory scriptFactory;
|
||||
|
||||
public class ScriptLongMappedFieldType extends AbstractScriptMappedFieldType<LongScriptFieldScript.LeafFactory> {
|
||||
ScriptLongMappedFieldType(String name, Script script, LongScriptFieldScript.Factory scriptFactory, Map<String, String> meta) {
|
||||
super(name, script, meta);
|
||||
this.scriptFactory = scriptFactory;
|
||||
super(name, script, scriptFactory::newFactory, meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,14 +60,10 @@ public class ScriptLongMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
return new ScriptLongFieldData.Builder(name(), leafFactory(searchLookup.get()));
|
||||
}
|
||||
|
||||
private LongScriptFieldScript.LeafFactory leafFactory(SearchLookup searchLookup) {
|
||||
return scriptFactory.newFactory(name(), script.getParams(), searchLookup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query existsQuery(QueryShardContext context) {
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new LongScriptFieldExistsQuery(script, leafFactory(context.lookup())::newInstance, name());
|
||||
return new LongScriptFieldExistsQuery(script, leafFactory(context)::newInstance, name());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,7 +82,7 @@ public class ScriptLongMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
upperTerm,
|
||||
includeLower,
|
||||
includeUpper,
|
||||
(l, u) -> new LongScriptFieldRangeQuery(script, leafFactory(context.lookup())::newInstance, name(), l, u)
|
||||
(l, u) -> new LongScriptFieldRangeQuery(script, leafFactory(context)::newInstance, name(), l, u)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -99,12 +92,7 @@ public class ScriptLongMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
return Queries.newMatchNoDocsQuery("Value [" + value + "] has a decimal part");
|
||||
}
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new LongScriptFieldTermQuery(
|
||||
script,
|
||||
leafFactory(context.lookup())::newInstance,
|
||||
name(),
|
||||
NumberType.objectToLong(value, true)
|
||||
);
|
||||
return new LongScriptFieldTermQuery(script, leafFactory(context)::newInstance, name(), NumberType.objectToLong(value, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -123,6 +111,6 @@ public class ScriptLongMappedFieldType extends AbstractScriptMappedFieldType {
|
|||
return Queries.newMatchNoDocsQuery("All values have a decimal part");
|
||||
}
|
||||
checkAllowExpensiveQueries(context);
|
||||
return new LongScriptFieldTermsQuery(script, leafFactory(context.lookup())::newInstance, name(), terms);
|
||||
return new LongScriptFieldTermsQuery(script, leafFactory(context)::newInstance, name(), terms);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ abstract class AbstractNonTextScriptMappedFieldTypeTestCase extends AbstractScri
|
|||
equalTo(
|
||||
"Can only use "
|
||||
+ queryName
|
||||
+ " queries on keyword and text fields - not on [test] which is of type [script] with runtime_type ["
|
||||
+ " queries on keyword and text fields - not on [test] which is of type [runtime] with runtime_type ["
|
||||
+ runtimeType()
|
||||
+ "]"
|
||||
)
|
||||
|
@ -57,7 +57,7 @@ abstract class AbstractNonTextScriptMappedFieldTypeTestCase extends AbstractScri
|
|||
equalTo(
|
||||
"Can only use "
|
||||
+ queryName
|
||||
+ " queries on keyword, text and wildcard fields - not on [test] which is of type [script] with runtime_type ["
|
||||
+ " queries on keyword, text and wildcard fields - not on [test] which is of type [runtime] with runtime_type ["
|
||||
+ runtimeType()
|
||||
+ "]"
|
||||
)
|
||||
|
|
|
@ -7,13 +7,17 @@
|
|||
package org.elasticsearch.xpack.runtimefields.mapper;
|
||||
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.geo.ShapeRelation;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.search.lookup.SearchLookup;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.mockito.Matchers.any;
|
||||
|
@ -22,7 +26,9 @@ import static org.mockito.Mockito.mock;
|
|||
import static org.mockito.Mockito.when;
|
||||
|
||||
abstract class AbstractScriptMappedFieldTypeTestCase extends ESTestCase {
|
||||
protected abstract AbstractScriptMappedFieldType simpleMappedFieldType() throws IOException;
|
||||
protected abstract MappedFieldType simpleMappedFieldType() throws IOException;
|
||||
|
||||
protected abstract MappedFieldType loopFieldType() throws IOException;
|
||||
|
||||
protected abstract String runtimeType();
|
||||
|
||||
|
@ -38,26 +44,20 @@ abstract class AbstractScriptMappedFieldTypeTestCase extends ESTestCase {
|
|||
@SuppressWarnings("unused")
|
||||
public abstract void testExistsQuery() throws IOException;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public abstract void testExistsQueryIsExpensive() throws IOException;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public abstract void testRangeQuery() throws IOException;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public abstract void testRangeQueryIsExpensive() throws IOException;
|
||||
protected abstract Query randomRangeQuery(MappedFieldType ft, QueryShardContext ctx);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public abstract void testTermQuery() throws IOException;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public abstract void testTermQueryIsExpensive() throws IOException;
|
||||
protected abstract Query randomTermQuery(MappedFieldType ft, QueryShardContext ctx);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public abstract void testTermsQuery() throws IOException;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public abstract void testTermsQueryIsExpensive() throws IOException;
|
||||
protected abstract Query randomTermsQuery(MappedFieldType ft, QueryShardContext ctx);
|
||||
|
||||
protected static QueryShardContext mockContext() {
|
||||
return mockContext(true);
|
||||
|
@ -67,7 +67,7 @@ abstract class AbstractScriptMappedFieldTypeTestCase extends ESTestCase {
|
|||
return mockContext(allowExpensiveQueries, null);
|
||||
}
|
||||
|
||||
protected static QueryShardContext mockContext(boolean allowExpensiveQueries, AbstractScriptMappedFieldType mappedFieldType) {
|
||||
protected static QueryShardContext mockContext(boolean allowExpensiveQueries, MappedFieldType mappedFieldType) {
|
||||
MapperService mapperService = mock(MapperService.class);
|
||||
when(mapperService.fieldType(anyString())).thenReturn(mappedFieldType);
|
||||
QueryShardContext context = mock(QueryShardContext.class);
|
||||
|
@ -86,6 +86,14 @@ abstract class AbstractScriptMappedFieldTypeTestCase extends ESTestCase {
|
|||
return context;
|
||||
}
|
||||
|
||||
public void testExistsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(MappedFieldType::existsQuery);
|
||||
}
|
||||
|
||||
public void testExistsQueryInLoop() throws IOException {
|
||||
checkLoop(MappedFieldType::existsQuery);
|
||||
}
|
||||
|
||||
public void testRangeQueryWithShapeRelationIsError() throws IOException {
|
||||
Exception e = expectThrows(
|
||||
IllegalArgumentException.class,
|
||||
|
@ -97,6 +105,30 @@ abstract class AbstractScriptMappedFieldTypeTestCase extends ESTestCase {
|
|||
);
|
||||
}
|
||||
|
||||
public void testRangeQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(this::randomRangeQuery);
|
||||
}
|
||||
|
||||
public void testRangeQueryInLoop() throws IOException {
|
||||
checkLoop(this::randomRangeQuery);
|
||||
}
|
||||
|
||||
public void testTermQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(this::randomTermQuery);
|
||||
}
|
||||
|
||||
public void testTermQueryInLoop() throws IOException {
|
||||
checkLoop(this::randomTermQuery);
|
||||
}
|
||||
|
||||
public void testTermsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(this::randomTermsQuery);
|
||||
}
|
||||
|
||||
public void testTermsQueryInLoop() throws IOException {
|
||||
checkLoop(this::randomTermsQuery);
|
||||
}
|
||||
|
||||
public void testPhraseQueryIsError() {
|
||||
assertQueryOnlyOnText("phrase", () -> simpleMappedFieldType().phraseQuery(null, 1, false));
|
||||
}
|
||||
|
@ -120,7 +152,7 @@ abstract class AbstractScriptMappedFieldTypeTestCase extends ESTestCase {
|
|||
equalTo(
|
||||
"Can only use "
|
||||
+ queryName
|
||||
+ " queries on text fields - not on [test] which is of type [script] with runtime_type ["
|
||||
+ " queries on text fields - not on [test] which is of type [runtime] with runtime_type ["
|
||||
+ runtimeType()
|
||||
+ "]"
|
||||
)
|
||||
|
@ -130,4 +162,17 @@ abstract class AbstractScriptMappedFieldTypeTestCase extends ESTestCase {
|
|||
protected String readSource(IndexReader reader, int docId) throws IOException {
|
||||
return reader.document(docId).getBinaryValue("_source").utf8ToString();
|
||||
}
|
||||
|
||||
protected final void checkExpensiveQuery(BiConsumer<MappedFieldType, QueryShardContext> queryBuilder) throws IOException {
|
||||
Exception e = expectThrows(ElasticsearchException.class, () -> queryBuilder.accept(simpleMappedFieldType(), mockContext(false)));
|
||||
assertThat(
|
||||
e.getMessage(),
|
||||
equalTo("queries cannot be executed against [runtime] fields while [search.allow_expensive_queries] is set to [false].")
|
||||
);
|
||||
}
|
||||
|
||||
protected final void checkLoop(BiConsumer<MappedFieldType, QueryShardContext> queryBuilder) throws IOException {
|
||||
Exception e = expectThrows(IllegalArgumentException.class, () -> queryBuilder.accept(loopFieldType(), mockContext()));
|
||||
assertThat(e.getMessage(), equalTo("Cyclic dependency detected while resolving runtime fields: test -> test"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ import java.util.Set;
|
|||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class RuntimeFieldMapperTests extends MapperTestCase {
|
||||
|
||||
|
@ -316,7 +317,12 @@ public class RuntimeFieldMapperTests extends MapperTestCase {
|
|||
IllegalArgumentException iae = expectThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> config.buildIndexSort(
|
||||
field -> new ScriptKeywordMappedFieldType(field, new Script(""), null, Collections.emptyMap()),
|
||||
field -> new ScriptKeywordMappedFieldType(
|
||||
field,
|
||||
new Script(""),
|
||||
mock(StringScriptFieldScript.Factory.class),
|
||||
Collections.emptyMap()
|
||||
),
|
||||
(fieldType, searchLookupSupplier) -> indexFieldDataService.getForField(fieldType, "index", searchLookupSupplier)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.apache.lucene.search.SortField;
|
|||
import org.apache.lucene.search.TopFieldDocs;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.lucene.search.function.ScriptScoreQuery;
|
||||
|
@ -61,7 +60,6 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
@ -171,10 +169,6 @@ public class ScriptBooleanMappedFieldTypeTests extends AbstractNonTextScriptMapp
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testExistsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(ScriptBooleanMappedFieldType::existsQuery);
|
||||
}
|
||||
|
||||
public void testRangeQuery() throws IOException {
|
||||
try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) {
|
||||
iw.addDocument(org.elasticsearch.common.collect.List.of(new StoredField("_source", new BytesRef("{\"foo\": [true]}"))));
|
||||
|
@ -213,11 +207,7 @@ public class ScriptBooleanMappedFieldTypeTests extends AbstractNonTextScriptMapp
|
|||
}
|
||||
}
|
||||
|
||||
public void testRangeQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.rangeQuery(true, true, true, true, null, null, null, ctx));
|
||||
checkExpensiveQuery((ft, ctx) -> ft.rangeQuery(false, true, true, true, null, null, null, ctx));
|
||||
checkExpensiveQuery((ft, ctx) -> ft.rangeQuery(false, true, false, true, null, null, null, ctx));
|
||||
// These are not expensive queries
|
||||
public void testRangeQueryDegeneratesIntoNotExpensive() throws IOException {
|
||||
assertThat(
|
||||
simpleMappedFieldType().rangeQuery(true, true, false, false, null, null, null, mockContext()),
|
||||
instanceOf(MatchNoDocsQuery.class)
|
||||
|
@ -226,6 +216,30 @@ public class ScriptBooleanMappedFieldTypeTests extends AbstractNonTextScriptMapp
|
|||
simpleMappedFieldType().rangeQuery(false, false, false, false, null, null, null, mockContext()),
|
||||
instanceOf(MatchNoDocsQuery.class)
|
||||
);
|
||||
// Even if the running the field would blow up because it loops the query *still* just returns none.
|
||||
assertThat(
|
||||
loopFieldType().rangeQuery(true, true, false, false, null, null, null, mockContext()),
|
||||
instanceOf(MatchNoDocsQuery.class)
|
||||
);
|
||||
assertThat(
|
||||
loopFieldType().rangeQuery(false, false, false, false, null, null, null, mockContext()),
|
||||
instanceOf(MatchNoDocsQuery.class)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Query randomRangeQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
// Builds a random range query that doesn't degenerate into match none
|
||||
switch (randomInt(2)) {
|
||||
case 0:
|
||||
return ft.rangeQuery(true, true, true, true, null, null, null, ctx);
|
||||
case 1:
|
||||
return ft.rangeQuery(false, true, true, true, null, null, null, ctx);
|
||||
case 2:
|
||||
return ft.rangeQuery(false, true, false, true, null, null, null, ctx);
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -264,8 +278,8 @@ public class ScriptBooleanMappedFieldTypeTests extends AbstractNonTextScriptMapp
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testTermQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termQuery(randomBoolean(), ctx));
|
||||
protected Query randomTermQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.termQuery(randomBoolean(), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -329,18 +343,27 @@ public class ScriptBooleanMappedFieldTypeTests extends AbstractNonTextScriptMapp
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testTermsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termsQuery(org.elasticsearch.common.collect.List.of(true), ctx));
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termsQuery(org.elasticsearch.common.collect.List.of(false), ctx));
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termsQuery(org.elasticsearch.common.collect.List.of(false, true), ctx));
|
||||
// This is not an expensive query
|
||||
public void randomTermsQueryDegeneratesIntoMatchNone() throws IOException {
|
||||
assertThat(
|
||||
simpleMappedFieldType().termsQuery(org.elasticsearch.common.collect.List.of(), mockContext()),
|
||||
instanceOf(MatchNoDocsQuery.class)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Query randomTermsQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
switch (randomInt(2)) {
|
||||
case 0:
|
||||
return ft.termsQuery(org.elasticsearch.common.collect.List.of(true), ctx);
|
||||
case 1:
|
||||
return ft.termsQuery(org.elasticsearch.common.collect.List.of(false), ctx);
|
||||
case 2:
|
||||
return ft.termsQuery(org.elasticsearch.common.collect.List.of(false, true), ctx);
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public void testDualingQueries() throws IOException {
|
||||
BooleanFieldMapper ootb = new BooleanFieldMapper.Builder("foo").build(new BuilderContext(Settings.EMPTY, new ContentPath()));
|
||||
try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) {
|
||||
|
@ -419,6 +442,11 @@ public class ScriptBooleanMappedFieldTypeTests extends AbstractNonTextScriptMapp
|
|||
return build("read_foo", org.elasticsearch.common.collect.Map.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MappedFieldType loopFieldType() throws IOException {
|
||||
return build("loop", org.elasticsearch.common.collect.Map.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String runtimeType() {
|
||||
return "boolean";
|
||||
|
@ -485,6 +513,12 @@ public class ScriptBooleanMappedFieldTypeTests extends AbstractNonTextScriptMapp
|
|||
}
|
||||
}
|
||||
};
|
||||
case "loop":
|
||||
return (fieldName, params, lookup) -> {
|
||||
// Indicate that this script wants the field call "test", which *is* the name of this field
|
||||
lookup.forkAndTrackFieldReferences("test");
|
||||
throw new IllegalStateException("shoud have thrown on the line above");
|
||||
};
|
||||
default:
|
||||
throw new IllegalArgumentException("unsupported script [" + code + "]");
|
||||
}
|
||||
|
@ -501,13 +535,4 @@ public class ScriptBooleanMappedFieldTypeTests extends AbstractNonTextScriptMapp
|
|||
return new ScriptBooleanMappedFieldType("test", script, factory, emptyMap());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkExpensiveQuery(BiConsumer<ScriptBooleanMappedFieldType, QueryShardContext> queryBuilder) throws IOException {
|
||||
ScriptBooleanMappedFieldType ft = simpleMappedFieldType();
|
||||
Exception e = expectThrows(ElasticsearchException.class, () -> queryBuilder.accept(ft, mockContext(false)));
|
||||
assertThat(
|
||||
e.getMessage(),
|
||||
equalTo("queries cannot be executed against [runtime] fields while [search.allow_expensive_queries] is set to [false].")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import org.apache.lucene.search.TopDocs;
|
|||
import org.apache.lucene.search.TopFieldDocs;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.lucene.search.function.ScriptScoreQuery;
|
||||
|
@ -59,7 +58,6 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.hamcrest.Matchers.arrayWithSize;
|
||||
|
@ -93,7 +91,7 @@ public class ScriptDateMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
);
|
||||
DateFieldMapper.DateFieldType indexed = new DateFieldMapper.DateFieldType("test", formatter);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
long date = randomLongBetween(0, 3000000000000L); // Maxes out in the year 2065
|
||||
long date = randomDate();
|
||||
assertThat(indexed.docValueFormat(null, null).format(date), equalTo(scripted.docValueFormat(null, null).format(date)));
|
||||
String format = randomDateFormatterPattern();
|
||||
assertThat(indexed.docValueFormat(format, null).format(date), equalTo(scripted.docValueFormat(format, null).format(date)));
|
||||
|
@ -246,7 +244,15 @@ public class ScriptDateMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
|
||||
public void testDistanceFeatureQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.distanceFeatureQuery(randomLong(), randomAlphaOfLength(5), randomFloat(), ctx));
|
||||
checkExpensiveQuery(this::randomDistanceFeatureQuery);
|
||||
}
|
||||
|
||||
public void testDistanceFeatureQueryInLoop() throws IOException {
|
||||
checkLoop(this::randomDistanceFeatureQuery);
|
||||
}
|
||||
|
||||
private Query randomDistanceFeatureQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.distanceFeatureQuery(randomDate(), randomTimeValue(), randomFloat(), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -263,11 +269,6 @@ public class ScriptDateMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testExistsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(ScriptDateMappedFieldType::existsQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testRangeQuery() throws IOException {
|
||||
try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) {
|
||||
|
@ -345,10 +346,15 @@ public class ScriptDateMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testRangeQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(
|
||||
(ft, ctx) -> ft.rangeQuery(randomLong(), randomLong(), randomBoolean(), randomBoolean(), null, null, null, ctx)
|
||||
);
|
||||
protected Query randomRangeQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
long d1 = randomDate();
|
||||
long d2 = randomValueOtherThan(d1, ScriptDateMappedFieldTypeTests::randomDate);
|
||||
if (d1 > d2) {
|
||||
long backup = d2;
|
||||
d2 = d1;
|
||||
d1 = backup;
|
||||
}
|
||||
return ft.rangeQuery(d1, d2, randomBoolean(), randomBoolean(), null, null, null, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -382,8 +388,8 @@ public class ScriptDateMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testTermQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termQuery(0, ctx));
|
||||
protected Query randomTermQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.termQuery(randomDate(), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -448,8 +454,8 @@ public class ScriptDateMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testTermsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termsQuery(org.elasticsearch.common.collect.List.of(0), ctx));
|
||||
protected Query randomTermsQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.termsQuery(randomList(1, 100, ScriptDateMappedFieldTypeTests::randomDate), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -457,6 +463,11 @@ public class ScriptDateMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
return build("read_timestamp");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MappedFieldType loopFieldType() throws IOException {
|
||||
return build("loop");
|
||||
}
|
||||
|
||||
private ScriptDateMappedFieldType coolFormattedFieldType() throws IOException {
|
||||
return build(simpleMappedFieldType().script, DateFormatter.forPattern("yyyy-MM-dd(-■_■)HH:mm:ss.SSSz||epoch_millis"));
|
||||
}
|
||||
|
@ -537,6 +548,12 @@ public class ScriptDateMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
}
|
||||
};
|
||||
case "loop":
|
||||
return (fieldName, params, lookup, formatter) -> {
|
||||
// Indicate that this script wants the field call "test", which *is* the name of this field
|
||||
lookup.forkAndTrackFieldReferences("test");
|
||||
throw new IllegalStateException("shoud have thrown on the line above");
|
||||
};
|
||||
default:
|
||||
throw new IllegalArgumentException("unsupported script [" + code + "]");
|
||||
}
|
||||
|
@ -554,13 +571,8 @@ public class ScriptDateMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
}
|
||||
|
||||
private void checkExpensiveQuery(BiConsumer<ScriptDateMappedFieldType, QueryShardContext> queryBuilder) throws IOException {
|
||||
ScriptDateMappedFieldType ft = simpleMappedFieldType();
|
||||
Exception e = expectThrows(ElasticsearchException.class, () -> queryBuilder.accept(ft, mockContext(false)));
|
||||
assertThat(
|
||||
e.getMessage(),
|
||||
equalTo("queries cannot be executed against [runtime] fields while [search.allow_expensive_queries] is set to [false].")
|
||||
);
|
||||
private static long randomDate() {
|
||||
return Math.abs(randomLong() % (2 * (long) 10e11)); // 1970-01-01T00:00:00Z - 2033-05-18T05:33:20.000+02:00
|
||||
}
|
||||
|
||||
private void checkBadDate(ThrowingRunnable queryBuilder) {
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.apache.lucene.search.Collector;
|
|||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.LeafCollector;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.Scorable;
|
||||
import org.apache.lucene.search.ScoreMode;
|
||||
import org.apache.lucene.search.Sort;
|
||||
|
@ -21,7 +22,6 @@ import org.apache.lucene.search.SortField;
|
|||
import org.apache.lucene.search.TopFieldDocs;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.lucene.search.function.ScriptScoreQuery;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
@ -48,7 +48,6 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
@ -163,10 +162,6 @@ public class ScriptDoubleMappedFieldTypeTests extends AbstractNonTextScriptMappe
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testExistsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(ScriptDoubleMappedFieldType::existsQuery);
|
||||
}
|
||||
|
||||
public void testRangeQuery() throws IOException {
|
||||
try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) {
|
||||
iw.addDocument(org.elasticsearch.common.collect.List.of(new StoredField("_source", new BytesRef("{\"foo\": [1]}"))));
|
||||
|
@ -186,10 +181,9 @@ public class ScriptDoubleMappedFieldTypeTests extends AbstractNonTextScriptMappe
|
|||
}
|
||||
}
|
||||
|
||||
public void testRangeQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(
|
||||
(ft, ctx) -> ft.rangeQuery(randomLong(), randomLong(), randomBoolean(), randomBoolean(), null, null, null, ctx)
|
||||
);
|
||||
@Override
|
||||
protected Query randomRangeQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.rangeQuery(randomLong(), randomLong(), randomBoolean(), randomBoolean(), null, null, null, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -211,8 +205,8 @@ public class ScriptDoubleMappedFieldTypeTests extends AbstractNonTextScriptMappe
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testTermQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termQuery(randomLong(), ctx));
|
||||
protected Query randomTermQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.termQuery(randomLong(), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -247,8 +241,8 @@ public class ScriptDoubleMappedFieldTypeTests extends AbstractNonTextScriptMappe
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testTermsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termsQuery(org.elasticsearch.common.collect.List.of(randomLong()), ctx));
|
||||
protected Query randomTermsQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.termsQuery(org.elasticsearch.common.collect.List.of(randomLong()), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -256,6 +250,11 @@ public class ScriptDoubleMappedFieldTypeTests extends AbstractNonTextScriptMappe
|
|||
return build("read_foo", org.elasticsearch.common.collect.Map.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MappedFieldType loopFieldType() throws IOException {
|
||||
return build("loop", org.elasticsearch.common.collect.Map.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String runtimeType() {
|
||||
return "double";
|
||||
|
@ -312,6 +311,12 @@ public class ScriptDoubleMappedFieldTypeTests extends AbstractNonTextScriptMappe
|
|||
}
|
||||
}
|
||||
};
|
||||
case "loop":
|
||||
return (fieldName, params, lookup) -> {
|
||||
// Indicate that this script wants the field call "test", which *is* the name of this field
|
||||
lookup.forkAndTrackFieldReferences("test");
|
||||
throw new IllegalStateException("shoud have thrown on the line above");
|
||||
};
|
||||
default:
|
||||
throw new IllegalArgumentException("unsupported script [" + code + "]");
|
||||
}
|
||||
|
@ -328,13 +333,4 @@ public class ScriptDoubleMappedFieldTypeTests extends AbstractNonTextScriptMappe
|
|||
return new ScriptDoubleMappedFieldType("test", script, factory, emptyMap());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkExpensiveQuery(BiConsumer<ScriptDoubleMappedFieldType, QueryShardContext> queryBuilder) throws IOException {
|
||||
ScriptDoubleMappedFieldType ft = simpleMappedFieldType();
|
||||
Exception e = expectThrows(ElasticsearchException.class, () -> queryBuilder.accept(ft, mockContext(false)));
|
||||
assertThat(
|
||||
e.getMessage(),
|
||||
equalTo("queries cannot be executed against [runtime] fields while [search.allow_expensive_queries] is set to [false].")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.apache.lucene.search.Collector;
|
|||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.LeafCollector;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.Scorable;
|
||||
import org.apache.lucene.search.ScoreMode;
|
||||
import org.apache.lucene.search.Sort;
|
||||
|
@ -21,11 +22,11 @@ import org.apache.lucene.search.SortField;
|
|||
import org.apache.lucene.search.TopFieldDocs;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.lucene.search.function.ScriptScoreQuery;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.plugins.ScriptPlugin;
|
||||
import org.elasticsearch.script.ScoreScript;
|
||||
|
@ -50,7 +51,6 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
@ -194,11 +194,6 @@ public class ScriptIpMappedFieldTypeTests extends AbstractScriptMappedFieldTypeT
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testExistsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(ScriptIpMappedFieldType::existsQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testRangeQuery() throws IOException {
|
||||
try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) {
|
||||
|
@ -222,8 +217,8 @@ public class ScriptIpMappedFieldTypeTests extends AbstractScriptMappedFieldTypeT
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testRangeQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.rangeQuery("192.0.0.0", "200.0.0.0", randomBoolean(), randomBoolean(), null, null, null, ctx));
|
||||
protected Query randomRangeQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.rangeQuery("192.0.0.0", "200.0.0.0", randomBoolean(), randomBoolean(), null, null, null, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -248,8 +243,8 @@ public class ScriptIpMappedFieldTypeTests extends AbstractScriptMappedFieldTypeT
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testTermQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termQuery(randomIp(randomBoolean()), ctx));
|
||||
protected Query randomTermQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.termQuery(randomIp(randomBoolean()), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -290,8 +285,8 @@ public class ScriptIpMappedFieldTypeTests extends AbstractScriptMappedFieldTypeT
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testTermsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termsQuery(randomList(100, () -> randomAlphaOfLengthBetween(1, 1000)), ctx));
|
||||
protected Query randomTermsQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.termsQuery(randomList(100, () -> randomIp(randomBoolean())), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -299,6 +294,11 @@ public class ScriptIpMappedFieldTypeTests extends AbstractScriptMappedFieldTypeT
|
|||
return build("read_foo", org.elasticsearch.common.collect.Map.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MappedFieldType loopFieldType() throws IOException {
|
||||
return build("loop", org.elasticsearch.common.collect.Map.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String runtimeType() {
|
||||
return "ip";
|
||||
|
@ -355,6 +355,12 @@ public class ScriptIpMappedFieldTypeTests extends AbstractScriptMappedFieldTypeT
|
|||
}
|
||||
}
|
||||
};
|
||||
case "loop":
|
||||
return (fieldName, params, lookup) -> {
|
||||
// Indicate that this script wants the field call "test", which *is* the name of this field
|
||||
lookup.forkAndTrackFieldReferences("test");
|
||||
throw new IllegalStateException("shoud have thrown on the line above");
|
||||
};
|
||||
default:
|
||||
throw new IllegalArgumentException("unsupported script [" + code + "]");
|
||||
}
|
||||
|
@ -371,13 +377,4 @@ public class ScriptIpMappedFieldTypeTests extends AbstractScriptMappedFieldTypeT
|
|||
return new ScriptIpMappedFieldType("test", script, factory, emptyMap());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkExpensiveQuery(BiConsumer<ScriptIpMappedFieldType, QueryShardContext> queryBuilder) throws IOException {
|
||||
ScriptIpMappedFieldType ft = simpleMappedFieldType();
|
||||
Exception e = expectThrows(ElasticsearchException.class, () -> queryBuilder.accept(ft, mockContext(false)));
|
||||
assertThat(
|
||||
e.getMessage(),
|
||||
equalTo("queries cannot be executed against [runtime] fields while [search.allow_expensive_queries] is set to [false].")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,13 +23,13 @@ import org.apache.lucene.search.TopFieldDocs;
|
|||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.apache.lucene.util.automaton.Operations;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.lucene.search.function.ScriptScoreQuery;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.Fuzziness;
|
||||
import org.elasticsearch.index.fielddata.ScriptDocValues;
|
||||
import org.elasticsearch.index.fielddata.SortedBinaryDocValues;
|
||||
import org.elasticsearch.index.mapper.MappedFieldType;
|
||||
import org.elasticsearch.index.query.MatchQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryShardContext;
|
||||
import org.elasticsearch.plugins.ScriptPlugin;
|
||||
|
@ -52,7 +52,6 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
@ -157,11 +156,6 @@ public class ScriptKeywordMappedFieldTypeTests extends AbstractScriptMappedField
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testExistsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(ScriptKeywordMappedFieldType::existsQuery);
|
||||
}
|
||||
|
||||
public void testFuzzyQuery() throws IOException {
|
||||
try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) {
|
||||
// No edits, matches
|
||||
|
@ -185,15 +179,21 @@ public class ScriptKeywordMappedFieldTypeTests extends AbstractScriptMappedField
|
|||
}
|
||||
|
||||
public void testFuzzyQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(
|
||||
(ft, ctx) -> ft.fuzzyQuery(
|
||||
checkExpensiveQuery(this::randomFuzzyQuery);
|
||||
}
|
||||
|
||||
public void testFuzzyQueryInLoop() throws IOException {
|
||||
checkLoop(this::randomFuzzyQuery);
|
||||
}
|
||||
|
||||
private Query randomFuzzyQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.fuzzyQuery(
|
||||
randomAlphaOfLengthBetween(1, 1000),
|
||||
randomFrom(Fuzziness.AUTO, Fuzziness.ZERO, Fuzziness.ONE, Fuzziness.TWO),
|
||||
randomInt(),
|
||||
randomInt(),
|
||||
randomBoolean(),
|
||||
ctx
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -210,7 +210,15 @@ public class ScriptKeywordMappedFieldTypeTests extends AbstractScriptMappedField
|
|||
}
|
||||
|
||||
public void testPrefixQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.prefixQuery(randomAlphaOfLengthBetween(1, 1000), null, ctx));
|
||||
checkExpensiveQuery(this::randomPrefixQuery);
|
||||
}
|
||||
|
||||
public void testPrefixQueryInLoop() throws IOException {
|
||||
checkLoop(this::randomPrefixQuery);
|
||||
}
|
||||
|
||||
private Query randomPrefixQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.prefixQuery(randomAlphaOfLengthBetween(1, 1000), null, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -230,18 +238,16 @@ public class ScriptKeywordMappedFieldTypeTests extends AbstractScriptMappedField
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testRangeQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(
|
||||
(ft, ctx) -> ft.rangeQuery(
|
||||
"a" + randomAlphaOfLengthBetween(0, 1000),
|
||||
"b" + randomAlphaOfLengthBetween(0, 1000),
|
||||
protected Query randomRangeQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.rangeQuery(
|
||||
randomAlphaOfLengthBetween(0, 1000),
|
||||
randomAlphaOfLengthBetween(0, 1000),
|
||||
randomBoolean(),
|
||||
randomBoolean(),
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
ctx
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -262,8 +268,12 @@ public class ScriptKeywordMappedFieldTypeTests extends AbstractScriptMappedField
|
|||
}
|
||||
}
|
||||
|
||||
public void testRegexpQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.regexpQuery(randomAlphaOfLengthBetween(1, 1000), randomInt(0xFFFF), 0, randomInt(), null, ctx));
|
||||
public void testRegexpQueryInLoop() throws IOException {
|
||||
checkLoop(this::randomRegexpQuery);
|
||||
}
|
||||
|
||||
private Query randomRegexpQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.regexpQuery(randomAlphaOfLengthBetween(1, 1000), randomInt(0xFFFF), 0, Integer.MAX_VALUE, null, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -280,8 +290,8 @@ public class ScriptKeywordMappedFieldTypeTests extends AbstractScriptMappedField
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testTermQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termQuery(randomAlphaOfLengthBetween(1, 1000), ctx));
|
||||
protected Query randomTermQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.termQuery(randomAlphaOfLengthBetween(1, 1000), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -302,8 +312,8 @@ public class ScriptKeywordMappedFieldTypeTests extends AbstractScriptMappedField
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testTermsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termsQuery(randomList(100, () -> randomAlphaOfLengthBetween(1, 1000)), ctx));
|
||||
protected Query randomTermsQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.termsQuery(randomList(100, () -> randomAlphaOfLengthBetween(1, 1000)), ctx);
|
||||
}
|
||||
|
||||
public void testWildcardQuery() throws IOException {
|
||||
|
@ -318,7 +328,15 @@ public class ScriptKeywordMappedFieldTypeTests extends AbstractScriptMappedField
|
|||
}
|
||||
|
||||
public void testWildcardQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.wildcardQuery(randomAlphaOfLengthBetween(1, 1000), null, ctx));
|
||||
checkExpensiveQuery(this::randomWildcardQuery);
|
||||
}
|
||||
|
||||
public void testWildcardQueryInLoop() throws IOException {
|
||||
checkLoop(this::randomWildcardQuery);
|
||||
}
|
||||
|
||||
private Query randomWildcardQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.wildcardQuery(randomAlphaOfLengthBetween(1, 1000), null, ctx);
|
||||
}
|
||||
|
||||
public void testMatchQuery() throws IOException {
|
||||
|
@ -340,6 +358,11 @@ public class ScriptKeywordMappedFieldTypeTests extends AbstractScriptMappedField
|
|||
return build("read_foo", org.elasticsearch.common.collect.Map.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptKeywordMappedFieldType loopFieldType() throws IOException {
|
||||
return build("loop", org.elasticsearch.common.collect.Map.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String runtimeType() {
|
||||
return "keyword";
|
||||
|
@ -396,6 +419,12 @@ public class ScriptKeywordMappedFieldTypeTests extends AbstractScriptMappedField
|
|||
}
|
||||
}
|
||||
};
|
||||
case "loop":
|
||||
return (fieldName, params, lookup) -> {
|
||||
// Indicate that this script wants the field call "test", which *is* the name of this field
|
||||
lookup.forkAndTrackFieldReferences("test");
|
||||
throw new IllegalStateException("shoud have thrown on the line above");
|
||||
};
|
||||
default:
|
||||
throw new IllegalArgumentException("unsupported script [" + code + "]");
|
||||
}
|
||||
|
@ -412,13 +441,4 @@ public class ScriptKeywordMappedFieldTypeTests extends AbstractScriptMappedField
|
|||
return new ScriptKeywordMappedFieldType("test", script, factory, emptyMap());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkExpensiveQuery(BiConsumer<ScriptKeywordMappedFieldType, QueryShardContext> queryBuilder) throws IOException {
|
||||
ScriptKeywordMappedFieldType ft = simpleMappedFieldType();
|
||||
Exception e = expectThrows(ElasticsearchException.class, () -> queryBuilder.accept(ft, mockContext(false)));
|
||||
assertThat(
|
||||
e.getMessage(),
|
||||
equalTo("queries cannot be executed against [runtime] fields while [search.allow_expensive_queries] is set to [false].")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.apache.lucene.search.FieldDoc;
|
|||
import org.apache.lucene.search.IndexSearcher;
|
||||
import org.apache.lucene.search.LeafCollector;
|
||||
import org.apache.lucene.search.MatchAllDocsQuery;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.search.Scorable;
|
||||
import org.apache.lucene.search.ScoreMode;
|
||||
import org.apache.lucene.search.Sort;
|
||||
|
@ -23,7 +24,6 @@ import org.apache.lucene.search.SortField;
|
|||
import org.apache.lucene.search.TopFieldDocs;
|
||||
import org.apache.lucene.store.Directory;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.lucene.search.function.ScriptScoreQuery;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
|
@ -50,7 +50,6 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
|
@ -192,11 +191,6 @@ public class ScriptLongMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testExistsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(ScriptLongMappedFieldType::existsQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testRangeQuery() throws IOException {
|
||||
try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) {
|
||||
|
@ -215,10 +209,8 @@ public class ScriptLongMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testRangeQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery(
|
||||
(ft, ctx) -> ft.rangeQuery(randomLong(), randomLong(), randomBoolean(), randomBoolean(), null, null, null, ctx)
|
||||
);
|
||||
protected Query randomRangeQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.rangeQuery(randomLong(), randomLong(), randomBoolean(), randomBoolean(), null, null, null, ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -240,8 +232,8 @@ public class ScriptLongMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testTermQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termQuery(randomLong(), ctx));
|
||||
protected Query randomTermQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.termQuery(randomLong(), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -276,8 +268,8 @@ public class ScriptLongMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
|
||||
@Override
|
||||
public void testTermsQueryIsExpensive() throws IOException {
|
||||
checkExpensiveQuery((ft, ctx) -> ft.termsQuery(org.elasticsearch.common.collect.List.of(randomLong()), ctx));
|
||||
protected Query randomTermsQuery(MappedFieldType ft, QueryShardContext ctx) {
|
||||
return ft.termsQuery(org.elasticsearch.common.collect.List.of(randomLong()), ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -285,6 +277,11 @@ public class ScriptLongMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
return build("read_foo", Collections.emptyMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptLongMappedFieldType loopFieldType() throws IOException {
|
||||
return build("loop", org.elasticsearch.common.collect.Map.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String runtimeType() {
|
||||
return "long";
|
||||
|
@ -352,6 +349,12 @@ public class ScriptLongMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
}
|
||||
}
|
||||
};
|
||||
case "loop":
|
||||
return (fieldName, params, lookup) -> {
|
||||
// Indicate that this script wants the field call "test", which *is* the name of this field
|
||||
lookup.forkAndTrackFieldReferences("test");
|
||||
throw new IllegalStateException("shoud have thrown on the line above");
|
||||
};
|
||||
default:
|
||||
throw new IllegalArgumentException("unsupported script [" + code + "]");
|
||||
}
|
||||
|
@ -368,13 +371,4 @@ public class ScriptLongMappedFieldTypeTests extends AbstractNonTextScriptMappedF
|
|||
return new ScriptLongMappedFieldType("test", script, factory, emptyMap());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkExpensiveQuery(BiConsumer<ScriptLongMappedFieldType, QueryShardContext> queryBuilder) throws IOException {
|
||||
ScriptLongMappedFieldType ft = simpleMappedFieldType();
|
||||
Exception e = expectThrows(ElasticsearchException.class, () -> queryBuilder.accept(ft, mockContext(false)));
|
||||
assertThat(
|
||||
e.getMessage(),
|
||||
equalTo("queries cannot be executed against [runtime] fields while [search.allow_expensive_queries] is set to [false].")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ setup:
|
|||
body:
|
||||
sort: timestamp
|
||||
docvalue_fields: [tight_loop]
|
||||
|
||||
---
|
||||
"tight loop - aggs":
|
||||
- do:
|
||||
|
@ -94,6 +95,7 @@ setup:
|
|||
loop:
|
||||
terms:
|
||||
field: tight_loop
|
||||
|
||||
---
|
||||
"tight loop - sort":
|
||||
- do:
|
||||
|
@ -103,6 +105,17 @@ setup:
|
|||
body:
|
||||
sort: tight_loop
|
||||
|
||||
---
|
||||
"tight loop - queries":
|
||||
- do:
|
||||
catch: '/Cyclic dependency detected while resolving runtime fields: tight_loop -> tight_loop/'
|
||||
search:
|
||||
index: sensor
|
||||
body:
|
||||
query:
|
||||
match:
|
||||
tight_loop: foo
|
||||
|
||||
---
|
||||
"loose loop - aggs":
|
||||
- do:
|
||||
|
@ -134,6 +147,17 @@ setup:
|
|||
sort: timestamp
|
||||
docvalue_fields: [loose_loop]
|
||||
|
||||
---
|
||||
"loose loop - queries":
|
||||
- do:
|
||||
catch: '/Cyclic dependency detected while resolving runtime fields: loose_loop -> lla -> llb -> llc -> loose_loop/'
|
||||
search:
|
||||
index: sensor
|
||||
body:
|
||||
query:
|
||||
match:
|
||||
loose_loop: foo
|
||||
|
||||
---
|
||||
"loose loop - begins within":
|
||||
- do:
|
||||
|
@ -148,7 +172,7 @@ setup:
|
|||
field: lla
|
||||
|
||||
---
|
||||
"Max chain depth - 5 is allowed":
|
||||
"Max chain depth for fetch - 5 is allowed":
|
||||
- do:
|
||||
search:
|
||||
index: sensor
|
||||
|
@ -159,6 +183,17 @@ setup:
|
|||
- match: {hits.total.value: 1}
|
||||
- match: {hits.hits.0.fields.over_max_depth_1.0: test}
|
||||
|
||||
---
|
||||
"Max chain depth for query - 5 is allowed":
|
||||
- do:
|
||||
search:
|
||||
index: sensor
|
||||
body:
|
||||
query:
|
||||
match:
|
||||
over_max_depth_1: test
|
||||
- match: {hits.total.value: 1}
|
||||
|
||||
---
|
||||
"Max chain depth - direct references are not counted":
|
||||
- do:
|
||||
|
@ -183,6 +218,7 @@ setup:
|
|||
loop:
|
||||
terms:
|
||||
field: over_max_depth
|
||||
|
||||
---
|
||||
"Max chain depth - sort":
|
||||
- do:
|
||||
|
@ -191,6 +227,7 @@ setup:
|
|||
index: sensor
|
||||
body:
|
||||
sort: over_max_depth
|
||||
|
||||
---
|
||||
"Max chain depth - docvalue_fields":
|
||||
- do:
|
||||
|
@ -200,3 +237,14 @@ setup:
|
|||
body:
|
||||
sort: timestamp
|
||||
docvalue_fields: [over_max_depth]
|
||||
|
||||
---
|
||||
"Max chain depth - query":
|
||||
- do:
|
||||
catch: '/Field requires resolving too many dependent fields: over_max_depth -> over_max_depth_1 -> over_max_depth_2 -> over_max_depth_3 -> over_max_depth_4 -> over_max_depth_5/'
|
||||
search:
|
||||
index: sensor
|
||||
body:
|
||||
query:
|
||||
match:
|
||||
over_max_depth: foo
|
||||
|
|
Loading…
Reference in New Issue