Elasticsearch.Nest 教程系列 4-1 映射:Auto 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


类似于 dynamic mapping,在创建索引或通过 Put Mapping API 创建映射时,NEST 提供了一种称为自动映射的功能,该功能可以从正在映射的 CLR POCO 属性类型自动推断出正确的 Elasticsearch 字段数据类型。

一个简单示例:

  • 新建 Document 抽象基类。

  • 新建 Company 类

  • 新建 Employee 类

  • 三者关系如下

Elasticsearch.Nest 教程系列 4 映射

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

  • 官方文档见此: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, bool, number)并进行映射,但无法满足在所有业务场景,显式指定模型映射至关重要。

本章节主要说明如何通过 NEST 将 .NET 中 POCOs 模型的属性跟 ES 中存储的 JSON 文档和字段进行映射。

NEST 提供了如下几种转换方式:

以上几种映射方式可以组合起来以形成整体映射方法。

此外,还有一些控制方法:

Elasticsearch.Nest 教程系列 3-2 序列化:Extending NEST types | 扩展 NEST 类型

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

  • 官方文档见此: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 的默认 JSON 序列化知道如何正确的序列化所有请求和响应类型,以及如何正确处理的你的 .NET 模型类。然而有的时候,你可能需要修改默认行为或者自定义你自己的序列化器,本章节将说明如何自定义以及扩展 NEST 类型。


有时为了解决某些问题,或者因为你使用了扩展了 Elasticsearch 功能的第三方插件,需要你提供某一种类型的自定义实现,而 NEST 并没有提供现成的支持。这个时候就可以通过如下方式来扩展 NEST 的类型使得在某些场景支持:

创建你自己的属性映射

通过实现自定义的 IProperty 实现,将 POCO 属性跟 NEST 字段进行映射。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyPluginProperty : IProperty
{
IDictionary<string, object> IProperty.LocalMetadata { get; set; }
public string Type { get; set; } = "my_plugin_property";
public PropertyName Name { get; set; }

public MyPluginProperty(string name, string language)
{
this.Name = name;
this.Language = language;
this.Numeric = true;
}

[PropertyName("language")]
public string Language { get; set; }

[PropertyName("numeric")]
public bool Numeric { get; set; }
}
  • PropertyNameAttribute 特性用于标记应序列化的属性。如果没有此属性,NEST将不会选择该属性进行序列化。

在创建索引的时候使用自定义的 IProperty 实现

Elasticsearch.Nest 教程系列 3-1 序列化:Custom Serialization | 自定义序列化

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

  • 官方文档见此: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 的默认 JSON 序列化知道如何正确的序列化所有请求和响应类型,以及如何正确处理的你的 .NET 模型类。然而有的时候,你可能需要修改默认行为或者自定义你自己的序列化器,本章节将说明如何自定义以及扩展 NEST 类型。


目前 NEST 客户端已经完全移除了 SimpleJson 和 Newtonsoft.Json,转而使用内置的 Utf8Json—一种直接与 UTF-8 二进制文件直接协同工作的快速序列化器。

随着转而使用 UtfJson,NEST 团队在 7.x 阶段删除了部分原先在之前 NEST 客户端中存在的 JSON 特性,变动如下:

  • 由于性能原因,由 Utf8Json 生成的 JSON 不会缩进。如请求中的 JSON 不会缩进,哪怕指定了 SerializationFormatting.Indented。但 NEST 团队正在考虑公开缩进 JSON 的选项以便于开发和调试。

  • NEST 类型不能通过继承扩展。在 6.x 版本,可以通过派生该类型并注释这些新属性来为该类型包括其他属性。在当前使用 Utf8Json 进行序列化的时候,此方法将不起作用。

  • 序列化器使用 Reflection.Emit,而 Utf8Json 使用 Reflection.Emit 来生成高效的格式化器。但并非所有平台都支持 Reflection.Emit,例如 UWP,Xamarin.iOS 和 Xamarin.Android。

  • Elasticsearch.Net.DynamicResponse 将 JSON 数组反序列化为 List。SimpleJson 将 JSON 数组反序列化为 object[]。但出于分配和性能方面的原因,Utf8Json 将它们反序列化为 List

  • 将 JSON 对象字段名称反序列化为 C# 类的属性时,Utf8Json 更加严格。在 6.x 版本中,内部使用 Json.NET 进行序列化,JSON 对象字段名称会先跟 C# 的类属性名完全匹配的进行匹配,之后再使用不区分大小写的进行匹配。但在 7.x 版本中(使用 Utf8Json 后),名称必须完全匹配。

  • 注入新的序列化器

    通过注入新的序列化器,可以让你在_source,_fields 或希望写入和返回用户提供的值的任何地方对(反)序列化进行调用。

    Elasticsearch.Nest 教程系列 2-4 连接:Working with certificates | 使用凭证连接

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

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


    使用证书

    如果你已经通过 Elastic Stack Security 功能在 Elasticsearch 上启用了SSL,或者在 ES 服务上层的代理上启用了SSL,并且生成证书的证书颁发机构(CA)受运行客户端代码的计算机信任,那么你不需要进行任何操作。

    如果你使用不受信任的 CA 证书(如你自己生成的CA 证书),默认情况下, .NET 不允许你使用 https 请求终结点,不过你可以使用 ServicePointManager.ServerCertificateValidationCallback 来解决这个问题。大部分的示例可能会让你直接返回一个 true,但并不建议你这样做,因为这么设置会允许所有到你应用程序域的 HTTPS 的流量,且无需验证:

    1
    2
    3
    //不建议这么干:
    ServicePointManager.ServerCertificateValidationCallback +=
    (sender, cert, chain, errors) => true
    • 这么设置不会对 HTTPS 连接请求jinxing yanzheng

    配置验证

    可以使用 Elasticsearch.Net 的 ConnectionConfiguration 和使用 NEST 的ConnectionSettings 公开该回调。你也可以在这处理程序中进行自己的验证,也可以使用静态类 CertificateValidations 提供的一些处理器。

    Elasticsearch.Nest 教程系列 2-2 连接:Connection pools | 连接池使用

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

    • 官方文档见此: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 可以使用那些节点来发送客户端的请求。

    • P.S.:此连接池非彼连接池(跟ADO.NET 中的数据库连接池不同),NEST 的连接池并不负责管理跟 ES 服务器的 TCP 连接。

      • 到 ES 服务端的 TCP 连接由 DESKTOP CLR 中的 ServicePointManager 负责,更多关于 ServicePointManager 见此

    ES 中的连接池的作用:负责管理 ES 集群中可以建立连接的节点,并且一个 IConnectionPool 示例与一个 ConnectionSetting 示例相关联(一一对应关联)。

    由于单个 NEST 客户端建议使用’单例’,因此单个连接池实例的生命周期跟应用程序的生命周期相同。

    一共包含以下 5 个类型的连接池

    • SingleNodeConnectionPool

    • CloudConnectionPool

    • StaticConnectionPool

    • SniffingConnectionPool

    • StickyConnectionPool

    SingleNodeConnectionPool

    一般 SingleNodeConnectionPool 适用于集群中只有一个节点或者只有单个复杂均衡实例的情况。

    当没有在 ConnectionSettings 构造函数中显式指定连接池类型的时候,此类型是默认连接池,也是在所有类型中最简单的一种连接池类型。

    Elasticsearch.Nest 教程系列 2-3 连接:Modifying the default connection | 修改默认连接

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

    • 官方文档见此: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 客户端通过 IConnection 发送请求并创建响应,默认实现使用 System.Net.Http.HttpClient。

    有的时候,你希望客制化连接,此时可以通过 InMemoryConnection,HttpConnection 来自定义。

    使用 InMemoryConnection

    InMemoryConnection 是一个内置的 IConnection,可以轻松地对其编写单元测试。通过配置,可以将调用时的默认响应字节、HTTP 状态代码和异常处理进行客制化。

    事实上,InMemoryConnection 并不会发送任何请求或接收来自E lasticsearch 的任何响应:如果将 .DisableDirectStreaming 在全局或请求的时候设置为 true,则此请求仍会序列化,并且可以在响应上获取请求字节。

    1
    2
    3
    4
    5
    6
    7
    8
    var connection = new InMemoryConnection();
    var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
    /*
    1.通过 IConnectionPool 和 IConnection 重载创建一个 ConnectionSettings
    2.connection 使用的是 InMemoryConnection 的无参构造函数,表示为所有相应内容返回 200 状态码,并不真实执行任何 IO 操作。
    */
    var settings = new ConnectionSettings(connectionPool, connection);
    var client = new ElasticClient(settings);

    Elasticsearch.Nest 教程系列 9-1 转换:Index name inference | 索引名推断的3种方式

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

    • 官方文档见此: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 提供了多种方式来推断索引名,不同方式可以同时指定,但相互之间存在优先级关系,具体如下:

    示例

    配置类:

    1
    2
    3
    4
    5
    public class ElasticSearchSettings
    {
    public string ServerUri { get; set; }
    public string DefaultIndex { get; set; } = "defaultindex";
    }

    Elasticsearch.Nest 教程系列 2-1 连接:Configuration options | 配置选项

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

    • 官方文档见此: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 默认情况下使用预设的值与 ElasticSearch 集群进行交互,并提供了许多配置选项和组件来修改默认值(行为)。

    你可以修改 ConnectionConfiguration 和 ConnectionStrings 的属性以达到修改默认连接行为的效果:

    • ConnectionConfiguration:面向 ElasticSearch.Net

    • ConnectionStrings:面向 NEST。

    配置 ConnectionConfiguration

    因为 ConnectionStrings 继承自 ConnectionConfiguration,所以以下选项(方法/属性)适用于 ConnectionConfiguration 和 ConnectionStrings。

    • ApiKeyAuthentication: 与所有请求一起发送到Elasticsearch的 Api Key。

    • BasicAuthentication: 与所有请求一起发送到Elasticsearch的 基本身份验证凭证。

    • ClientCertificate: 为所有 HTTP 请求使用 X509Certificate 认证。你也可以在每一个请求上通过 ClientCertificates 属性来进行设置。

    Elasticsearch.Nest 教程系列 1:Nest 快速入门

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

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


    Elasticsearch.Net 和 NEST 对比说明:

    • Elasticsearch 官方为 .NET 提供了 2 个官方客户端库:Elasticsearch.Net 和 NEST。

    • 可以简单理解为 Elasticsearch.Net 是 NEST 的一个子集。

    • NEST 内部使用了 ElasticSearch.Net ,并通过 NEST 可以对外暴露 ElasticSearch.Net 客户端。

    • 但 NEST 包含了 ElasticSearch.Net 所没有的一些高级功能,如:

      • 强类型查询 DSL:可以将所有请求和响应的对象类型转换 1:1 的.NET 类型。
      • 自动转换为 CLR 的数据类型。

    基本上 .NET 项目到了要使用上 ElasticSearch 的地步,直接选择 NEST 即可。

    在使用 NEST 作为客户端的时候,建议将 ElasticClient 对象作为单例来使用。

    • ElasticClient 被设计为线程安全。

    • ES 中的缓存是根据 ConnectionSettings 来划分的,即服务端缓存针对的是每一个 ConnectionStrings

    • 例外: 当你需要连接不同的 ES 集群的时候,就不要用单例了,应为不同的 ElasticClient 使用不同的 ConnectionStrings。

    快速使用

    • 使用 Nest 的时候约定 Nest 版本需要跟 ElasticSearch 版本保持一致,即服务端 ES版本为 7.3.1,则 Nest 版本也要使用 7.3.1

    • 以下示例通过 IoC 进行注入(单例),你也可以直接通过单例模式来实现。