Elasticsearch.Nest 教程系列 5-3 索引:Ingest Pipeline | Ingest 管道

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

  • 官方文档见此: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


Ingest 管道是一系列按照声明的顺序执行的处理器。

假设有以下 POCO 类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string IpAddress { get; set; }
public GeoIp GeoIp { get; set; }
}

public class GeoIp
{
public string CityName { get; set; }
public string ContinentName { get; set; }
public string CountryIsoCode { get; set; }
public GeoLocation Location { get; set; }
public string RegionName { get; set; }
}

创建一个 Ingestion 管道:
eg:假设为 Person 文档建立索引,创建一个 Ingestion 管道,在被索引到 ES 之前对其进行相关操作:

  • 将 LastName 转换为大写

  • 将姓名的首字母索引到其他字段—这里用 initials 字段

  • 将 IpAddress 转换为具体地址。

Elasticsearch.Nest 教程系列 5-2 索引:Ingest Node | 使用 Ingest 节点

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

  • 官方文档见此: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


Ingest Node 的作用

在文档索引发生之前,会使用 Ingest 节点进行预处理文档。Ingest 节点会拦截批量和索引请求,之后应用转换(mapping),然后将文档传递回索引或 Bulk API。

  • 即:在数据被索引之前,通过预定义好的处理管道对数据进行预处理。

默认情况下,所有节点都启用 Ingest,也就是说任何节点都可以处理 Ingest 任务。

  • 当然,你也可以创建某些业务专用的 Ingest 节点。

Elasticsearch 会将自动将索引请求重新路由到 Ingest 节点,而您可以优化此路径。

Elasticsearch.Nest 教程系列 5-1 索引:Indexing | 索引(添加)文档

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

  • 官方文档见此: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


索引(Indexing):是指讲文档添加到 ES 中的过程,目前 Nest 提供了以下 3 种 Indexing 方式:

  • Indexing Documents
  • Ingest Node
  • Ingest Pipelines

NEST 提供了多种索引文档的方式:

假设有 Person 类:

1
2
3
4
5
6
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}

Elasticsearch.Nest 教程系列 4-7 映射:Multi fields | 多字段映射

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

  • 官方文档见此: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


在 ES 中,多字段映射是很有用的,如:

  • 一个 string 类型的属性会被推断为 ES 的 包含 keyword 子字段的 text 数据类型,其中:

    • text 数据类型适用于全文搜索。
    • keyword 适用于结构搜索、排序以及聚合。
  • 另外多字段映射适用于不同的分析器,以满足不同的全文本搜索需求。

假设有如下模型类:

1
2
3
4
public class Person
{
public string Name { get; set; }
}

Elasticsearch.Nest 教程系列 4-6 映射:Ignoring properties | 映射时忽略 POCO 上的某些属性

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

  • 官方文档见此: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


POCO 类属性进行映射时,可以通过以下几种方式忽略部分属性

  • 在使用继承了 ElasticsearchPropertyAttributeBase 的各特性上使用 Ignore 属性:如在使用 TextAttribute 时,使用 Ingore 属性进行属性忽略。

  • 在使用 PropertyNameAttribute 的时候使用Ignore属性。

  • 使用 ConnectionSettings.DefaultMappingFor(Func<ClrTypeMappingDescriptor,
    IClrTypeMapping> selector) 方法的时候进行指定需要忽略的属性。

  • 使用能够被 IElasticsearchSerializer 识别的 Ignore 特性,内建的 SourceSerializer 可以使用 [IgnoreAttribute] 进行忽略。

忽略类中的部分属性

示例:

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 类型,如下:

Elasticsearch.Nest 教程系列 4-5 映射:Parent/Child relationships | 子父级关系映射

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

  • 官方文档见此: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


如果把 官方示例 放在你本地进行测试,会发现没有问题,但当你连接测试 ES 服务器的时候,就会报各种错误:

  • 这是因为官方使用了 InMemoryConnection ,所有请求并不会真实发送到测试 ES 服务器,规避掉了不少现实问题。以下示例基于官方文档进行了修正,使用本地搭建测试 ES 服务器。

父子关系的数据结构,在日常开发过程中,使用还是比较平凡的:

  • 在 ES 6.x 之前,你可以在一个索引中包含多种 type(类型)。通过给定类型的特殊 _parent 字段映射,可以创建 1对N 关系 的父-子文档。

    • 通过这种方式在索引子项时,你需要传递一个 _parent id 作为路由键(需要确保父项、其子项及所有祖先都保存在同一个分片上)。
  • 但从 ES 6.x 开始,type 不再支持多类型,固定 _type=_doc。(另外在 ES5 的时候,ES 的 index 相当于 DB,_type 相当于 DB 中的表名,但从 ES7 开始,ES 的 index 相当于 DB中的表,_type 固定为 _doc)

嵌套对象和父子结构文档的差异对比和使用建议:

Nested Object Parent/Child
优点 文档存储再一起,读取性能高 父子文档可以独立更新
缺点 更新嵌套的子文档时,需要更新整个文档 需要额外的内存维护关系。读取性能相对差
适用场景 子文档偶尔更新,以查询为主 子文档更新频繁

既然索引不再允许将不同 _type 类型存储在同一索引中,那么如何创建父联接?

Elasticsearch.Nest 教程系列 4-4 映射:through the Visitor Pattern | 通过访问者模式进行映射

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

  • 官方文档见此: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


通过访问者模式,可以对所有或者特定的属性进行应用转换。

.AutoMap() 方法内部实现了 Visitor Pattern,默认访问者 NoopPropertyVisitor 不执行任何操作,并允许你实现自己的访问方法。

常规使用:

示例:自定义一个访问者,以禁用数字和布尔类型的 doc 值:

1
2
3
4
5
6
7
8
9
10
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Salary { get; set; }
public DateTime Birthday { get; set; }
public bool IsManager { get; set; }
public List<Employee> Employees { get; set; }
public TimeSpan Hours { get; set; }
}

Elasticsearch.Nest 教程系列 4-3 映射:Fluent mapping | 通过 lambda 表达式流畅映射

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

  • 官方文档见此: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


Fluent mapping 允许你可以最大程度地控制 POCOs 到 ES 字段的映射。你可以认为这种方式类似于 Automapper 中通过 CreateMap<T1, T2>().ForMember 来显式指定属性之间的映射。Fluent mapping 同样需要你显式指定每一个 POCO 属性跟 ES 字段的映射关系。

下面使用 Company 和 Employee 这 2 个 类来进行演示,两者之间的关系如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Company
{
public string Name { get; set; }
public List<Employee> Employees { get; set; }
}

public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Salary { get; set; }
public DateTime Birthday { get; set; }
public bool IsManager { get; set; }
public List<Employee> Employees { get; set; }
public TimeSpan Hours { get; set; }
}

Elasticsearch.Nest 教程系列 4-2 映射:Attribute mapping | 通过特性进行映射

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

  • 官方文档见此: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


使用自动映射的时候,NEST 会将 POCO 模型属性的数据类型自动推断出对应的 ES 数据类型。同样,NEST 也提供了一系列特性,方便你进行一些定制。

唯一需要注意的是,虽然使用特性进行了映射,但依然需要调用 .AutoMap() 方法,以便在特性上自定义的值生效。

示例:

在 Employee 和 Skill 类上使用特性