.NET Elasticsearch教程:序列化

NEST默认通过内置的JSON序列化解析器来处理POCO的请求和响应,如果要更改其中的行为或者想提供自己的序列化器,有下面两种方式:

  • 自定义序列化器(Custom Serialization)
  • 扩展NEST类型(Extending Nest Types)

 

1.自定义序列化器(Custom Serialization)

在NEST 7.x版本中,SimpleJson和Newtonsoft.Json已经被Utf8Json取代,Utf8Json是直接基于UTF-8工作的快速JSON序列化器,在迁移到Utf8Json的过程中,删除了之前JSON库中提供的一些特性,这些特性已被证明过于繁重,在新版本中将不再使用。下面是对在NEST 7.x 中使用 Utf8Json 的一些说明:

  • 序列化格式,由于性能原因,Utf8Json不会对生成的JSON文本进行缩进。
  • 不能通过继承来扩展嵌套类型,Utf8Json不支持这种方式。
  • Utf8Json会使用Reflection.Emit进行反射,但不是所有的平台都支持Emit,如UWP、Xamarin.iOS和Xamarin.Android。
  • Elasticsearch.NET.DynamicResponse进行JSON序列化时将 array 转化为 List<>,SimpleJson将 array 序列化为 object[],出于性能的考虑,Utf8Json会和DynamicResponse保持一致,将 array 转换为 List<>。
  • 将JSON中的对象字段反序列化为c# POCO属性时,Utf8Json的限制比Json.NET严格得多,Utf8Json需要JSON字段名和C# POCO类型的属性名大小写完全匹配。

1.1.注入一个序列化器

你可以注入一个单独的序列化程序,用于对源数据进行序列化,在NEST中,将他称为 SourceSerializer。

在NEST内部还有一个内置的序列化程序 RequestResponseSerialize 负责处理请求和响应的序列化,如果没有配置 SourceSerializer,则直接由 RequestResponseSerializer 来处理。

要注入一个 SourceSerializer需要实现 IElasticsearchSerializer 接口。

public class VanillaSerializer : IElasticsearchSerializer
{
    public T Deserialize<T>(Stream stream) => throw new NotImplementedException();

    public object Deserialize(Type type, Stream stream) => throw new NotImplementedException();

    public Task<T> DeserializeAsync<T>(Stream stream, CancellationToken cancellationToken = default(CancellationToken)) =>
        throw new NotImplementedException();

    public Task<object> DeserializeAsync(Type type, Stream stream, CancellationToken cancellationToken = default(CancellationToken)) =>
        throw new NotImplementedException();

    public void Serialize<T>(T data, Stream stream, SerializationFormatting formatting = SerializationFormatting.Indented) =>
        throw new NotImplementedException();

    public Task SerializeAsync<T>(T data, Stream stream, SerializationFormatting formatting = SerializationFormatting.Indented,
        CancellationToken cancellationToken = default(CancellationToken)) =>
        throw new NotImplementedException();
}

在创建 ConnectionSettings 时设置

var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var connectionSettings = new ConnectionSettings(
    pool,
    sourceSerializer: (builtin, settings) => new VanillaSerializer()); 
var client = new ElasticClient(connectionSettings);

如果被序列化的POCO类型包含嵌套类型(如下面的类),自定义的序列化程序无法处理,需要有一种方法将嵌套类型的序列化委托给Nest的序列化程序。

public class MyPercolationDocument
{
    public QueryContainer Query { get; set; }
    public string Category { get; set; }
}

这时,就需要用NEST 提供的 JsonNetSerializer 将嵌套类的序列化委托给NEST的序列化程序。

使用 JsonNetSerializer 的方式如下:

var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var connectionSettings =
    new ConnectionSettings(pool, sourceSerializer: (builtin, settings) => new JsonNetSerializer(
        builtin, settings,
        () => new JsonSerializerSettings { NullValueHandling = NullValueHandling.Include },
        resolver => resolver.NamingStrategy = new SnakeCaseNamingStrategy()
    ));
var client = new ElasticClient(connectionSettings);

1.2.派生序列化器

在 JsonNetSerializer 中进行太多设置的话会不太直观,这时可以直接继承 ConnectionSettingsAwareSerializerBase 类并重写 CreateJsonSerializerSettings() 和 ModifyContractResolver() 方法实现一个序列化器。

public class MyFirstCustomJsonNetSerializer : ConnectionSettingsAwareSerializerBase
{
    public MyFirstCustomJsonNetSerializer(IElasticsearchSerializer builtinSerializer, IConnectionSettingsValues connectionSettings)
        : base(builtinSerializer, connectionSettings) { }

    protected override JsonSerializerSettings CreateJsonSerializerSettings() =>
        new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Include
        };

    protected override void ModifyContractResolver(ConnectionSettingsAwareContractResolver resolver) =>
        resolver.NamingStrategy = new SnakeCaseNamingStrategy();
}

下面演示使用 MyFirstCustomJsonNetSerializer 进行序列化:

//定义POCO
public class MyDocument
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string FilePath { get; set; }

    public int OwnerId { get; set; }

    public IEnumerable<MySubDocument> SubDocuments { get; set; }
}

public class MySubDocument
{
    public string Name { get; set; }
}

//创建连接
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var connectionSettings = new ConnectionSettings(
    pool,
    connection: new InMemoryConnection(), 
    sourceSerializer: (builtin, settings) => new MyFirstCustomJsonNetSerializer(builtin, settings))
    .DefaultIndex("my-index");

var client = new ElasticClient(connectionSettings);

//实例化POCO
var document = new MyDocument
{
    Id = 1,
    Name = "My first document",
    OwnerId = 2
};

var ndexResponse = client.IndexDocument(document);

序列化结果:

{
  "id": 1,
  "name": "My first document",
  "file_path": null,
  "owner_id": 2,
  "sub_documents": null
}

2.扩展 NEST 类型

创建属性,实现 IProperty 接口

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; }
}

在创建索引时将其添加到属性映射中

var createIndexResponse = _client.Indices.Create("myindex", c => c
    .Map<Project>(m => m
        .Properties(props => props
            .Custom(new MyPluginProperty("fieldName", "dutch"))
        )
    )
);

会生成下面的JSON请求数据:

{
  "mappings": {
    "properties": {
      "fieldName": {
        "type": "my_plugin_property",
        "language": "dutch",
        "numeric": true
      }
    }
  }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值