Elasticsearch.Nest 教程系列 9-8 转换:Routing Inference | 路由推断


有的时候,我们在索引文档的时候,会要求指定 routing,否则会报“[routing] is missing for ….”之类的错误,ES 原生直接通过 ?routing 的形式来进行指定,如:

PUT /index/_doc/1?routing=1  
{
    "parentProperty": "a parent prop",
    "id": 1,
    "parentChildRelation": {
        "name":"myparent"
    }
}

那么在 NEST 中,如何指定 routing?NEST 提供了以下几种方法:

隐式转换

以下数据类型会自动进行隐式转换来显式创建路由:

  • Int32
  • Int64
  • String
  • Guid

以上几个数据类型,在被声明为 Routing 类型的 方法/属性使用的时候,会自动进行隐式转换——转换成 Routing 类型,如下:

Routing routingFromInt = 1;
Routing routingFromLong = 2L;
Routing routingFromString = "hello-world";
Routing routingFromGuid = new Guid("D70BD3CF-4E38-46F3-91CA-FCBEF29B148E");

从类型中推断

你可以在 POCO 中声明一个名为 Routing 的属性(数据类型需要为 Int32/Int64/String/Guid),之后在请求的时候,就会自动映射到 _routing 种。

  • Routing 的默认值为 null

public abstract class MyDocument
{
    public int Id { get; set; }

    public int Routing { get; set; }

    public JoinField ParentChildRelation { get; set; }
}
  • 默认情况下,NEST会尝试通过反射在类上找到一个名为 Routing 的属性,并基于该属性getter 创建一个缓存的委托。

你也可以在 ConnectionSettings 种,通过 DefaultMappingFor.RoutingProperty 来显式指定 Routing,如下:

var settings = new ConnectionSettings(new Uri(_esSettings.ServerUri))
    .DefaultMappingFor<MyDocument>(m => m.IndexName("index").RoutingProperty(rp => rp.Id))
    .DefaultMappingFor<MyChild>(m => m.IndexName("index").RoutingProperty(rp => rp.Id))
    .DefaultMappingFor<MyParent>(m => m.IndexName("index").RoutingProperty(rp => rp.Id));
  • 这里指定 Id 为 routing 的值。
  • 另外需要注意,每个 ConnectionSettings 实例会缓存推导规则。
    • 鉴于此,可以用不同的 ConnectionSettings 来推导不同的规则。

JoinField

如果你的类包含一个 JoinField 类型的属性,那么 Nest 会自动将 父Id 作为 _routing 的值。更多关于子父级的使用可以见此博文:NEST 教程系列 4-5 映射:Parent/Child relationships | 子父级关系映射

  • 一个类不能包含多个 JoinField 类型的属性,否则会异常。

class MyOtherDTO
{
    public JoinField SomeJoinField { get; set; }
    public Int Id { get; set; }
    public string Name { get; set; }
    public string OtherName { get; set; }
}

声明一个父文档,NEST 会自动将 Id 推导为 routing 的值:

var parent = new MyOtherDTO
{
    SomeJoinField = JoinField.Root<MyOtherDTO>(),
    Id = 8080
    Name = "x",
    OtherName = "y"
};

声明一个子文档,并连接上方的父文档:

var dto = new MyOtherDTO
{
    SomeJoinField = JoinField.Link<MyOtherDTO>("8080"),
    Id = new Guid("D70BD3CF-4E38-46F3-91CA-FCBEF29B148E"),
    Name = "x",
    OtherName = "y"
};
  • 将 MyOtherDTO 实例跟 父Id 为 8080 的相连接

不同方式配置 routing 推断的优先级顺序

  • 在 ConnectionSettings 上配置的路由属性优先级最高。