路由值
当 Elasticsearch 将文档存储到具有多个分片的索引中时,它会根据文档的 id 确定要使用的分片。有时需要预先指定多个文档应索引到同一个分片上(连接类型、对相关数据的更快搜索)。为此,Elasticsearch 提供了定义路由的能力,即用于计算分片的值,而不是使用 id。
Spring Data Elasticsearch 以以下方式在存储和检索数据时支持路由定义:
连接类型上的路由
在使用连接类型时(请参阅连接类型实现),Spring Data Elasticsearch 会自动使用实体 JoinField 属性的 parent 属性作为路由值。
对于父子关系只有一层的所有用例,这都是正确的。如果关系更深,例如子-父-祖父关系——如上面的 vote → answer → question 示例——那么就需要使用下一节所述的技术显式指定路由(vote 需要使用 question.id 作为路由值)。
自定义路由值
要为实体定义自定义路由,Spring Data Elasticsearch 提供了 @Routing 注解(复用上面的 Statement 类):
@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...
}
这将 "routing" 定义为路由规范
一个名为 routing 的属性
如果注解的 routing 规范是一个普通字符串而不是 SpEL 表达式,它会被解释为实体的一个属性名,在本例中即 routing 属性。该属性的值随后将用作该实体所有请求的路由值。
也可以在 @Document 注解中像这样使用 SpEL 表达式:
@Document(indexName = "statements")
@Routing("@myBean.getRouting(#entity)")
public class Statement{
// all the needed stuff
}
在这种情况下,用户需要提供一个名为 myBean 的 Bean,它具有 String getRouting(Object) 方法。要在 SpEL 表达式中引用实体,必须使用 "#entity",且返回值必须为 null 或作为字符串的路由值。
如果普通属性名和 SpEL 表达式还不足以自定义路由定义,可以提供 RoutingResolver 接口的实现。然后可以在 ElasticOperations 实例上设置它:
RoutingResolver resolver = ...;
ElasticsearchOperations customOperations= operations.withRouting(resolver);
withRouting() 函数返回原始 ElasticsearchOperations 实例的一个副本,并带上自定义的路由设置。
当实体存储到 Elasticsearch 时定义了路由,那么在执行 get 或 delete 操作时必须提供相同的值。对于不使用实体的方法——例如 get(ID) 或 delete(ID)——可以像这样使用 ElasticsearchOperations.withRouting(RoutingResolver) 方法:
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);
RoutingResolver.just(s)返回一个解析器,它只会返回给定的字符串。