Routing values

When Elasticsearch stores a document in an index that has multiple shards, it determines the shard to you use based on the id of the document. Sometimes it is necessary to predefine that multiple documents should be indexed on the same shard (join-types, faster search for related data). For this Elasticsearch offers the possibility to define a routing, which is the value that should be used to calculate the shard from instead of the id.

Spring Data Elasticsearch supports routing definitions on storing and retrieving data in the following ways:

Routing on join-types

When using join-types (see Join-Type implementation), Spring Data Elasticsearch will automatically use the parent property of the entity’s JoinField property as the value for the routing.

This is correct for all the use-cases where the parent-child relationship has just one level. If it is deeper, like a child-parent-grandparent relationship - like in the above example from voteanswerquestion - then the routing needs to explicitly specified by using the techniques described in the next section (the vote needs the question.id as routing value).

Custom routing values

To define a custom routing for an entity, Spring Data Elasticsearch provides a @Routing annotation (reusing the Statement class from above):

@Document(indexName = "statements")
@Routing("routing")                  (1)
public class Statement {
    @Id
    private String id;

    @Field(type = FieldType.Text)
    private String text;

    @JoinTypeRelations(
        relations =
            {
                @JoinTypeRelation(parent = "question", children = {"answer", "comment"}),
                @JoinTypeRelation(parent = "answer", children = "vote")
            }
    )
    private JoinField<String> relation;

    @Nullable
    @Field(type = FieldType.Keyword)
    private String routing;          (2)

    // getter/setter...
}
1 This defines "routing" as routing specification
2 a property with the name routing

If the routing specification of the annotation is a plain string and not a SpEL expression, it is interpreted as the name of a property of the entity, in the example it’s the routing property. The value of this property will then be used as the routing value for all requests that use the entity.

It is also possible to us a SpEL expression in the @Document annotation like this:

@Document(indexName = "statements")
@Routing("@myBean.getRouting(#entity)")
public class Statement{
    // all the needed stuff
}

In this case the user needs to provide a bean with the name myBean that has a method String getRouting(Object). To reference the entity "#entity" must be used in the SpEL expression, and the return value must be null or the routing value as a String.

If plain property’s names and SpEL expressions are not enough to customize the routing definitions, it is possible to define provide an implementation of the RoutingResolver interface. This can then be set on the ElasticOperations instance:

RoutingResolver resolver = ...;

ElasticsearchOperations customOperations= operations.withRouting(resolver);

The withRouting() functions return a copy of the original ElasticsearchOperations instance with the customized routing set.

When a routing has been defined on an entity when it is stored in Elasticsearch, the same value must be provided when doing a get or delete operation. For methods that do not use an entity - like get(ID) or delete(ID) - the ElasticsearchOperations.withRouting(RoutingResolver) method can be used like this:

String id = "someId";
String routing = "theRoutingValue";

// get an entity
Statement s = operations
                .withRouting(RoutingResolver.just(routing))       (1)
                .get(id, Statement.class);

// delete an entity
operations.withRouting(RoutingResolver.just(routing)).delete(id);
1 RoutingResolver.just(s) returns a resolver that will just return the given String.