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

  • 本系列博文是“伪”官方文档翻译(更加本土化),并非完全将官方文档进行翻译,而是在查阅、测试原始文档并转换为自己真知灼见后的“准”翻译。有不同见解 / 说明不周的地方,还请海涵、不吝拍砖 :)

  • 官方文档见此:https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/introduction.html

  • 本系列对应的版本环境:ElasticSearch@7.3.1,NEST@7.3.1,IDE 和开发平台默认为 VS2019,.NET CORE 2.1


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

1
2
3
4
5
6
7
8
PUT /index/_doc/1?routing=1  
{
"parentProperty": "a parent prop",
"id": 1,
"parentChildRelation": {
"name":"myparent"
}
}

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

隐式转换

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

  • Int32

  • Int64

  • String

  • Guid

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

1
2
3
4
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

1
2
3
4
5
6
7
8
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,如下:

1
2
3
4
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 类型的属性,否则会异常。
1
2
3
4
5
6
7
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 的值:

1
2
3
4
5
6
7
var parent = new MyOtherDTO
{
SomeJoinField = JoinField.Root<MyOtherDTO>(),
Id = 8080
Name = "x",
OtherName = "y"
};

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

1
2
3
4
5
6
7
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 上配置的路由属性优先级最高。