mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-24 17:09:48 +00:00
Cache results from queries that use scripts if they use only deterministic API calls. Nondeterministic API calls are marked in the whitelist with the `@nondeterministic` annotation. Examples are `Math.random()` and `new Date()`. Refs: #49466
This commit is contained in:
parent
246d926412
commit
06a24f09cf
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.painless.spi.annotation;
|
||||
|
||||
public class NonDeterministicAnnotation {
|
||||
|
||||
public static final String NAME = "nondeterministic";
|
||||
|
||||
public static final NonDeterministicAnnotation INSTANCE = new NonDeterministicAnnotation();
|
||||
|
||||
private NonDeterministicAnnotation() {}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.painless.spi.annotation;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class NonDeterministicAnnotationParser implements WhitelistAnnotationParser {
|
||||
|
||||
public static final NonDeterministicAnnotationParser INSTANCE = new NonDeterministicAnnotationParser();
|
||||
|
||||
private NonDeterministicAnnotationParser() {}
|
||||
|
||||
@Override
|
||||
public Object parse(Map<String, String> arguments) {
|
||||
if (arguments.isEmpty() == false) {
|
||||
throw new IllegalArgumentException(
|
||||
"unexpected parameters for [@" + NonDeterministicAnnotation.NAME + "] annotation, found " + arguments
|
||||
);
|
||||
}
|
||||
|
||||
return NonDeterministicAnnotation.INSTANCE;
|
||||
}
|
||||
}
|
@ -34,7 +34,8 @@ public interface WhitelistAnnotationParser {
|
||||
Map<String, WhitelistAnnotationParser> BASE_ANNOTATION_PARSERS = Collections.unmodifiableMap(
|
||||
Stream.of(
|
||||
new AbstractMap.SimpleEntry<>(NoImportAnnotation.NAME, NoImportAnnotationParser.INSTANCE),
|
||||
new AbstractMap.SimpleEntry<>(DeprecatedAnnotation.NAME, DeprecatedAnnotationParser.INSTANCE)
|
||||
new AbstractMap.SimpleEntry<>(DeprecatedAnnotation.NAME, DeprecatedAnnotationParser.INSTANCE),
|
||||
new AbstractMap.SimpleEntry<>(NonDeterministicAnnotation.NAME, NonDeterministicAnnotationParser.INSTANCE)
|
||||
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))
|
||||
);
|
||||
|
||||
|
@ -26,7 +26,6 @@ import org.elasticsearch.painless.node.SClass;
|
||||
import org.elasticsearch.painless.spi.Whitelist;
|
||||
import org.objectweb.asm.util.Printer;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
@ -205,13 +204,14 @@ final class Compiler {
|
||||
* @param name The name of the script.
|
||||
* @param source The source code for the script.
|
||||
* @param settings The CompilerSettings to be used during the compilation.
|
||||
* @return An executable script that implements both a specified interface and is a subclass of {@link PainlessScript}
|
||||
* @return The ScriptRoot used to compile
|
||||
*/
|
||||
Constructor<?> compile(Loader loader, Set<String> extractedVariables, String name, String source, CompilerSettings settings) {
|
||||
ScriptRoot compile(Loader loader, Set<String> extractedVariables, String name, String source,
|
||||
CompilerSettings settings) {
|
||||
ScriptClassInfo scriptClassInfo = new ScriptClassInfo(painlessLookup, scriptClass);
|
||||
SClass root = Walker.buildPainlessTree(scriptClassInfo, name, source, settings, painlessLookup, null);
|
||||
root.extractVariables(extractedVariables);
|
||||
root.analyze(painlessLookup, settings);
|
||||
ScriptRoot scriptRoot = root.analyze(painlessLookup, settings);
|
||||
Map<String, Object> statics = root.write();
|
||||
|
||||
try {
|
||||
@ -225,8 +225,9 @@ final class Compiler {
|
||||
clazz.getField(statik.getKey()).set(null, statik.getValue());
|
||||
}
|
||||
|
||||
return clazz.getConstructors()[0];
|
||||
} catch (Exception exception) { // Catch everything to let the user know this is something caused internally.
|
||||
return scriptRoot;
|
||||
} catch (Exception exception) {
|
||||
// Catch everything to let the user know this is something caused internally.
|
||||
throw new IllegalStateException("An internal error occurred attempting to define the script [" + name + "].", exception);
|
||||
}
|
||||
}
|
||||
|
@ -143,12 +143,13 @@ public final class PainlessScriptEngine implements ScriptEngine {
|
||||
});
|
||||
|
||||
Set<String> extractedVariables = new HashSet<>();
|
||||
compile(contextsToCompilers.get(context), loader, extractedVariables, scriptName, scriptSource, params);
|
||||
ScriptRoot scriptRoot = compile(contextsToCompilers.get(context), loader, extractedVariables, scriptName, scriptSource, params);
|
||||
|
||||
if (context.statefulFactoryClazz != null) {
|
||||
return generateFactory(loader, context, extractedVariables, generateStatefulFactory(loader, context, extractedVariables));
|
||||
return generateFactory(loader, context, extractedVariables, generateStatefulFactory(loader, context, extractedVariables),
|
||||
scriptRoot);
|
||||
} else {
|
||||
return generateFactory(loader, context, extractedVariables, WriterConstants.CLASS_TYPE);
|
||||
return generateFactory(loader, context, extractedVariables, WriterConstants.CLASS_TYPE, scriptRoot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,6 +271,7 @@ public final class PainlessScriptEngine implements ScriptEngine {
|
||||
* @param context The {@link ScriptContext}'s semantics are used to define the factory class.
|
||||
* @param classType The type to be instaniated in the newFactory or newInstance method. Depends
|
||||
* on whether a {@link ScriptContext#statefulFactoryClazz} is specified.
|
||||
* @param scriptRoot the {@link ScriptRoot} used to do the compilation
|
||||
* @param <T> The factory class.
|
||||
* @return A factory class that will return script instances.
|
||||
*/
|
||||
@ -277,7 +279,8 @@ public final class PainlessScriptEngine implements ScriptEngine {
|
||||
Loader loader,
|
||||
ScriptContext<T> context,
|
||||
Set<String> extractedVariables,
|
||||
Type classType
|
||||
Type classType,
|
||||
ScriptRoot scriptRoot
|
||||
) {
|
||||
int classFrames = ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS;
|
||||
int classAccess = Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER| Opcodes.ACC_FINAL;
|
||||
@ -330,8 +333,19 @@ public final class PainlessScriptEngine implements ScriptEngine {
|
||||
adapter.endMethod();
|
||||
|
||||
writeNeedsMethods(context.factoryClazz, writer, extractedVariables);
|
||||
writer.visitEnd();
|
||||
|
||||
String methodName = "isResultDeterministic";
|
||||
org.objectweb.asm.commons.Method isResultDeterministic = new org.objectweb.asm.commons.Method(methodName,
|
||||
MethodType.methodType(boolean.class).toMethodDescriptorString());
|
||||
|
||||
GeneratorAdapter deterAdapter = new GeneratorAdapter(Opcodes.ASM5, isResultDeterministic,
|
||||
writer.visitMethod(Opcodes.ACC_PUBLIC, methodName, isResultDeterministic.getDescriptor(), null, null));
|
||||
deterAdapter.visitCode();
|
||||
deterAdapter.push(scriptRoot.deterministic);
|
||||
deterAdapter.returnValue();
|
||||
deterAdapter.endMethod();
|
||||
|
||||
writer.visitEnd();
|
||||
Class<?> factory = loader.defineFactory(className.replace('/', '.'), writer.toByteArray());
|
||||
|
||||
try {
|
||||
@ -363,19 +377,17 @@ public final class PainlessScriptEngine implements ScriptEngine {
|
||||
}
|
||||
}
|
||||
|
||||
void compile(Compiler compiler, Loader loader, Set<String> extractedVariables,
|
||||
ScriptRoot compile(Compiler compiler, Loader loader, Set<String> extractedVariables,
|
||||
String scriptName, String source, Map<String, String> params) {
|
||||
final CompilerSettings compilerSettings = buildCompilerSettings(params);
|
||||
|
||||
try {
|
||||
// Drop all permissions to actually compile the code itself.
|
||||
AccessController.doPrivileged(new PrivilegedAction<Void>() {
|
||||
return AccessController.doPrivileged(new PrivilegedAction<ScriptRoot>() {
|
||||
@Override
|
||||
public Void run() {
|
||||
public ScriptRoot run() {
|
||||
String name = scriptName == null ? source : scriptName;
|
||||
compiler.compile(loader, extractedVariables, name, source, compilerSettings);
|
||||
|
||||
return null;
|
||||
return compiler.compile(loader, extractedVariables, name, source, compilerSettings);
|
||||
}
|
||||
}, COMPILATION_CONTEXT);
|
||||
// Note that it is safe to catch any of the following errors since Painless is stateless.
|
||||
|
@ -38,6 +38,7 @@ public class ScriptRoot {
|
||||
|
||||
protected final FunctionTable functionTable = new FunctionTable();
|
||||
protected int syntheticCounter = 0;
|
||||
protected boolean deterministic = true;
|
||||
|
||||
public ScriptRoot(PainlessLookup painlessLookup, CompilerSettings compilerSettings, ScriptClassInfo scriptClassInfo, SClass classRoot) {
|
||||
this.painlessLookup = Objects.requireNonNull(painlessLookup);
|
||||
@ -72,4 +73,6 @@ public class ScriptRoot {
|
||||
public String getNextSyntheticName(String prefix) {
|
||||
return prefix + "$synthetic$" + syntheticCounter++;
|
||||
}
|
||||
|
||||
public void markNonDeterministic(boolean nondeterministic) { this.deterministic &= !nondeterministic; }
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ package org.elasticsearch.painless.lookup;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class PainlessClassBinding {
|
||||
@ -31,13 +32,16 @@ public class PainlessClassBinding {
|
||||
|
||||
public final Class<?> returnType;
|
||||
public final List<Class<?>> typeParameters;
|
||||
public final Map<Class<?>, Object> annotations;
|
||||
|
||||
PainlessClassBinding(Constructor<?> javaConstructor, Method javaMethod, Class<?> returnType, List<Class<?>> typeParameters) {
|
||||
PainlessClassBinding(Constructor<?> javaConstructor, Method javaMethod, Class<?> returnType, List<Class<?>> typeParameters,
|
||||
Map<Class<?>, Object> annotations) {
|
||||
this.javaConstructor = javaConstructor;
|
||||
this.javaMethod = javaMethod;
|
||||
|
||||
this.returnType = returnType;
|
||||
this.typeParameters = typeParameters;
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -23,6 +23,7 @@ import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class PainlessConstructor {
|
||||
@ -31,12 +32,15 @@ public class PainlessConstructor {
|
||||
public final List<Class<?>> typeParameters;
|
||||
public final MethodHandle methodHandle;
|
||||
public final MethodType methodType;
|
||||
public final Map<Class<?>, Object> annotations;
|
||||
|
||||
PainlessConstructor(Constructor<?> javaConstructor, List<Class<?>> typeParameters, MethodHandle methodHandle, MethodType methodType) {
|
||||
PainlessConstructor(Constructor<?> javaConstructor, List<Class<?>> typeParameters, MethodHandle methodHandle, MethodType methodType,
|
||||
Map<Class<?>, Object> annotations) {
|
||||
this.javaConstructor = javaConstructor;
|
||||
this.typeParameters = typeParameters;
|
||||
this.methodHandle = methodHandle;
|
||||
this.methodType = methodType;
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,11 +57,12 @@ public class PainlessConstructor {
|
||||
|
||||
return Objects.equals(javaConstructor, that.javaConstructor) &&
|
||||
Objects.equals(typeParameters, that.typeParameters) &&
|
||||
Objects.equals(methodType, that.methodType);
|
||||
Objects.equals(methodType, that.methodType) &&
|
||||
Objects.equals(annotations, that.annotations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(javaConstructor, typeParameters, methodType);
|
||||
return Objects.hash(javaConstructor, typeParameters, methodType, annotations);
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ import java.security.PrivilegedAction;
|
||||
import java.security.SecureClassLoader;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -132,7 +133,8 @@ public final class PainlessLookupBuilder {
|
||||
for (WhitelistConstructor whitelistConstructor : whitelistClass.whitelistConstructors) {
|
||||
origin = whitelistConstructor.origin;
|
||||
painlessLookupBuilder.addPainlessConstructor(
|
||||
targetCanonicalClassName, whitelistConstructor.canonicalTypeNameParameters);
|
||||
targetCanonicalClassName, whitelistConstructor.canonicalTypeNameParameters,
|
||||
whitelistConstructor.painlessAnnotations);
|
||||
}
|
||||
|
||||
for (WhitelistMethod whitelistMethod : whitelistClass.whitelistMethods) {
|
||||
@ -140,7 +142,7 @@ public final class PainlessLookupBuilder {
|
||||
painlessLookupBuilder.addPainlessMethod(
|
||||
whitelist.classLoader, targetCanonicalClassName, whitelistMethod.augmentedCanonicalClassName,
|
||||
whitelistMethod.methodName, whitelistMethod.returnCanonicalTypeName,
|
||||
whitelistMethod.canonicalTypeNameParameters);
|
||||
whitelistMethod.canonicalTypeNameParameters, whitelistMethod.painlessAnnotations);
|
||||
}
|
||||
|
||||
for (WhitelistField whitelistField : whitelistClass.whitelistFields) {
|
||||
@ -155,14 +157,16 @@ public final class PainlessLookupBuilder {
|
||||
painlessLookupBuilder.addImportedPainlessMethod(
|
||||
whitelist.classLoader, whitelistStatic.augmentedCanonicalClassName,
|
||||
whitelistStatic.methodName, whitelistStatic.returnCanonicalTypeName,
|
||||
whitelistStatic.canonicalTypeNameParameters);
|
||||
whitelistStatic.canonicalTypeNameParameters,
|
||||
whitelistStatic.painlessAnnotations);
|
||||
}
|
||||
|
||||
for (WhitelistClassBinding whitelistClassBinding : whitelist.whitelistClassBindings) {
|
||||
origin = whitelistClassBinding.origin;
|
||||
painlessLookupBuilder.addPainlessClassBinding(
|
||||
whitelist.classLoader, whitelistClassBinding.targetJavaClassName, whitelistClassBinding.methodName,
|
||||
whitelistClassBinding.returnCanonicalTypeName, whitelistClassBinding.canonicalTypeNameParameters);
|
||||
whitelistClassBinding.returnCanonicalTypeName, whitelistClassBinding.canonicalTypeNameParameters,
|
||||
whitelistClassBinding.painlessAnnotations);
|
||||
}
|
||||
|
||||
for (WhitelistInstanceBinding whitelistInstanceBinding : whitelist.whitelistInstanceBindings) {
|
||||
@ -313,7 +317,8 @@ public final class PainlessLookupBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
public void addPainlessConstructor(String targetCanonicalClassName, List<String> canonicalTypeNameParameters) {
|
||||
public void addPainlessConstructor(String targetCanonicalClassName, List<String> canonicalTypeNameParameters,
|
||||
Map<Class<?>, Object> annotations) {
|
||||
Objects.requireNonNull(targetCanonicalClassName);
|
||||
Objects.requireNonNull(canonicalTypeNameParameters);
|
||||
|
||||
@ -337,10 +342,10 @@ public final class PainlessLookupBuilder {
|
||||
typeParameters.add(typeParameter);
|
||||
}
|
||||
|
||||
addPainlessConstructor(targetClass, typeParameters);
|
||||
addPainlessConstructor(targetClass, typeParameters, annotations);
|
||||
}
|
||||
|
||||
public void addPainlessConstructor(Class<?> targetClass, List<Class<?>> typeParameters) {
|
||||
public void addPainlessConstructor(Class<?> targetClass, List<Class<?>> typeParameters, Map<Class<?>, Object> annotations) {
|
||||
Objects.requireNonNull(targetClass);
|
||||
Objects.requireNonNull(typeParameters);
|
||||
|
||||
@ -390,7 +395,8 @@ public final class PainlessLookupBuilder {
|
||||
|
||||
String painlessConstructorKey = buildPainlessConstructorKey(typeParametersSize);
|
||||
PainlessConstructor existingPainlessConstructor = painlessClassBuilder.constructors.get(painlessConstructorKey);
|
||||
PainlessConstructor newPainlessConstructor = new PainlessConstructor(javaConstructor, typeParameters, methodHandle, methodType);
|
||||
PainlessConstructor newPainlessConstructor = new PainlessConstructor(javaConstructor, typeParameters, methodHandle, methodType,
|
||||
annotations);
|
||||
|
||||
if (existingPainlessConstructor == null) {
|
||||
newPainlessConstructor = painlessConstructorCache.computeIfAbsent(newPainlessConstructor, key -> key);
|
||||
@ -403,7 +409,8 @@ public final class PainlessLookupBuilder {
|
||||
}
|
||||
|
||||
public void addPainlessMethod(ClassLoader classLoader, String targetCanonicalClassName, String augmentedCanonicalClassName,
|
||||
String methodName, String returnCanonicalTypeName, List<String> canonicalTypeNameParameters) {
|
||||
String methodName, String returnCanonicalTypeName, List<String> canonicalTypeNameParameters,
|
||||
Map<Class<?>, Object> annotations) {
|
||||
|
||||
Objects.requireNonNull(classLoader);
|
||||
Objects.requireNonNull(targetCanonicalClassName);
|
||||
@ -449,11 +456,11 @@ public final class PainlessLookupBuilder {
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + canonicalTypeNameParameters + "]");
|
||||
}
|
||||
|
||||
addPainlessMethod(targetClass, augmentedClass, methodName, returnType, typeParameters);
|
||||
addPainlessMethod(targetClass, augmentedClass, methodName, returnType, typeParameters, annotations);
|
||||
}
|
||||
|
||||
public void addPainlessMethod(Class<?> targetClass, Class<?> augmentedClass,
|
||||
String methodName, Class<?> returnType, List<Class<?>> typeParameters) {
|
||||
String methodName, Class<?> returnType, List<Class<?>> typeParameters, Map<Class<?>, Object> annotations) {
|
||||
|
||||
Objects.requireNonNull(targetClass);
|
||||
Objects.requireNonNull(methodName);
|
||||
@ -562,7 +569,7 @@ public final class PainlessLookupBuilder {
|
||||
painlessClassBuilder.staticMethods.get(painlessMethodKey) :
|
||||
painlessClassBuilder.methods.get(painlessMethodKey);
|
||||
PainlessMethod newPainlessMethod =
|
||||
new PainlessMethod(javaMethod, targetClass, returnType, typeParameters, methodHandle, methodType);
|
||||
new PainlessMethod(javaMethod, targetClass, returnType, typeParameters, methodHandle, methodType, annotations);
|
||||
|
||||
if (existingPainlessMethod == null) {
|
||||
newPainlessMethod = painlessMethodCache.computeIfAbsent(newPainlessMethod, key -> key);
|
||||
@ -708,7 +715,8 @@ public final class PainlessLookupBuilder {
|
||||
}
|
||||
|
||||
public void addImportedPainlessMethod(ClassLoader classLoader, String targetJavaClassName,
|
||||
String methodName, String returnCanonicalTypeName, List<String> canonicalTypeNameParameters) {
|
||||
String methodName, String returnCanonicalTypeName, List<String> canonicalTypeNameParameters,
|
||||
Map<Class<?>, Object> annotations) {
|
||||
|
||||
Objects.requireNonNull(classLoader);
|
||||
Objects.requireNonNull(targetJavaClassName);
|
||||
@ -751,10 +759,11 @@ public final class PainlessLookupBuilder {
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + canonicalTypeNameParameters + "]");
|
||||
}
|
||||
|
||||
addImportedPainlessMethod(targetClass, methodName, returnType, typeParameters);
|
||||
addImportedPainlessMethod(targetClass, methodName, returnType, typeParameters, annotations);
|
||||
}
|
||||
|
||||
public void addImportedPainlessMethod(Class<?> targetClass, String methodName, Class<?> returnType, List<Class<?>> typeParameters) {
|
||||
public void addImportedPainlessMethod(Class<?> targetClass, String methodName, Class<?> returnType, List<Class<?>> typeParameters,
|
||||
Map<Class<?>, Object> annotations) {
|
||||
Objects.requireNonNull(targetClass);
|
||||
Objects.requireNonNull(methodName);
|
||||
Objects.requireNonNull(returnType);
|
||||
@ -841,7 +850,7 @@ public final class PainlessLookupBuilder {
|
||||
|
||||
PainlessMethod existingImportedPainlessMethod = painlessMethodKeysToImportedPainlessMethods.get(painlessMethodKey);
|
||||
PainlessMethod newImportedPainlessMethod =
|
||||
new PainlessMethod(javaMethod, targetClass, returnType, typeParameters, methodHandle, methodType);
|
||||
new PainlessMethod(javaMethod, targetClass, returnType, typeParameters, methodHandle, methodType, annotations);
|
||||
|
||||
if (existingImportedPainlessMethod == null) {
|
||||
newImportedPainlessMethod = painlessMethodCache.computeIfAbsent(newImportedPainlessMethod, key -> key);
|
||||
@ -859,7 +868,8 @@ public final class PainlessLookupBuilder {
|
||||
}
|
||||
|
||||
public void addPainlessClassBinding(ClassLoader classLoader, String targetJavaClassName,
|
||||
String methodName, String returnCanonicalTypeName, List<String> canonicalTypeNameParameters) {
|
||||
String methodName, String returnCanonicalTypeName, List<String> canonicalTypeNameParameters,
|
||||
Map<Class<?>, Object> annotations) {
|
||||
|
||||
Objects.requireNonNull(classLoader);
|
||||
Objects.requireNonNull(targetJavaClassName);
|
||||
@ -896,10 +906,11 @@ public final class PainlessLookupBuilder {
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + canonicalTypeNameParameters + "]");
|
||||
}
|
||||
|
||||
addPainlessClassBinding(targetClass, methodName, returnType, typeParameters);
|
||||
addPainlessClassBinding(targetClass, methodName, returnType, typeParameters, annotations);
|
||||
}
|
||||
|
||||
public void addPainlessClassBinding(Class<?> targetClass, String methodName, Class<?> returnType, List<Class<?>> typeParameters) {
|
||||
public void addPainlessClassBinding(Class<?> targetClass, String methodName, Class<?> returnType, List<Class<?>> typeParameters,
|
||||
Map<Class<?>, Object> annotations) {
|
||||
Objects.requireNonNull(targetClass);
|
||||
Objects.requireNonNull(methodName);
|
||||
Objects.requireNonNull(returnType);
|
||||
@ -1036,7 +1047,7 @@ public final class PainlessLookupBuilder {
|
||||
|
||||
PainlessClassBinding existingPainlessClassBinding = painlessMethodKeysToPainlessClassBindings.get(painlessMethodKey);
|
||||
PainlessClassBinding newPainlessClassBinding =
|
||||
new PainlessClassBinding(javaConstructor, javaMethod, returnType, typeParameters);
|
||||
new PainlessClassBinding(javaConstructor, javaMethod, returnType, typeParameters, annotations);
|
||||
|
||||
if (existingPainlessClassBinding == null) {
|
||||
newPainlessClassBinding = painlessClassBindingCache.computeIfAbsent(newPainlessClassBinding, key -> key);
|
||||
@ -1444,7 +1455,7 @@ public final class PainlessLookupBuilder {
|
||||
painlessMethod.javaMethod.getName(), bridgeTypeParameters.toArray(new Class<?>[0]));
|
||||
MethodHandle bridgeHandle = MethodHandles.publicLookup().in(bridgeClass).unreflect(bridgeClass.getMethods()[0]);
|
||||
bridgePainlessMethod = new PainlessMethod(bridgeMethod, bridgeClass,
|
||||
painlessMethod.returnType, bridgeTypeParameters, bridgeHandle, bridgeMethodType);
|
||||
painlessMethod.returnType, bridgeTypeParameters, bridgeHandle, bridgeMethodType, Collections.emptyMap());
|
||||
painlessClassBuilder.runtimeMethods.put(painlessMethodKey.intern(), bridgePainlessMethod);
|
||||
painlessBridgeCache.put(painlessMethod, bridgePainlessMethod);
|
||||
} catch (Exception exception) {
|
||||
|
@ -25,6 +25,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class PainlessMethod {
|
||||
@ -35,9 +36,10 @@ public class PainlessMethod {
|
||||
public final List<Class<?>> typeParameters;
|
||||
public final MethodHandle methodHandle;
|
||||
public final MethodType methodType;
|
||||
public final Map<Class<?>, Object> annotations;
|
||||
|
||||
public PainlessMethod(Method javaMethod, Class<?> targetClass, Class<?> returnType, List<Class<?>> typeParameters,
|
||||
MethodHandle methodHandle, MethodType methodType) {
|
||||
MethodHandle methodHandle, MethodType methodType, Map<Class<?>, Object> annotations) {
|
||||
|
||||
this.javaMethod = javaMethod;
|
||||
this.targetClass = targetClass;
|
||||
@ -45,6 +47,7 @@ public class PainlessMethod {
|
||||
this.typeParameters = typeParameters.isEmpty() ? Collections.emptyList() : Arrays.asList(typeParameters.toArray(new Class<?>[0]));
|
||||
this.methodHandle = methodHandle;
|
||||
this.methodType = methodType;
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -63,11 +66,12 @@ public class PainlessMethod {
|
||||
Objects.equals(targetClass, that.targetClass) &&
|
||||
Objects.equals(returnType, that.returnType) &&
|
||||
Objects.equals(typeParameters, that.typeParameters) &&
|
||||
Objects.equals(methodType, that.methodType);
|
||||
Objects.equals(methodType, that.methodType) &&
|
||||
Objects.equals(annotations, that.annotations);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(javaMethod, targetClass, returnType, typeParameters, methodType);
|
||||
return Objects.hash(javaMethod, targetClass, returnType, typeParameters, methodType, annotations);
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import org.elasticsearch.painless.ScriptRoot;
|
||||
import org.elasticsearch.painless.lookup.PainlessClassBinding;
|
||||
import org.elasticsearch.painless.lookup.PainlessInstanceBinding;
|
||||
import org.elasticsearch.painless.lookup.PainlessMethod;
|
||||
import org.elasticsearch.painless.spi.annotation.NonDeterministicAnnotation;
|
||||
import org.elasticsearch.painless.symbol.FunctionTable;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.Type;
|
||||
@ -127,9 +128,11 @@ public final class ECallLocal extends AExpression {
|
||||
typeParameters = new ArrayList<>(localFunction.getTypeParameters());
|
||||
actual = localFunction.getReturnType();
|
||||
} else if (importedMethod != null) {
|
||||
scriptRoot.markNonDeterministic(importedMethod.annotations.containsKey(NonDeterministicAnnotation.class));
|
||||
typeParameters = new ArrayList<>(importedMethod.typeParameters);
|
||||
actual = importedMethod.returnType;
|
||||
} else if (classBinding != null) {
|
||||
scriptRoot.markNonDeterministic(classBinding.annotations.containsKey(NonDeterministicAnnotation.class));
|
||||
typeParameters = new ArrayList<>(classBinding.typeParameters);
|
||||
actual = classBinding.returnType;
|
||||
bindingName = scriptRoot.getNextSyntheticName("class_binding");
|
||||
|
@ -37,7 +37,7 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a capturing function reference.
|
||||
* Represents a capturing function reference. For member functions that require a this reference, ie not static.
|
||||
*/
|
||||
public final class ECapturingFunctionRef extends AExpression implements ILambda {
|
||||
private final String variable;
|
||||
|
@ -32,7 +32,7 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents a cast that is inserted into the tree replacing other casts. (Internal only.)
|
||||
* Represents a cast that is inserted into the tree replacing other casts. (Internal only.) Casts are inserted during semantic checking.
|
||||
*/
|
||||
final class ECast extends AExpression {
|
||||
|
||||
|
@ -27,6 +27,7 @@ import org.elasticsearch.painless.MethodWriter;
|
||||
import org.elasticsearch.painless.ScriptRoot;
|
||||
import org.elasticsearch.painless.lookup.PainlessConstructor;
|
||||
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
|
||||
import org.elasticsearch.painless.spi.annotation.NonDeterministicAnnotation;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.commons.Method;
|
||||
|
||||
@ -75,6 +76,8 @@ public final class ENewObj extends AExpression {
|
||||
"constructor [" + typeToCanonicalTypeName(actual) + ", <init>/" + arguments.size() + "] not found"));
|
||||
}
|
||||
|
||||
scriptRoot.markNonDeterministic(constructor.annotations.containsKey(NonDeterministicAnnotation.class));
|
||||
|
||||
Class<?>[] types = new Class<?>[constructor.typeParameters.size()];
|
||||
constructor.typeParameters.toArray(types);
|
||||
|
||||
|
@ -27,6 +27,7 @@ import org.elasticsearch.painless.MethodWriter;
|
||||
import org.elasticsearch.painless.ScriptRoot;
|
||||
import org.elasticsearch.painless.lookup.PainlessMethod;
|
||||
import org.elasticsearch.painless.lookup.def;
|
||||
import org.elasticsearch.painless.spi.annotation.NonDeterministicAnnotation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -79,6 +80,8 @@ public final class PCallInvoke extends AExpression {
|
||||
"method [" + typeToCanonicalTypeName(prefix.actual) + ", " + name + "/" + arguments.size() + "] not found"));
|
||||
}
|
||||
|
||||
scriptRoot.markNonDeterministic(method.annotations.containsKey(NonDeterministicAnnotation.class));
|
||||
|
||||
sub = new PSubCallInvoke(location, method, prefix.actual, arguments);
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ public final class SClass extends AStatement {
|
||||
extractedVariables.addAll(variables);
|
||||
}
|
||||
|
||||
public void analyze(PainlessLookup painlessLookup, CompilerSettings settings) {
|
||||
public ScriptRoot analyze(PainlessLookup painlessLookup, CompilerSettings settings) {
|
||||
this.settings = settings;
|
||||
table = new ScriptRoot(painlessLookup, settings, scriptClassInfo, this);
|
||||
|
||||
@ -148,6 +148,7 @@ public final class SClass extends AStatement {
|
||||
|
||||
Locals locals = Locals.newProgramScope();
|
||||
analyze(table, locals);
|
||||
return table;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -636,7 +636,7 @@ class java.lang.Math {
|
||||
double nextDown(double)
|
||||
double nextUp(double)
|
||||
double pow(double,double)
|
||||
double random()
|
||||
double random() @nondeterministic
|
||||
double rint(double)
|
||||
long round(double)
|
||||
double scalb(double,int)
|
||||
@ -729,7 +729,7 @@ class java.lang.StrictMath {
|
||||
double nextDown(double)
|
||||
double nextUp(double)
|
||||
double pow(double,double)
|
||||
double random()
|
||||
double random() @nondeterministic
|
||||
double rint(double)
|
||||
long round(double)
|
||||
double scalb(double,int)
|
||||
@ -844,8 +844,8 @@ class java.lang.StringBuilder {
|
||||
|
||||
class java.lang.System {
|
||||
void arraycopy(Object,int,Object,int,int)
|
||||
long currentTimeMillis()
|
||||
long nanoTime()
|
||||
long currentTimeMillis() @nondeterministic
|
||||
long nanoTime() @nondeterministic
|
||||
}
|
||||
|
||||
# Thread: skipped
|
||||
|
@ -26,11 +26,11 @@
|
||||
|
||||
class java.time.Clock {
|
||||
Clock fixed(Instant,ZoneId)
|
||||
ZoneId getZone()
|
||||
Instant instant()
|
||||
long millis()
|
||||
Clock offset(Clock,Duration)
|
||||
Clock tick(Clock,Duration)
|
||||
ZoneId getZone() @nondeterministic
|
||||
Instant instant() @nondeterministic
|
||||
long millis() @nondeterministic
|
||||
Clock offset(Clock,Duration) @nondeterministic
|
||||
Clock tick(Clock,Duration) @nondeterministic
|
||||
}
|
||||
|
||||
class java.time.Duration {
|
||||
|
@ -490,9 +490,9 @@ class java.util.Calendar {
|
||||
Map getDisplayNames(int,int,Locale)
|
||||
int getFirstDayOfWeek()
|
||||
int getGreatestMinimum(int)
|
||||
Calendar getInstance()
|
||||
Calendar getInstance(TimeZone)
|
||||
Calendar getInstance(TimeZone,Locale)
|
||||
Calendar getInstance() @nondeterministic
|
||||
Calendar getInstance(TimeZone) @nondeterministic
|
||||
Calendar getInstance(TimeZone,Locale) @nondeterministic
|
||||
int getLeastMaximum(int)
|
||||
int getMaximum(int)
|
||||
int getMinimalDaysInFirstWeek()
|
||||
@ -574,7 +574,7 @@ class java.util.Collections {
|
||||
Comparator reverseOrder()
|
||||
Comparator reverseOrder(Comparator)
|
||||
void rotate(List,int)
|
||||
void shuffle(List)
|
||||
void shuffle(List) @nondeterministic
|
||||
void shuffle(List,Random)
|
||||
Set singleton(def)
|
||||
List singletonList(def)
|
||||
@ -605,7 +605,7 @@ class java.util.Currency {
|
||||
}
|
||||
|
||||
class java.util.Date {
|
||||
()
|
||||
() @nondeterministic
|
||||
(long)
|
||||
boolean after(Date)
|
||||
boolean before(Date)
|
||||
@ -910,22 +910,22 @@ class java.util.PriorityQueue {
|
||||
}
|
||||
|
||||
class java.util.Random {
|
||||
()
|
||||
() @nondeterministic
|
||||
(long)
|
||||
DoubleStream doubles(long)
|
||||
DoubleStream doubles(long,double,double)
|
||||
IntStream ints(long)
|
||||
IntStream ints(long,int,int)
|
||||
LongStream longs(long)
|
||||
LongStream longs(long,long,long)
|
||||
boolean nextBoolean()
|
||||
void nextBytes(byte[])
|
||||
double nextDouble()
|
||||
float nextFloat()
|
||||
double nextGaussian()
|
||||
int nextInt()
|
||||
int nextInt(int)
|
||||
long nextLong()
|
||||
DoubleStream doubles(long) @nondeterministic
|
||||
DoubleStream doubles(long,double,double) @nondeterministic
|
||||
IntStream ints(long) @nondeterministic
|
||||
IntStream ints(long,int,int) @nondeterministic
|
||||
LongStream longs(long) @nondeterministic
|
||||
LongStream longs(long,long,long) @nondeterministic
|
||||
boolean nextBoolean() @nondeterministic
|
||||
void nextBytes(byte[]) @nondeterministic
|
||||
double nextDouble() @nondeterministic
|
||||
float nextFloat() @nondeterministic
|
||||
double nextGaussian() @nondeterministic
|
||||
int nextInt() @nondeterministic
|
||||
int nextInt(int) @nondeterministic
|
||||
long nextLong() @nondeterministic
|
||||
void setSeed(long)
|
||||
}
|
||||
|
||||
@ -1031,7 +1031,7 @@ class java.util.UUID {
|
||||
UUID fromString(String)
|
||||
long getLeastSignificantBits()
|
||||
long getMostSignificantBits()
|
||||
UUID randomUUID()
|
||||
UUID randomUUID() @nondeterministic
|
||||
UUID nameUUIDFromBytes(byte[])
|
||||
long node()
|
||||
long timestamp()
|
||||
|
@ -162,6 +162,32 @@ public class FactoryTests extends ScriptTestCase {
|
||||
assertEquals(false, factory.needsNothing());
|
||||
}
|
||||
|
||||
public void testDeterministic() {
|
||||
FactoryTestScript.Factory factory =
|
||||
scriptEngine.compile("deterministic_test", "Integer.parseInt('123')",
|
||||
FactoryTestScript.CONTEXT, Collections.emptyMap());
|
||||
assertTrue(factory.isResultDeterministic());
|
||||
assertEquals(123, factory.newInstance(Collections.emptyMap()).execute(0));
|
||||
}
|
||||
|
||||
public void testNotDeterministic() {
|
||||
FactoryTestScript.Factory factory =
|
||||
scriptEngine.compile("not_deterministic_test", "Math.random()",
|
||||
FactoryTestScript.CONTEXT, Collections.emptyMap());
|
||||
assertFalse(factory.isResultDeterministic());
|
||||
Double d = (Double)factory.newInstance(Collections.emptyMap()).execute(0);
|
||||
assertTrue(d >= 0.0 && d <= 1.0);
|
||||
}
|
||||
|
||||
public void testMixedDeterministicIsNotDeterministic() {
|
||||
FactoryTestScript.Factory factory =
|
||||
scriptEngine.compile("not_deterministic_test", "Integer.parseInt('123') + Math.random()",
|
||||
FactoryTestScript.CONTEXT, Collections.emptyMap());
|
||||
assertFalse(factory.isResultDeterministic());
|
||||
Double d = (Double)factory.newInstance(Collections.emptyMap()).execute(0);
|
||||
assertTrue(d >= 123.0 && d <= 124.0);
|
||||
}
|
||||
|
||||
public abstract static class EmptyTestScript {
|
||||
public static final String[] PARAMETERS = {};
|
||||
public abstract Object execute();
|
||||
|
@ -360,6 +360,8 @@ public class QueryShardContext extends QueryRewriteContext {
|
||||
/** Compile script using script service */
|
||||
public <FactoryType extends ScriptFactory> FactoryType compile(Script script, ScriptContext<FactoryType> context) {
|
||||
FactoryType factory = scriptService.compile(script, context);
|
||||
// TODO(stu): can check `factory instanceof ScriptFactory && ((ScriptFactory) factory).isResultDeterministic() == false`
|
||||
// to avoid being so intrusive
|
||||
if (factory.isResultDeterministic() == false) {
|
||||
failIfFrozen();
|
||||
}
|
||||
|
@ -82,7 +82,11 @@ public class MultiValuesSourceFieldConfig implements Writeable, ToXContentObject
|
||||
}
|
||||
|
||||
public MultiValuesSourceFieldConfig(StreamInput in) throws IOException {
|
||||
this.fieldName = in.readString();
|
||||
if (in.getVersion().onOrAfter(Version.V_7_6_0)) {
|
||||
this.fieldName = in.readOptionalString();
|
||||
} else {
|
||||
this.fieldName = in.readString();
|
||||
}
|
||||
this.missing = in.readGenericValue();
|
||||
this.script = in.readOptionalWriteable(Script::new);
|
||||
if (in.getVersion().before(Version.V_7_0_0)) {
|
||||
@ -110,7 +114,11 @@ public class MultiValuesSourceFieldConfig implements Writeable, ToXContentObject
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeString(fieldName);
|
||||
if (out.getVersion().onOrAfter(Version.V_7_6_0)) {
|
||||
out.writeOptionalString(fieldName);
|
||||
} else {
|
||||
out.writeString(fieldName);
|
||||
}
|
||||
out.writeGenericValue(missing);
|
||||
out.writeOptionalWriteable(script);
|
||||
if (out.getVersion().before(Version.V_7_0_0)) {
|
||||
|
@ -23,6 +23,7 @@ import org.elasticsearch.index.fielddata.ScriptDocValues;
|
||||
import org.elasticsearch.script.MockScriptPlugin;
|
||||
import org.elasticsearch.script.Script;
|
||||
import org.elasticsearch.script.ScriptType;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -116,4 +117,13 @@ public class AggregationTestScriptsPlugin extends MockScriptPlugin {
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
|
||||
scripts.put("Math.random()", vars -> ESTestCase.randomDouble());
|
||||
|
||||
return scripts;
|
||||
}
|
||||
}
|
||||
|
@ -1466,10 +1466,10 @@ public class DateHistogramIT extends ESIntegTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=date")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -1484,10 +1484,21 @@ public class DateHistogramIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("fieldname", "d");
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(dateHistogram("histo").field("d")
|
||||
.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.CURRENT_DATE, params))
|
||||
.dateHistogramInterval(DateHistogramInterval.MONTH)).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(dateHistogram("histo").field("d")
|
||||
.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.LONG_PLUS_ONE_MONTH, params))
|
||||
.dateHistogramInterval(DateHistogramInterval.MONTH)).get();
|
||||
assertSearchResponse(r);
|
||||
@ -1495,10 +1506,9 @@ public class DateHistogramIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(dateHistogram("histo").field("d").dateHistogramInterval(DateHistogramInterval.MONTH)).get();
|
||||
assertSearchResponse(r);
|
||||
@ -1506,7 +1516,7 @@ public class DateHistogramIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
public void testSingleValuedFieldOrderedBySingleValueSubAggregationAscAndKeyDesc() throws Exception {
|
||||
|
@ -884,10 +884,10 @@ public class DateRangeIT extends ESIntegTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "date", "type=date")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -903,11 +903,11 @@ public class DateRangeIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("fieldname", "date");
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(dateRange("foo").field("date")
|
||||
.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.DOUBLE_PLUS_ONE_MONTH, params))
|
||||
.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.CURRENT_DATE, params))
|
||||
.addRange(ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC),
|
||||
ZonedDateTime.of(2013, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)))
|
||||
.get();
|
||||
@ -918,9 +918,9 @@ public class DateRangeIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(dateRange("foo").field("date")
|
||||
.script(new Script(ScriptType.INLINE, "mockscript", DateScriptMocksPlugin.DOUBLE_PLUS_ONE_MONTH, params))
|
||||
.addRange(ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC),
|
||||
ZonedDateTime.of(2013, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)))
|
||||
.get();
|
||||
@ -930,6 +930,18 @@ public class DateRangeIT extends ESIntegTestCase {
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(dateRange("foo").field("date")
|
||||
.addRange(ZonedDateTime.of(2012, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC),
|
||||
ZonedDateTime.of(2013, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC)))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,6 +38,7 @@ public class DateScriptMocksPlugin extends MockScriptPlugin {
|
||||
static final String EXTRACT_FIELD = "extract_field";
|
||||
static final String DOUBLE_PLUS_ONE_MONTH = "double_date_plus_1_month";
|
||||
static final String LONG_PLUS_ONE_MONTH = "long_date_plus_1_month";
|
||||
static final String CURRENT_DATE = "current_date";
|
||||
|
||||
@Override
|
||||
public Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
|
||||
@ -53,4 +54,11 @@ public class DateScriptMocksPlugin extends MockScriptPlugin {
|
||||
new DateTime((long) params.get("_value"), DateTimeZone.UTC).plusMonths(1).getMillis());
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
scripts.put(CURRENT_DATE, params -> new DateTime().getMillis());
|
||||
return scripts;
|
||||
}
|
||||
}
|
||||
|
@ -112,6 +112,15 @@ public class DoubleTermsIT extends AbstractTermsTestCase {
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
|
||||
scripts.put("Math.random()", vars -> DoubleTermsIT.randomDouble());
|
||||
|
||||
return scripts;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int NUM_DOCS = 5; // TODO: randomize the size?
|
||||
@ -918,10 +927,10 @@ public class DoubleTermsIT extends AbstractTermsTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=float")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -934,10 +943,10 @@ public class DoubleTermsIT extends AbstractTermsTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(
|
||||
terms("terms").field("d").script(
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "_value + 1", Collections.emptyMap()))).get();
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "Math.random()", Collections.emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
@ -945,14 +954,24 @@ public class DoubleTermsIT extends AbstractTermsTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(
|
||||
terms("terms").field("d").script(
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "_value + 1", Collections.emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(terms("terms").field("d")).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
}
|
||||
|
@ -109,6 +109,15 @@ public class HistogramIT extends ESIntegTestCase {
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
|
||||
scripts.put("Math.random()", vars -> HistogramIT.randomDouble());
|
||||
|
||||
return scripts;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1101,10 +1110,10 @@ public class HistogramIT extends ESIntegTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=float")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -1117,9 +1126,10 @@ public class HistogramIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(histogram("histo").field("d")
|
||||
.script(new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "_value + 1", emptyMap())).interval(0.7).offset(0.05)).get();
|
||||
.script(new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "Math.random()", emptyMap())).interval(0.7).offset(0.05))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
@ -1127,8 +1137,17 @@ public class HistogramIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(histogram("histo").field("d")
|
||||
.script(new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "_value + 1", emptyMap())).interval(0.7).offset(0.05)).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(histogram("histo").field("d").interval(0.7).offset(0.05))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
@ -1136,7 +1155,7 @@ public class HistogramIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
public void testSingleValuedFieldOrderedBySingleValueSubAggregationAscAndKeyDesc() throws Exception {
|
||||
|
@ -99,6 +99,15 @@ public class LongTermsIT extends AbstractTermsTestCase {
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
|
||||
scripts.put("Math.random()", vars -> LongTermsIT.randomDouble());
|
||||
|
||||
return scripts;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int NUM_DOCS = 5; // TODO randomize the size?
|
||||
@ -894,10 +903,10 @@ public class LongTermsIT extends AbstractTermsTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -910,10 +919,10 @@ public class LongTermsIT extends AbstractTermsTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(
|
||||
terms("terms").field("d").script(
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "_value + 1", Collections.emptyMap()))).get();
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "Math.random()", Collections.emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
@ -921,14 +930,24 @@ public class LongTermsIT extends AbstractTermsTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(terms("terms").field("d")).get();
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(
|
||||
terms("terms").field("d").script(
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "_value + 1", Collections.emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(terms("terms").field("d")).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
}
|
||||
|
@ -92,6 +92,15 @@ public class RangeIT extends ESIntegTestCase {
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
|
||||
scripts.put("Math.random()", vars -> RangeIT.randomDouble());
|
||||
|
||||
return scripts;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -945,10 +954,10 @@ public class RangeIT extends ESIntegTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "i", "type=integer")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -962,12 +971,12 @@ public class RangeIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("fieldname", "date");
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(
|
||||
range("foo").field("i").script(
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "_value + 1", Collections.emptyMap())).addRange(0, 10))
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "Math.random()", Collections.emptyMap())).addRange(0, 10))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
@ -976,15 +985,26 @@ public class RangeIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(range("foo").field("i").addRange(0, 10)).get();
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(
|
||||
range("foo").field("i").script(
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "_value + 1", Collections.emptyMap())).addRange(0, 10))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(range("foo").field("i").addRange(0, 10)).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
public void testFieldAlias() {
|
||||
|
@ -198,6 +198,15 @@ public class SignificantTermsSignificanceScoreIT extends ESIntegTestCase {
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
|
||||
scripts.put("Math.random()", vars -> SignificantTermsSignificanceScoreIT.randomDouble());
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
private static long longValue(Object value) {
|
||||
return ((ScriptHeuristic.LongAccessor) value).longValue();
|
||||
}
|
||||
@ -683,10 +692,10 @@ public class SignificantTermsSignificanceScoreIT extends ESIntegTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -699,8 +708,10 @@ public class SignificantTermsSignificanceScoreIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
ScriptHeuristic scriptHeuristic = getScriptSignificanceHeuristic();
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
ScriptHeuristic scriptHeuristic = new ScriptHeuristic(
|
||||
new Script(ScriptType.INLINE, "mockscript", "Math.random()", Collections.emptyMap())
|
||||
);
|
||||
boolean useSigText = randomBoolean();
|
||||
SearchResponse r;
|
||||
if (useSigText) {
|
||||
@ -717,8 +728,24 @@ public class SignificantTermsSignificanceScoreIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
// Test that a request using a deterministic script gets cached
|
||||
scriptHeuristic = getScriptSignificanceHeuristic();
|
||||
useSigText = randomBoolean();
|
||||
if (useSigText) {
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(significantText("foo", "s").significanceHeuristic(scriptHeuristic)).get();
|
||||
} else {
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(significantTerms("foo").field("s").significanceHeuristic(scriptHeuristic)).get();
|
||||
}
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
if (useSigText) {
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(significantText("foo", "s")).get();
|
||||
} else {
|
||||
@ -729,9 +756,6 @@ public class SignificantTermsSignificanceScoreIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -119,6 +119,15 @@ public class StringTermsIT extends AbstractTermsTestCase {
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
|
||||
scripts.put("Math.random()", vars -> StringTermsIT.randomDouble());
|
||||
|
||||
return scripts;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1115,10 +1124,10 @@ public class StringTermsIT extends AbstractTermsTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=keyword")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -1131,8 +1140,21 @@ public class StringTermsIT extends AbstractTermsTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(
|
||||
terms("terms").field("d").script(
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "Math.random()", Collections.emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(
|
||||
terms("terms").field("d").script(
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "'foo_' + _value", Collections.emptyMap())))
|
||||
@ -1142,16 +1164,15 @@ public class StringTermsIT extends AbstractTermsTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(terms("terms").field("d")).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
}
|
||||
|
@ -83,6 +83,9 @@ public class AvgAggregatorTests extends AggregatorTestCase {
|
||||
/** Script to return the {@code _value} provided by aggs framework. */
|
||||
public static final String VALUE_SCRIPT = "_value";
|
||||
|
||||
/** Script to return a random double */
|
||||
public static final String RANDOM_SCRIPT = "Math.random()";
|
||||
|
||||
@Override
|
||||
protected ScriptService getMockScriptService() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
@ -115,8 +118,12 @@ public class AvgAggregatorTests extends AggregatorTestCase {
|
||||
return ((Number) vars.get("_value")).doubleValue() + inc;
|
||||
});
|
||||
|
||||
Map<String, Function<Map<String, Object>, Object>> nonDeterministicScripts = new HashMap<>();
|
||||
nonDeterministicScripts.put(RANDOM_SCRIPT, vars -> AvgAggregatorTests.randomDouble());
|
||||
|
||||
MockScriptEngine scriptEngine = new MockScriptEngine(MockScriptEngine.NAME,
|
||||
scripts,
|
||||
nonDeterministicScripts,
|
||||
Collections.emptyMap());
|
||||
Map<String, ScriptEngine> engines = Collections.singletonMap(scriptEngine.getType(), scriptEngine);
|
||||
|
||||
@ -638,9 +645,10 @@ public class AvgAggregatorTests extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that an aggregation using a script does not get cached.
|
||||
* Make sure that an aggregation using a deterministic script does gets cached while
|
||||
* one using a nondeterministic script does not.
|
||||
*/
|
||||
public void testDontCacheScripts() throws IOException {
|
||||
public void testScriptCaching() throws IOException {
|
||||
Directory directory = newDirectory();
|
||||
RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory);
|
||||
final int numDocs = 10;
|
||||
@ -675,7 +683,26 @@ public class AvgAggregatorTests extends AggregatorTestCase {
|
||||
assertEquals("avg", avg.getName());
|
||||
assertTrue(AggregationInspectionHelper.hasValue(avg));
|
||||
|
||||
// Test that an aggregation using a script does not get cached
|
||||
// Test that an aggregation using a deterministic script gets cached
|
||||
assertTrue(aggregator.context().getQueryShardContext().isCacheable());
|
||||
|
||||
aggregationBuilder = new AvgAggregationBuilder("avg")
|
||||
.field("value")
|
||||
.script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, RANDOM_SCRIPT, Collections.emptyMap()));
|
||||
|
||||
aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType);
|
||||
aggregator.preCollection();
|
||||
indexSearcher.search(new MatchAllDocsQuery(), aggregator);
|
||||
aggregator.postCollection();
|
||||
|
||||
avg = (InternalAvg) aggregator.buildAggregation(0L);
|
||||
|
||||
assertTrue(avg.getValue() >= 0.0);
|
||||
assertTrue(avg.getValue() <= 1.0);
|
||||
assertEquals("avg", avg.getName());
|
||||
assertTrue(AggregationInspectionHelper.hasValue(avg));
|
||||
|
||||
// Test that an aggregation using a nondeterministic script does not get cached
|
||||
assertFalse(aggregator.context().getQueryShardContext().isCacheable());
|
||||
|
||||
multiReader.close();
|
||||
|
@ -90,6 +90,15 @@ public class CardinalityIT extends ESIntegTestCase {
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
|
||||
scripts.put("Math.random()", vars -> CardinalityIT.randomDouble());
|
||||
|
||||
return scripts;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -449,10 +458,10 @@ public class CardinalityIT extends ESIntegTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -465,10 +474,11 @@ public class CardinalityIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(
|
||||
cardinality("foo").field("d").script(new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "_value", emptyMap())))
|
||||
cardinality("foo").field("d").script(new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "Math.random()",
|
||||
emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
@ -477,14 +487,25 @@ public class CardinalityIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(cardinality("foo").field("d")).get();
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(
|
||||
cardinality("foo").field("d").script(new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "_value", emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(cardinality("foo").field("d")).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
}
|
||||
|
@ -639,10 +639,10 @@ public class ExtendedStatsIT extends AbstractNumericTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -655,10 +655,10 @@ public class ExtendedStatsIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(extendedStats("foo").field("d")
|
||||
.script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value + 1", Collections.emptyMap())))
|
||||
.script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "Math.random()", Collections.emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
@ -667,15 +667,26 @@ public class ExtendedStatsIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(extendedStats("foo").field("d")).get();
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(extendedStats("foo").field("d")
|
||||
.script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value + 1", Collections.emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(extendedStats("foo").field("d")).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -558,10 +558,10 @@ public class HDRPercentileRanksIT extends AbstractNumericTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -574,8 +574,22 @@ public class HDRPercentileRanksIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client()
|
||||
.prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(percentileRanks("foo", new double[]{50.0})
|
||||
.method(PercentilesMethod.HDR).field("d")
|
||||
.script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "Math.random()", emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client()
|
||||
.prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(percentileRanks("foo", new double[]{50.0})
|
||||
.method(PercentilesMethod.HDR).field("d")
|
||||
@ -586,10 +600,9 @@ public class HDRPercentileRanksIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(percentileRanks("foo", new double[]{50.0}).method(PercentilesMethod.HDR).field("d")).get();
|
||||
assertSearchResponse(r);
|
||||
@ -597,7 +610,7 @@ public class HDRPercentileRanksIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -523,10 +523,10 @@ public class HDRPercentilesIT extends AbstractNumericTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -539,10 +539,10 @@ public class HDRPercentilesIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(percentiles("foo").method(PercentilesMethod.HDR).field("d").percentiles(50.0)
|
||||
.script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value - 1", emptyMap())))
|
||||
.script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "Math.random()", emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
@ -551,8 +551,19 @@ public class HDRPercentilesIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(percentiles("foo").method(PercentilesMethod.HDR).field("d").percentiles(50.0)
|
||||
.script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value - 1", emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(percentiles("foo").method(PercentilesMethod.HDR).field("d").percentiles(50.0)).get();
|
||||
assertSearchResponse(r);
|
||||
@ -560,7 +571,7 @@ public class HDRPercentilesIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -110,6 +110,9 @@ public class MaxAggregatorTests extends AggregatorTestCase {
|
||||
/** Script to return the {@code _value} provided by aggs framework. */
|
||||
public static final String VALUE_SCRIPT = "_value";
|
||||
|
||||
/** Script to return a random double */
|
||||
public static final String RANDOM_SCRIPT = "Math.random()";
|
||||
|
||||
@Override
|
||||
protected ScriptService getMockScriptService() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
@ -143,8 +146,12 @@ public class MaxAggregatorTests extends AggregatorTestCase {
|
||||
return ((Number) vars.get("_value")).doubleValue() + inc;
|
||||
});
|
||||
|
||||
Map<String, Function<Map<String, Object>, Object>> nonDeterministicScripts = new HashMap<>();
|
||||
nonDeterministicScripts.put(RANDOM_SCRIPT, vars -> MaxAggregatorTests.randomDouble());
|
||||
|
||||
MockScriptEngine scriptEngine = new MockScriptEngine(MockScriptEngine.NAME,
|
||||
scripts,
|
||||
nonDeterministicScripts,
|
||||
Collections.emptyMap());
|
||||
Map<String, ScriptEngine> engines = Collections.singletonMap(scriptEngine.getType(), scriptEngine);
|
||||
|
||||
@ -948,9 +955,10 @@ public class MaxAggregatorTests extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that an aggregation using a script does not get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws IOException {
|
||||
public void testScriptCaching() throws Exception {
|
||||
Directory directory = newDirectory();
|
||||
RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory);
|
||||
final int numDocs = 10;
|
||||
@ -968,7 +976,6 @@ public class MaxAggregatorTests extends AggregatorTestCase {
|
||||
MultiReader multiReader = new MultiReader(indexReader, unamappedIndexReader);
|
||||
IndexSearcher indexSearcher = newSearcher(multiReader, true, true);
|
||||
|
||||
|
||||
MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER);
|
||||
fieldType.setName("value");
|
||||
MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max")
|
||||
@ -987,6 +994,24 @@ public class MaxAggregatorTests extends AggregatorTestCase {
|
||||
assertTrue(AggregationInspectionHelper.hasValue(max));
|
||||
|
||||
// Test that an aggregation using a script does not get cached
|
||||
assertTrue(aggregator.context().getQueryShardContext().isCacheable());
|
||||
aggregationBuilder = new MaxAggregationBuilder("max")
|
||||
.field("value")
|
||||
.script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, RANDOM_SCRIPT, Collections.emptyMap()));
|
||||
|
||||
aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType);
|
||||
aggregator.preCollection();
|
||||
indexSearcher.search(new MatchAllDocsQuery(), aggregator);
|
||||
aggregator.postCollection();
|
||||
|
||||
max = (InternalMax) aggregator.buildAggregation(0L);
|
||||
|
||||
assertTrue(max.getValue() >= 0.0);
|
||||
assertTrue(max.getValue() <= 1.0);
|
||||
assertEquals("max", max.getName());
|
||||
assertTrue(AggregationInspectionHelper.hasValue(max));
|
||||
|
||||
// Test that an aggregation using a nondeterministic script does not get cached
|
||||
assertFalse(aggregator.context().getQueryShardContext().isCacheable());
|
||||
|
||||
multiReader.close();
|
||||
|
@ -556,10 +556,10 @@ public class MedianAbsoluteDeviationIT extends AbstractNumericTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(
|
||||
prepareCreate("cache_test_idx")
|
||||
.addMapping("type", "d", "type=long")
|
||||
@ -579,8 +579,20 @@ public class MedianAbsoluteDeviationIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(randomBuilder()
|
||||
.field("d")
|
||||
.script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "Math.random()", emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(randomBuilder()
|
||||
.field("d")
|
||||
.script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value - 1", emptyMap()))).get();
|
||||
@ -589,16 +601,15 @@ public class MedianAbsoluteDeviationIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(randomBuilder().field("d")).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import java.util.function.Function;
|
||||
|
||||
import org.elasticsearch.script.MockScriptPlugin;
|
||||
import org.elasticsearch.search.lookup.LeafDocLookup;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
|
||||
/**
|
||||
* Provides a number of dummy scripts for tests.
|
||||
@ -52,6 +53,9 @@ public class MetricAggScriptPlugin extends MockScriptPlugin {
|
||||
/** Script to return the {@code _value} provided by aggs framework. */
|
||||
public static final String VALUE_SCRIPT = "_value";
|
||||
|
||||
/** Script to return a random double */
|
||||
public static final String RANDOM_SCRIPT = "Math.random()";
|
||||
|
||||
@Override
|
||||
public String pluginScriptLang() {
|
||||
return METRIC_SCRIPT_ENGINE;
|
||||
@ -88,4 +92,13 @@ public class MetricAggScriptPlugin extends MockScriptPlugin {
|
||||
});
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
|
||||
scripts.put("Math.random()", vars -> ESTestCase.randomDouble());
|
||||
|
||||
return scripts;
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +127,8 @@ public class MinAggregatorTests extends AggregatorTestCase {
|
||||
|
||||
private static final String INVERT_SCRIPT = "invert";
|
||||
|
||||
private static final String RANDOM_SCRIPT = "random";
|
||||
|
||||
@Override
|
||||
protected ScriptService getMockScriptService() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
@ -161,8 +163,12 @@ public class MinAggregatorTests extends AggregatorTestCase {
|
||||
});
|
||||
scripts.put(INVERT_SCRIPT, vars -> -((Number) vars.get("_value")).doubleValue());
|
||||
|
||||
Map<String, Function<Map<String, Object>, Object>> nonDeterministicScripts = new HashMap<>();
|
||||
nonDeterministicScripts.put(RANDOM_SCRIPT, vars -> AggregatorTestCase.randomDouble());
|
||||
|
||||
MockScriptEngine scriptEngine = new MockScriptEngine(MockScriptEngine.NAME,
|
||||
scripts,
|
||||
nonDeterministicScripts,
|
||||
Collections.emptyMap());
|
||||
Map<String, ScriptEngine> engines = Collections.singletonMap(scriptEngine.getType(), scriptEngine);
|
||||
|
||||
@ -649,7 +655,7 @@ public class MinAggregatorTests extends AggregatorTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testNoCachingWithScript() throws IOException {
|
||||
public void testScriptCaching() throws IOException {
|
||||
|
||||
MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER);
|
||||
fieldType.setName("number");
|
||||
@ -657,6 +663,10 @@ public class MinAggregatorTests extends AggregatorTestCase {
|
||||
.field("number")
|
||||
.script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, INVERT_SCRIPT, Collections.emptyMap()));;
|
||||
|
||||
MinAggregationBuilder nonDeterministicAggregationBuilder = new MinAggregationBuilder("min")
|
||||
.field("number")
|
||||
.script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, RANDOM_SCRIPT, Collections.emptyMap()));;
|
||||
|
||||
try (Directory directory = newDirectory()) {
|
||||
RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory);
|
||||
indexWriter.addDocument(singleton(new NumericDocValuesField("number", 7)));
|
||||
@ -668,11 +678,19 @@ public class MinAggregatorTests extends AggregatorTestCase {
|
||||
try (IndexReader indexReader = DirectoryReader.open(directory)) {
|
||||
IndexSearcher indexSearcher = newSearcher(indexReader, true, true);
|
||||
|
||||
InternalMin min = searchAndReduce(indexSearcher, new MatchAllDocsQuery(), aggregationBuilder, fieldType);
|
||||
assertEquals(-7.0, min.getValue(), 0);
|
||||
InternalMin min = searchAndReduce(indexSearcher, new MatchAllDocsQuery(), nonDeterministicAggregationBuilder, fieldType);
|
||||
assertTrue(min.getValue() >= 0.0 && min.getValue() <= 1.0);
|
||||
assertTrue(AggregationInspectionHelper.hasValue(min));
|
||||
|
||||
assertFalse(queryShardContext.isCacheable());
|
||||
|
||||
indexSearcher = newSearcher(indexReader, true, true);
|
||||
|
||||
min = searchAndReduce(indexSearcher, new MatchAllDocsQuery(), aggregationBuilder, fieldType);
|
||||
assertEquals(-7.0, min.getValue(), 0);
|
||||
assertTrue(AggregationInspectionHelper.hasValue(min));
|
||||
|
||||
assertTrue(queryShardContext.isCacheable());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -247,6 +247,23 @@ public class ScriptedMetricIT extends ESIntegTestCase {
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
Map<String, Function<Map<String, Object>, Object>> scripts = new HashMap<>();
|
||||
|
||||
scripts.put("state.data = Math.random()", vars ->
|
||||
aggScript(vars, state -> state.put("data", ScriptedMetricIT.randomDouble())));
|
||||
|
||||
|
||||
scripts.put("state['count'] = Math.random() >= 0.5 ? 1 : 0", vars ->
|
||||
aggScript(vars, state -> state.put("count", ScriptedMetricIT.randomDouble() >= 0.5 ? 1 : 0)));
|
||||
|
||||
|
||||
scripts.put("return Math.random()", vars -> ScriptedMetricIT.randomDouble());
|
||||
|
||||
return scripts;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static Map<String, Object> aggScript(Map<String, Object> vars, Consumer<Map<String, Object>> fn) {
|
||||
Map<String, Object> aggState = (Map<String, Object>) vars.get("state");
|
||||
@ -1015,17 +1032,27 @@ public class ScriptedMetricIT extends ESIntegTestCase {
|
||||
assertThat(aggregationResult.get(0), equalTo(0));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script gets cached and nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
// TODO(stu): add non-determinism in init, agg, combine and reduce, ensure not cached
|
||||
Script mapScript = new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "state['count'] = 1", Collections.emptyMap());
|
||||
Script combineScript =
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "no-op aggregation", Collections.emptyMap());
|
||||
Script reduceScript = new Script(ScriptType.INLINE, CustomScriptPlugin.NAME,
|
||||
"no-op list aggregation", Collections.emptyMap());
|
||||
|
||||
Script ndInitScript = new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "state.data = Math.random()",
|
||||
Collections.emptyMap());
|
||||
|
||||
Script ndMapScript = new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "state['count'] = Math.random() >= 0.5 ? 1 : 0",
|
||||
Collections.emptyMap());
|
||||
|
||||
Script ndRandom = new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "return Math.random()",
|
||||
Collections.emptyMap());
|
||||
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -1038,15 +1065,58 @@ public class ScriptedMetricIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a non-deterministic init script causes the result to not be cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(scriptedMetric("foo").mapScript(mapScript).combineScript(combineScript).reduceScript(reduceScript)).get();
|
||||
.addAggregation(scriptedMetric("foo").initScript(ndInitScript).mapScript(mapScript).combineScript(combineScript)
|
||||
.reduceScript(reduceScript)).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a non-deterministic map script causes the result to not be cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(scriptedMetric("foo").mapScript(ndMapScript).combineScript(combineScript).reduceScript(reduceScript))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a non-deterministic combine script causes the result to not be cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(scriptedMetric("foo").mapScript(mapScript).combineScript(ndRandom).reduceScript(reduceScript)).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// NOTE: random reduce scripts don't hit the query shard context (they are done on the coordinator) and so can be cached.
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(scriptedMetric("foo").mapScript(mapScript).combineScript(combineScript).reduceScript(ndRandom)).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Test that all deterministic scripts cause the request to be cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(scriptedMetric("foo").mapScript(mapScript).combineScript(combineScript).reduceScript(reduceScript))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
public void testConflictingAggAndScriptParams() {
|
||||
|
@ -488,10 +488,10 @@ public class StatsIT extends AbstractNumericTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -504,10 +504,10 @@ public class StatsIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(
|
||||
stats("foo").field("d").script(
|
||||
new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value + 1", Collections.emptyMap()))).get();
|
||||
new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "Math.random()", Collections.emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
@ -515,14 +515,24 @@ public class StatsIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(stats("foo").field("d")).get();
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(
|
||||
stats("foo").field("d").script(
|
||||
new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value + 1", Collections.emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(stats("foo").field("d")).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ import static org.elasticsearch.search.aggregations.AggregationBuilders.histogra
|
||||
import static org.elasticsearch.search.aggregations.AggregationBuilders.sum;
|
||||
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
|
||||
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.METRIC_SCRIPT_ENGINE;
|
||||
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.RANDOM_SCRIPT;
|
||||
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.SUM_VALUES_FIELD_SCRIPT;
|
||||
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.VALUE_FIELD_SCRIPT;
|
||||
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.VALUE_SCRIPT;
|
||||
@ -374,10 +375,10 @@ public class SumIT extends AbstractNumericTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -390,10 +391,10 @@ public class SumIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(sum("foo").field("d").script(
|
||||
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_SCRIPT, Collections.emptyMap()))).get();
|
||||
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, RANDOM_SCRIPT, Collections.emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
@ -401,15 +402,25 @@ public class SumIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(sum("foo").field("d")).get();
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(sum("foo").field("d").script(
|
||||
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_SCRIPT, Collections.emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(sum("foo").field("d")).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
public void testFieldAlias() {
|
||||
|
@ -484,10 +484,10 @@ public class TDigestPercentileRanksIT extends AbstractNumericTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -500,8 +500,20 @@ public class TDigestPercentileRanksIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(percentileRanks("foo", new double[]{50.0})
|
||||
.field("d")
|
||||
.script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "Math.random()", emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(percentileRanks("foo", new double[]{50.0})
|
||||
.field("d")
|
||||
.script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value - 1", emptyMap()))).get();
|
||||
@ -510,17 +522,16 @@ public class TDigestPercentileRanksIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(percentileRanks("foo", new double[]{50.0}).field("d")).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -467,10 +467,10 @@ public class TDigestPercentilesIT extends AbstractNumericTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -483,9 +483,9 @@ public class TDigestPercentilesIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(percentiles("foo").field("d")
|
||||
.percentiles(50.0).script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value - 1", emptyMap())))
|
||||
.percentiles(50.0).script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "Math.random()", emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
@ -494,14 +494,24 @@ public class TDigestPercentilesIT extends AbstractNumericTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(percentiles("foo").field("d").percentiles(50.0)).get();
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(percentiles("foo").field("d")
|
||||
.percentiles(50.0).script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value - 1", emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(percentiles("foo").field("d").percentiles(50.0)).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
}
|
||||
|
@ -107,6 +107,11 @@ public class TopHitsIT extends ESIntegTestCase {
|
||||
protected Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
|
||||
return Collections.singletonMap("5", script -> "5");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() {
|
||||
return Collections.singletonMap("Math.random()", script -> TopHitsIT.randomDouble());
|
||||
}
|
||||
}
|
||||
|
||||
public static String randomExecutionHint() {
|
||||
@ -1087,10 +1092,10 @@ public class TopHitsIT extends ESIntegTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
try {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(
|
||||
@ -1108,10 +1113,10 @@ public class TopHitsIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script field does not get cached
|
||||
// Test that a request using a nondeterministic script field does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(topHits("foo").scriptField("bar",
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "5", Collections.emptyMap()))).get();
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "Math.random()", Collections.emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
@ -1119,7 +1124,32 @@ public class TopHitsIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script sort does not get cached
|
||||
// Test that a request using a nondeterministic script sort does not get cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(topHits("foo").sort(
|
||||
SortBuilders.scriptSort(
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "Math.random()", Collections.emptyMap()),
|
||||
ScriptSortType.STRING)))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a deterministic script field does not get cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(topHits("foo").scriptField("bar",
|
||||
new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "5", Collections.emptyMap()))).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Test that a request using a deterministic script sort does not get cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(topHits("foo").sort(
|
||||
SortBuilders.scriptSort(
|
||||
@ -1130,17 +1160,16 @@ public class TopHitsIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
.getMissCount(), equalTo(2L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(topHits("foo")).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
.getMissCount(), equalTo(3L));
|
||||
} finally {
|
||||
assertAcked(client().admin().indices().prepareDelete("cache_test_idx")); // delete this - if we use tests.iters it would fail
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ import static org.elasticsearch.search.aggregations.AggregationBuilders.filter;
|
||||
import static org.elasticsearch.search.aggregations.AggregationBuilders.global;
|
||||
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
|
||||
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.METRIC_SCRIPT_ENGINE;
|
||||
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.RANDOM_SCRIPT;
|
||||
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.SUM_FIELD_PARAMS_SCRIPT;
|
||||
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.SUM_VALUES_FIELD_SCRIPT;
|
||||
import static org.elasticsearch.search.aggregations.metrics.MetricAggScriptPlugin.VALUE_FIELD_SCRIPT;
|
||||
@ -211,10 +212,10 @@ public class ValueCountIT extends ESIntegTestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that a request using a script does not get cached and a request
|
||||
* not using a script does get cached.
|
||||
* Make sure that a request using a deterministic script or not using a script get cached.
|
||||
* Ensure requests using nondeterministic scripts do not get cached.
|
||||
*/
|
||||
public void testDontCacheScripts() throws Exception {
|
||||
public void testScriptCaching() throws Exception {
|
||||
assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long")
|
||||
.setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1))
|
||||
.get());
|
||||
@ -227,10 +228,10 @@ public class ValueCountIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// Test that a request using a script does not get cached
|
||||
// Test that a request using a nondeterministic script does not get cached
|
||||
SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(count("foo").field("d").script(
|
||||
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_FIELD_SCRIPT, Collections.emptyMap())))
|
||||
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, RANDOM_SCRIPT, Collections.emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
@ -239,15 +240,26 @@ public class ValueCountIT extends ESIntegTestCase {
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(0L));
|
||||
|
||||
// To make sure that the cache is working test that a request not using
|
||||
// a script is cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(count("foo").field("d")).get();
|
||||
// Test that a request using a deterministic script gets cached
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0)
|
||||
.addAggregation(count("foo").field("d").script(
|
||||
new Script(ScriptType.INLINE, METRIC_SCRIPT_ENGINE, VALUE_FIELD_SCRIPT, Collections.emptyMap())))
|
||||
.get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(1L));
|
||||
|
||||
// Ensure that non-scripted requests are cached as normal
|
||||
r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(count("foo").field("d")).get();
|
||||
assertSearchResponse(r);
|
||||
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getHitCount(), equalTo(0L));
|
||||
assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache()
|
||||
.getMissCount(), equalTo(2L));
|
||||
}
|
||||
|
||||
public void testOrderByEmptyAggregation() throws Exception {
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.script;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A mocked script used for testing purposes. {@code deterministic} implies cacheability in query shard cache.
|
||||
*/
|
||||
public abstract class MockDeterministicScript implements Function<Map<String, Object>, Object>, ScriptFactory {
|
||||
public abstract Object apply(Map<String, Object> vars);
|
||||
public abstract boolean isResultDeterministic();
|
||||
|
||||
public static MockDeterministicScript asDeterministic(Function<Map<String, Object>, Object> script) {
|
||||
return new MockDeterministicScript() {
|
||||
@Override public boolean isResultDeterministic() { return true; }
|
||||
@Override public Object apply(Map<String, Object> vars) { return script.apply(vars); }
|
||||
};
|
||||
}
|
||||
|
||||
public static MockDeterministicScript asNonDeterministic(Function<Map<String, Object>, Object> script) {
|
||||
return new MockDeterministicScript() {
|
||||
@Override public boolean isResultDeterministic() { return false; }
|
||||
@Override public Object apply(Map<String, Object> vars) { return script.apply(vars); }
|
||||
};
|
||||
}
|
||||
}
|
@ -64,11 +64,22 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
public static final String NAME = "mockscript";
|
||||
|
||||
private final String type;
|
||||
private final Map<String, Function<Map<String, Object>, Object>> scripts;
|
||||
private final Map<String, MockDeterministicScript> scripts;
|
||||
private final Map<ScriptContext<?>, ContextCompiler> contexts;
|
||||
|
||||
public MockScriptEngine(String type, Map<String, Function<Map<String, Object>, Object>> scripts,
|
||||
Map<ScriptContext<?>, ContextCompiler> contexts) {
|
||||
this(type, scripts, Collections.emptyMap(), contexts);
|
||||
}
|
||||
|
||||
public MockScriptEngine(String type, Map<String, Function<Map<String, Object>, Object>> deterministicScripts,
|
||||
Map<String, Function<Map<String, Object>, Object>> nonDeterministicScripts,
|
||||
Map<ScriptContext<?>, ContextCompiler> contexts) {
|
||||
|
||||
Map<String, MockDeterministicScript> scripts = new HashMap<>(deterministicScripts.size() + nonDeterministicScripts.size());
|
||||
deterministicScripts.forEach((key, value) -> scripts.put(key, MockDeterministicScript.asDeterministic(value)));
|
||||
nonDeterministicScripts.forEach((key, value) -> scripts.put(key, MockDeterministicScript.asNonDeterministic(value)));
|
||||
|
||||
this.type = type;
|
||||
this.scripts = Collections.unmodifiableMap(scripts);
|
||||
this.contexts = Collections.unmodifiableMap(contexts);
|
||||
@ -87,34 +98,14 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
public <T extends ScriptFactory> T compile(String name, String source, ScriptContext<T> context, Map<String, String> params) {
|
||||
// Scripts are always resolved using the script's source. For inline scripts, it's easy because they don't have names and the
|
||||
// source is always provided. For stored and file scripts, the source of the script must match the key of a predefined script.
|
||||
Function<Map<String, Object>, Object> script = scripts.get(source);
|
||||
MockDeterministicScript script = scripts.get(source);
|
||||
if (script == null) {
|
||||
throw new IllegalArgumentException("No pre defined script matching [" + source + "] for script with name [" + name + "], " +
|
||||
"did you declare the mocked script?");
|
||||
}
|
||||
MockCompiledScript mockCompiled = new MockCompiledScript(name, params, source, script);
|
||||
if (context.instanceClazz.equals(FieldScript.class)) {
|
||||
FieldScript.Factory factory = (parameters, lookup) ->
|
||||
ctx -> new FieldScript(parameters, lookup, ctx) {
|
||||
@Override
|
||||
public Object execute() {
|
||||
Map<String, Object> vars = createVars(parameters);
|
||||
vars.putAll(getLeafLookup().asMap());
|
||||
return script.apply(vars);
|
||||
}
|
||||
};
|
||||
return context.factoryClazz.cast(factory);
|
||||
} else if (context.instanceClazz.equals(FieldScript.class)) {
|
||||
FieldScript.Factory factory = (parameters, lookup) ->
|
||||
ctx -> new FieldScript(parameters, lookup, ctx) {
|
||||
@Override
|
||||
public Object execute() {
|
||||
Map<String, Object> vars = createVars(parameters);
|
||||
vars.putAll(getLeafLookup().asMap());
|
||||
return script.apply(vars);
|
||||
}
|
||||
};
|
||||
return context.factoryClazz.cast(factory);
|
||||
return context.factoryClazz.cast(new MockFieldScriptFactory(script));
|
||||
} else if(context.instanceClazz.equals(TermsSetQueryScript.class)) {
|
||||
TermsSetQueryScript.Factory factory = (parameters, lookup) -> (TermsSetQueryScript.LeafFactory) ctx
|
||||
-> new TermsSetQueryScript(parameters, lookup, ctx) {
|
||||
@ -149,17 +140,7 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
};
|
||||
return context.factoryClazz.cast(factory);
|
||||
} else if (context.instanceClazz.equals(StringSortScript.class)) {
|
||||
StringSortScript.Factory factory = (parameters, lookup) -> (StringSortScript.LeafFactory) ctx
|
||||
-> new StringSortScript(parameters, lookup, ctx) {
|
||||
@Override
|
||||
public String execute() {
|
||||
Map<String, Object> vars = new HashMap<>(parameters);
|
||||
vars.put("params", parameters);
|
||||
vars.put("doc", getDoc());
|
||||
return String.valueOf(script.apply(vars));
|
||||
}
|
||||
};
|
||||
return context.factoryClazz.cast(factory);
|
||||
return context.factoryClazz.cast(new MockStringSortScriptFactory(script));
|
||||
} else if (context.instanceClazz.equals(IngestScript.class)) {
|
||||
IngestScript.Factory factory = vars -> new IngestScript(vars) {
|
||||
@Override
|
||||
@ -169,37 +150,7 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
};
|
||||
return context.factoryClazz.cast(factory);
|
||||
} else if(context.instanceClazz.equals(AggregationScript.class)) {
|
||||
AggregationScript.Factory factory = (parameters, lookup) -> new AggregationScript.LeafFactory() {
|
||||
@Override
|
||||
public AggregationScript newInstance(final LeafReaderContext ctx) {
|
||||
return new AggregationScript(parameters, lookup, ctx) {
|
||||
@Override
|
||||
public Object execute() {
|
||||
Map<String, Object> vars = new HashMap<>(parameters);
|
||||
vars.put("params", parameters);
|
||||
vars.put("doc", getDoc());
|
||||
vars.put("_score", get_score());
|
||||
vars.put("_value", get_value());
|
||||
return script.apply(vars);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needs_score() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return context.factoryClazz.cast(factory);
|
||||
} else if (context.instanceClazz.equals(IngestScript.class)) {
|
||||
IngestScript.Factory factory = vars ->
|
||||
new IngestScript(vars) {
|
||||
@Override
|
||||
public void execute(Map<String, Object> ctx) {
|
||||
script.apply(ctx);
|
||||
}
|
||||
};
|
||||
return context.factoryClazz.cast(factory);
|
||||
return context.factoryClazz.cast(new MockAggregationScript(script));
|
||||
} else if (context.instanceClazz.equals(IngestConditionalScript.class)) {
|
||||
IngestConditionalScript.Factory factory = parameters -> new IngestConditionalScript(parameters) {
|
||||
@Override
|
||||
@ -242,13 +193,7 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
};
|
||||
return context.factoryClazz.cast(factory);
|
||||
} else if (context.instanceClazz.equals(SignificantTermsHeuristicScoreScript.class)) {
|
||||
SignificantTermsHeuristicScoreScript.Factory factory = () -> new SignificantTermsHeuristicScoreScript() {
|
||||
@Override
|
||||
public double execute(Map<String, Object> vars) {
|
||||
return ((Number) script.apply(vars)).doubleValue();
|
||||
}
|
||||
};
|
||||
return context.factoryClazz.cast(factory);
|
||||
return context.factoryClazz.cast(new MockSignificantTermsHeuristicScoreScript(script));
|
||||
} else if (context.instanceClazz.equals(TemplateScript.class)) {
|
||||
TemplateScript.Factory factory = vars -> {
|
||||
Map<String, Object> varsWithParams = new HashMap<>();
|
||||
@ -282,19 +227,19 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
};
|
||||
return context.factoryClazz.cast(factory);
|
||||
} else if (context.instanceClazz.equals(ScoreScript.class)) {
|
||||
ScoreScript.Factory factory = new MockScoreScript(script);
|
||||
ScoreScript.Factory factory = new MockScoreScript(script::apply);
|
||||
return context.factoryClazz.cast(factory);
|
||||
} else if (context.instanceClazz.equals(ScriptedMetricAggContexts.InitScript.class)) {
|
||||
ScriptedMetricAggContexts.InitScript.Factory factory = mockCompiled::createMetricAggInitScript;
|
||||
ScriptedMetricAggContexts.InitScript.Factory factory = new MockMetricAggInitScriptFactory(script);
|
||||
return context.factoryClazz.cast(factory);
|
||||
} else if (context.instanceClazz.equals(ScriptedMetricAggContexts.MapScript.class)) {
|
||||
ScriptedMetricAggContexts.MapScript.Factory factory = mockCompiled::createMetricAggMapScript;
|
||||
ScriptedMetricAggContexts.MapScript.Factory factory = new MockMetricAggMapScriptFactory(script);
|
||||
return context.factoryClazz.cast(factory);
|
||||
} else if (context.instanceClazz.equals(ScriptedMetricAggContexts.CombineScript.class)) {
|
||||
ScriptedMetricAggContexts.CombineScript.Factory factory = mockCompiled::createMetricAggCombineScript;
|
||||
ScriptedMetricAggContexts.CombineScript.Factory factory = new MockMetricAggCombineScriptFactory(script);
|
||||
return context.factoryClazz.cast(factory);
|
||||
} else if (context.instanceClazz.equals(ScriptedMetricAggContexts.ReduceScript.class)) {
|
||||
ScriptedMetricAggContexts.ReduceScript.Factory factory = mockCompiled::createMetricAggReduceScript;
|
||||
ScriptedMetricAggContexts.ReduceScript.Factory factory = new MockMetricAggReduceScriptFactory(script);
|
||||
return context.factoryClazz.cast(factory);
|
||||
} else if (context.instanceClazz.equals(IntervalFilterScript.class)) {
|
||||
IntervalFilterScript.Factory factory = mockCompiled::createIntervalFilterScript;
|
||||
@ -302,7 +247,7 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
}
|
||||
ContextCompiler compiler = contexts.get(context);
|
||||
if (compiler != null) {
|
||||
return context.factoryClazz.cast(compiler.compile(script, params));
|
||||
return context.factoryClazz.cast(compiler.compile(script::apply, params));
|
||||
}
|
||||
throw new IllegalArgumentException("mock script engine does not know how to handle context [" + context.name + "]");
|
||||
}
|
||||
@ -372,25 +317,6 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
return new MockSimilarityWeightScript(script != null ? script : ctx -> 42d);
|
||||
}
|
||||
|
||||
public ScriptedMetricAggContexts.InitScript createMetricAggInitScript(Map<String, Object> params, Map<String, Object> state) {
|
||||
return new MockMetricAggInitScript(params, state, script != null ? script : ctx -> 42d);
|
||||
}
|
||||
|
||||
public ScriptedMetricAggContexts.MapScript.LeafFactory createMetricAggMapScript(Map<String, Object> params,
|
||||
Map<String, Object> state,
|
||||
SearchLookup lookup) {
|
||||
return new MockMetricAggMapScript(params, state, lookup, script != null ? script : ctx -> 42d);
|
||||
}
|
||||
|
||||
public ScriptedMetricAggContexts.CombineScript createMetricAggCombineScript(Map<String, Object> params,
|
||||
Map<String, Object> state) {
|
||||
return new MockMetricAggCombineScript(params, state, script != null ? script : ctx -> 42d);
|
||||
}
|
||||
|
||||
public ScriptedMetricAggContexts.ReduceScript createMetricAggReduceScript(Map<String, Object> params, List<Object> states) {
|
||||
return new MockMetricAggReduceScript(params, states, script != null ? script : ctx -> 42d);
|
||||
}
|
||||
|
||||
public IntervalFilterScript createIntervalFilterScript() {
|
||||
return new IntervalFilterScript() {
|
||||
@Override
|
||||
@ -471,6 +397,17 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MockMetricAggInitScriptFactory implements ScriptedMetricAggContexts.InitScript.Factory, ScriptFactory {
|
||||
private final MockDeterministicScript script;
|
||||
MockMetricAggInitScriptFactory(MockDeterministicScript script) { this.script = script; }
|
||||
@Override public boolean isResultDeterministic() { return script.isResultDeterministic(); }
|
||||
|
||||
@Override
|
||||
public ScriptedMetricAggContexts.InitScript newInstance(Map<String, Object> params, Map<String, Object> state) {
|
||||
return new MockMetricAggInitScript(params, state, script);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MockMetricAggInitScript extends ScriptedMetricAggContexts.InitScript {
|
||||
private final Function<Map<String, Object>, Object> script;
|
||||
|
||||
@ -493,6 +430,18 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MockMetricAggMapScriptFactory implements ScriptedMetricAggContexts.MapScript.Factory, ScriptFactory {
|
||||
private final MockDeterministicScript script;
|
||||
MockMetricAggMapScriptFactory(MockDeterministicScript script) { this.script = script; }
|
||||
@Override public boolean isResultDeterministic() { return script.isResultDeterministic(); }
|
||||
|
||||
@Override
|
||||
public ScriptedMetricAggContexts.MapScript.LeafFactory newFactory(Map<String, Object> params, Map<String, Object> state,
|
||||
SearchLookup lookup) {
|
||||
return new MockMetricAggMapScript(params, state, lookup, script);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MockMetricAggMapScript implements ScriptedMetricAggContexts.MapScript.LeafFactory {
|
||||
private final Map<String, Object> params;
|
||||
private final Map<String, Object> state;
|
||||
@ -529,11 +478,21 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MockMetricAggCombineScriptFactory implements ScriptedMetricAggContexts.CombineScript.Factory, ScriptFactory {
|
||||
private final MockDeterministicScript script;
|
||||
MockMetricAggCombineScriptFactory(MockDeterministicScript script) { this.script = script; }
|
||||
@Override public boolean isResultDeterministic() { return script.isResultDeterministic(); }
|
||||
|
||||
@Override
|
||||
public ScriptedMetricAggContexts.CombineScript newInstance(Map<String, Object> params, Map<String, Object> state) {
|
||||
return new MockMetricAggCombineScript(params, state, script);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MockMetricAggCombineScript extends ScriptedMetricAggContexts.CombineScript {
|
||||
private final Function<Map<String, Object>, Object> script;
|
||||
|
||||
MockMetricAggCombineScript(Map<String, Object> params, Map<String, Object> state,
|
||||
Function<Map<String, Object>, Object> script) {
|
||||
MockMetricAggCombineScript(Map<String, Object> params, Map<String, Object> state, Function<Map<String, Object>, Object> script) {
|
||||
super(params, state);
|
||||
this.script = script;
|
||||
}
|
||||
@ -551,11 +510,21 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MockMetricAggReduceScriptFactory implements ScriptedMetricAggContexts.ReduceScript.Factory, ScriptFactory {
|
||||
private final MockDeterministicScript script;
|
||||
MockMetricAggReduceScriptFactory(MockDeterministicScript script) { this.script = script; }
|
||||
@Override public boolean isResultDeterministic() { return script.isResultDeterministic(); }
|
||||
|
||||
@Override
|
||||
public ScriptedMetricAggContexts.ReduceScript newInstance(Map<String, Object> params, List<Object> states) {
|
||||
return new MockMetricAggReduceScript(params, states, script);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MockMetricAggReduceScript extends ScriptedMetricAggContexts.ReduceScript {
|
||||
private final Function<Map<String, Object>, Object> script;
|
||||
|
||||
MockMetricAggReduceScript(Map<String, Object> params, List<Object> states,
|
||||
Function<Map<String, Object>, Object> script) {
|
||||
MockMetricAggReduceScript(Map<String, Object> params, List<Object> states, Function<Map<String, Object>, Object> script) {
|
||||
super(params, states);
|
||||
this.script = script;
|
||||
}
|
||||
@ -617,4 +586,88 @@ public class MockScriptEngine implements ScriptEngine {
|
||||
}
|
||||
}
|
||||
|
||||
class MockAggregationScript implements AggregationScript.Factory, ScriptFactory {
|
||||
private final MockDeterministicScript script;
|
||||
MockAggregationScript(MockDeterministicScript script) { this.script = script; }
|
||||
@Override public boolean isResultDeterministic() { return script.isResultDeterministic(); }
|
||||
|
||||
@Override
|
||||
public AggregationScript.LeafFactory newFactory(Map<String, Object> params, SearchLookup lookup) {
|
||||
return new AggregationScript.LeafFactory() {
|
||||
@Override
|
||||
public AggregationScript newInstance(final LeafReaderContext ctx) {
|
||||
return new AggregationScript(params, lookup, ctx) {
|
||||
@Override
|
||||
public Object execute() {
|
||||
Map<String, Object> vars = new HashMap<>(params);
|
||||
vars.put("params", params);
|
||||
vars.put("doc", getDoc());
|
||||
vars.put("_score", get_score());
|
||||
vars.put("_value", get_value());
|
||||
return script.apply(vars);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needs_score() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class MockSignificantTermsHeuristicScoreScript implements SignificantTermsHeuristicScoreScript.Factory, ScriptFactory {
|
||||
private final MockDeterministicScript script;
|
||||
MockSignificantTermsHeuristicScoreScript(MockDeterministicScript script) { this.script = script; }
|
||||
@Override public boolean isResultDeterministic() { return script.isResultDeterministic(); }
|
||||
|
||||
@Override
|
||||
public SignificantTermsHeuristicScoreScript newInstance() {
|
||||
return new SignificantTermsHeuristicScoreScript() {
|
||||
@Override
|
||||
public double execute(Map<String, Object> vars) {
|
||||
return ((Number) script.apply(vars)).doubleValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class MockFieldScriptFactory implements FieldScript.Factory, ScriptFactory {
|
||||
private final MockDeterministicScript script;
|
||||
MockFieldScriptFactory(MockDeterministicScript script) { this.script = script; }
|
||||
@Override public boolean isResultDeterministic() { return script.isResultDeterministic(); }
|
||||
|
||||
@Override
|
||||
public FieldScript.LeafFactory newFactory(Map<String, Object> parameters, SearchLookup lookup) {
|
||||
return ctx -> new FieldScript(parameters, lookup, ctx) {
|
||||
@Override
|
||||
public Object execute() {
|
||||
Map<String, Object> vars = createVars(parameters);
|
||||
vars.putAll(getLeafLookup().asMap());
|
||||
return script.apply(vars);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class MockStringSortScriptFactory implements StringSortScript.Factory, ScriptFactory {
|
||||
private final MockDeterministicScript script;
|
||||
MockStringSortScriptFactory(MockDeterministicScript script) { this.script = script; }
|
||||
@Override public boolean isResultDeterministic() { return script.isResultDeterministic(); }
|
||||
|
||||
@Override
|
||||
public StringSortScript.LeafFactory newFactory(Map<String, Object> parameters, SearchLookup lookup) {
|
||||
return ctx -> new StringSortScript(parameters, lookup, ctx) {
|
||||
@Override
|
||||
public String execute() {
|
||||
Map<String, Object> vars = new HashMap<>(parameters);
|
||||
vars.put("params", parameters);
|
||||
vars.put("doc", getDoc());
|
||||
return String.valueOf(script.apply(vars));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,11 +37,13 @@ public abstract class MockScriptPlugin extends Plugin implements ScriptPlugin {
|
||||
|
||||
@Override
|
||||
public ScriptEngine getScriptEngine(Settings settings, Collection<ScriptContext<?>> contexts) {
|
||||
return new MockScriptEngine(pluginScriptLang(), pluginScripts(), pluginContextCompilers());
|
||||
return new MockScriptEngine(pluginScriptLang(), pluginScripts(), nonDeterministicPluginScripts(), pluginContextCompilers());
|
||||
}
|
||||
|
||||
protected abstract Map<String, Function<Map<String, Object>, Object>> pluginScripts();
|
||||
|
||||
protected Map<String, Function<Map<String, Object>, Object>> nonDeterministicPluginScripts() { return Collections.emptyMap(); }
|
||||
|
||||
protected Map<ScriptContext<?>, MockScriptEngine.ContextCompiler> pluginContextCompilers() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user