分类:backend

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


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

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

示例:

在 Employee 和 Skill 类上使用特性

Elasticsearch.Nest 教程系列 4-1 映射:Auto mapping | 自动映射


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

一个简单示例:

  • 新建 Document 抽象基类。
  • 新建 Company 类
  • 新建 Employee 类
  • 三者关系如下

Elasticsearch.Nest 教程系列 4 映射


虽然 ES 可以自动推断部分类型(如 string, bool, number)并进行映射,但无法满足在所有业务场景,显式指定模型映射至关重要。

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

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

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

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

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

NEST 的默认 JSON 序列化知道如何正确的序列化所有请求和响应类型,以及如何正确处理的你的 .NET 模型类。然而有的时候,你可能需要修改默认行为或者自定义你自己的序列化器,本章节将说明如何自定义以及扩展 NEST 类型。


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

创建你自己的属性映射

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

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 | 自定义序列化

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 | 使用凭证连接


使用证书

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

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

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

配置验证

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

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


连接池是一个内部机制,它主要关注于集群中注册的节点以及判断 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 | 修改默认连接


NEST 客户端通过 IConnection 发送请求并创建响应,默认实现使用 System.Net.Http.HttpClient。

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

使用 InMemoryConnection

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

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

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种方式


NEST 提供了多种方式来推断索引名,不同方式可以同时指定,但相互之间存在优先级关系,具体如下:

示例

配置类:

public class ElasticSearchSettings
{
    public string ServerUri { get; set; }
    public string DefaultIndex { get; set; } = "defaultindex";
}

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


NEST 默认情况下使用预设的值与 ElasticSearch 集群进行交互,并提供了许多配置选项和组件来修改默认值(行为)。

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

  • ConnectionConfiguration:面向 ElasticSearch.Net。
  • ConnectionStrings:面向 NEST。

配置 ConnectionConfiguration

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

  • ApiKeyAuthentication: 与所有请求一起发送到Elasticsearch的 Api Key。
  • BasicAuthentication: 与所有请求一起发送到Elasticsearch的 基本身份验证凭证。
  • ClientCertificate: 为所有 HTTP 请求使用 X509Certificate 认证。你也可以在每一个请求上通过 ClientCertificates 属性来进行设置。