Class QuerySettingDef<T>
java.lang.Object
org.elasticsearch.xpack.esql.plan.QuerySettingDef<T>
The typed handle for one ES|QL query setting. Declared as a
public static final
constant on QuerySettings.
Mental model
A setting is a typed knob. Users always supply it via in-querySET. For tooling that
builds requests programmatically, a setting can also be exposed in the request body. We declare
the knob once; the framework wires both surfaces, resolves precedence automatically
(default < body < SET), and gives downstream code one typed read.
What you specify
Required:- a name — used as both the
SETkey and the body key, - a value type — picked by choosing a factory.
withDefault— value readers see when no source supplied one;withRequestBody— opt the setting into the body undersettings.<name>;withAliasAtRoot/withAliasAt— extra body paths, used only for BWC with settings whose top-level body fields predate this framework (time_zone,project_routing,approximation);withValidator— value-level check with runtime context;withReconciler— custom cross-source merge (see Reconciliation);withPreview,withSnapshotOnly,withServerlessOnly— lifecycle.
SET dispatch, the precedence fold
(default < body < SET, applied per setting via its reconciler), the read API. The one thing
you write outside the declaration is adding the constant to QuerySettings.ALL to register it.
How to declare a setting
- Pick a factory matching the value type.
- Chain only the modifiers you need.
- End with
build(), which validates and constructs the setting; add its constant toQuerySettings.ALLto register it.
1. SET-only
Accepted in queries asSET foo='x';. Not reachable from the body.
public static final QuerySettingDef<String> FOO = QuerySettingDef.string("foo").build();
2. SET + body parameter
Also accepted as"settings": { "bar": "x" }. Tooling that constructs the body without
splicing the query string uses this form.
public static final QuerySettingDef<String> BAR = QuerySettingDef
.string("bar").withDefault("hello").withRequestBody().build();
3. SET + body parameter + legacy top-level alias
Same as case 2, plus accepted at the top-level body field. Reserved for BWC with the three settings whose top-level fields predate this framework.
public static final QuerySettingDef<ZoneId> TIME_ZONE = QuerySettingDef
.string("time_zone", s -> ZoneId.of(s).normalized())
.withDefault(ZoneOffset.UTC)
.withRequestBody()
.withAliasAtRoot()
.build();
4. Structured value with a custom reconciler
Use this shape when aSET and a body contribution each fill different fields and
you want them combined rather than last-wins.
public static final QuerySettingDef<ApproximationSettings> APPROXIMATION = QuerySettingDef
.object("approximation", ApproximationSettings::fromXContent, ApproximationSettings::parse)
.withRequestBody()
.withAliasAtRoot()
.withReconciler((prev, cur) ->
new ApproximationSettings.Builder(false).merge(prev).merge(cur).build())
.streamFormat((out, value) -> value.writeTo(out), ApproximationSettings::new) // object/builder must set this
.build();
Reading
ZoneId tz = QuerySettings.TIME_ZONE.get(resolved);
Reconciliation
The same setting can arrive from default, body, andSET in one query, so reconciliation
is unavoidable. The framework folds the three in ascending precedence
default < body < SET. The default fold is last-wins — correct for any scalar. Override
with withReconciler only when a structured value's fields should combine across sources
rather than replace.
Factories
string(String), string(String, FromString) (function errors surface as the
user-visible message), bool(String), object(String, JsonReader, ExpressionReader),
builder(String).
When things go wrong
Three places things can fail, and each behaves the way the consumer of that surface should expect.- Build time.
build()refuses an incoherent declaration — for example, a body-exposed setting that has no JSON reader. The node won't start, so these surface at boot rather than in production. - Parse time. An unknown key is a typo the client can act on, so both surfaces reject it — the body
path with a 400 naming the field, the
SETpath with aParsingException. A known-but-deprecated key (seeQuerySettingDef.Builder.withDeprecated(java.lang.String)) is accepted with a deprecation warning on either surface. Type mismatches throw on either path. - Resolve time. A
snapshotOnlysetting supplied on a non-snapshot build throws. If a validator was declared, it runs against the resolved value with access to cluster context (snapshot-mode flag, cross-project mode, etc).
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classFluent builder forQuerySettingDef.static interfacestatic interfacestatic interfacestatic final recordA body-side alias path for a setting outside the canonicalsettings.{}block.static interfacestatic interface -
Method Summary
Modifier and TypeMethodDescriptionaliases()static QuerySettingDef.Builder<Boolean> static <T> QuerySettingDef.Builder<T> Direct entry point for a setting whose factory above doesn't fit.canonicalize(T value) Coerce a value into this setting's canonical form.A human-readable deprecation message, ornullif the setting is not deprecated.get(ResolvedSettings settings) name()static <T> QuerySettingDef.Builder<T> object(String name, QuerySettingDef.JsonReader<T> jsonReader, QuerySettingDef.ExpressionReader<T> expressionReader) Escape hatch for non-primitive types.booleanpreview()readFromExpression(Expression value) readFromJson(XContentParser parser) readValue(StreamInput in) Deserialize the typed value of this setting from the stream.booleanrunValidator(T value, SettingsValidationContext ctx) booleanbooleanstatic QuerySettingDef.Builder<String> static <T> QuerySettingDef.Builder<T> string(String name, QuerySettingDef.FromString<T> from) type()voidwriteValue(StreamOutput out, T value) Serialize the typed value of this setting to the stream.
-
Method Details
-
string
-
string
public static <T> QuerySettingDef.Builder<T> string(String name, QuerySettingDef.FromString<T> from) -
bool
-
object
public static <T> QuerySettingDef.Builder<T> object(String name, QuerySettingDef.JsonReader<T> jsonReader, QuerySettingDef.ExpressionReader<T> expressionReader) Escape hatch for non-primitive types. Supply both a JSON and an expression parser. -
builder
Direct entry point for a setting whose factory above doesn't fit. -
canonicalize
Coerce a value into this setting's canonical form. Applied on every write into a resolved view (the resolver,ResolvedSettings.withOverride(org.elasticsearch.xpack.esql.plan.QuerySettingDef<T>, T), and theResolvedSettings(StreamInput)wire reader), so a value reaches consumers in one shape no matter which surface supplied it — e.g.time_zonenormalizesZoneIds so"UTC"and"Z"compare equal. Defaults to identity.nullpasses through untouched. -
name
-
type
-
defaultValue
-
requestBody
public boolean requestBody() -
aliases
-
preview
public boolean preview() -
snapshotOnly
public boolean snapshotOnly() -
serverlessOnly
public boolean serverlessOnly() -
deprecationMessage
A human-readable deprecation message, ornullif the setting is not deprecated. A deprecated setting keeps working — it is still resolved and applied — but supplying it (viaSETor the request body) emits this text as a deprecation warning. Deprecation is distinct from removal: a removed setting drops out of the registry and is then rejected as unknown, whereas a deprecated one stays known and merely warns, so clients relying on it are not broken. -
reconciler
-
get
-
readFromJson
- Throws:
IOException
-
readFromExpression
-
runValidator
-
writeValue
Serialize the typed value of this setting to the stream. Used byResolvedSettings.writeTo(org.elasticsearch.common.io.stream.StreamOutput).- Throws:
IOException
-
readValue
Deserialize the typed value of this setting from the stream. Used byResolvedSettings(StreamInput).- Throws:
IOException
-