The {es} API has a lot of variant types: queries, aggregations, field mappings, analyzers, and so on. Finding the correct class name in such large collections can be challenging.
The {java-client} builders make this easy: the builders for variant types, such as
Query
, have methods for each of the available implementations. We’ve seen this
in action above with intervals
(a kind of query) and allOf
, match
and
anyOf
(various kinds of intervals).
This is because variant objects in the {java-client} are implementations of a
“tagged union”: they contain the identifier (or tag) of the variant they hold
and the value for that variant. For example, a Query
object can contain an
IntervalsQuery
with tag intervals
, a TermQuery
with tag term
, and so on.
This approach allows writing fluent code where you can let the IDE completion
features guide you to build and navigate complex nested structures:
Variant builders have setter methods for every available implementation. They use the same conventions as regular properties and accept both a builder lambda expression and a ready-made object of the actual type of the variant. Here’s an example to build a term query:
include-tagged::{doc-tests-src}/api_conventions/ApiConventionsTest.java[variant-creation]
-
Choose the
term
variant to build a term query. -
Build the terms query with a builder lambda expression.
-
Build the
Query
that now holds aTermQuery
object of kindterm
.
Variant objects have getter methods for every available implementation. These
methods check that the object actually holds a variant of that kind and return
the value downcasted to the correct type. They throw an IllegalStateException
otherwise. This approach allows writing fluent code to traverse variants.
include-tagged::{doc-tests-src}/api_conventions/ApiConventionsTest.java[variant-navigation]
Variant objects also provide information on the variant kind they currently hold:
-
with
is
methods for each of the variant kinds:isTerm()
,isIntervals()
,isFuzzy()
, etc. -
with a nested
Kind
enumeration that defines all variant kinds.
This information can then be used to navigate down into specific variants after checking their actual kind:
include-tagged::{doc-tests-src}/api_conventions/ApiConventionsTest.java[variant-kind]
-
Test if the variant is of a specific kind.
-
Test a larger set of variant kinds.
-
Get the kind and value held by the variant object.
{es} accepts plugins that can extend the available variants for a number of types. This includes queries, aggregations, text analyzers and tokenizers, ingest processors, etc.
The {java-client} classes for these types accept a _custom
variant in addition to the builtin ones. This allows you to use these plugin-defined extensions by providing arbitrary JSON in requests, and also receive arbitrary JSON produced by the plugins in responses.
In the examples below we use a hypothetical plugin that adds a sphere-distance
aggregation that groups documents containing 3D coordinates according to their distance to a reference location.
To create a custom aggregation, use the _custom()
aggregation type and provide its identifier, defined by the plugin, and parameters. The parameters can be any object or value that can be serialized to JSON. In the example below we use a simple map:
include-tagged::{doc-tests-src}/api_conventions/ApiConventionsTest.java[custom-variant-creation]
-
Parameters for the custom aggregation.
-
Create a custom aggregation named
neighbors
of kindsphere-distance
with its parameters.
The results of custom variants are returned as raw JSON represented by a JsonData
object. You can then traverse the JSON tree to get the data. Since this is not always convenient, you can also define classes that represent that JSON data and deserialize them from the raw JSON.
Traversing the JSON tree:
include-tagged::{doc-tests-src}/api_conventions/ApiConventionsTest.java[custom-variant-navigation-json]
-
Use
Void
if you’re only interested in aggregation results, not search hits (see also [aggregations]). -
Get the
neighbors
aggregation result as custom JSON result. -
Traverse the JSON tree to extract the result data.
Using a class that represents the custom aggregation results:
include-tagged::{doc-tests-src}/api_conventions/ApiConventionsTest.java[custom-variant-navigation-typed]
-
Deserialize the custom JSON to a dedicated
SphereDistanceAggregate
class.
Where SphereDistanceAggregate
can be defined as follows:
include-tagged::{doc-tests-src}/api_conventions/ApiConventionsTest.java[custom-variant-types]
{doc-tests-blurb}