在 Elasticsearch Nest 中将一种类型映射到另一种类型

In Elasticsearch Nest mapping one type to another

我正在使用 elasticsearch nest C# 库来映射文档。除了我拥有的自定义类型 TypeX 之外,一切都很顺利,它被视为对象并存储为 { }。

此自定义类型是 v1 uuid,本质上被视为 Guid。老实说,我想将它转换为 Guid 用于存储目的,因为它隐式地来回转换。因此 elastic 会将其视为 Guid 而不是 TypeX。

根据 attribute mapping 部分,我似乎可以通过这种方式更改类型,但是我真的不想将 Nest 公开为我的类型的依赖项,因为它在许多地方使用。

是否可以从连接或索引设置此映射以将 TypeX 映射到 Guid 并将 Guid 映射到 TypeX?

嵌套:6.0.1

ES: 6.2.2

您可以使用流畅映射而不是属性映射(属性映射的下一页 link)

System.Guid 被映射为 keyword 数据类型,使用 NEST 进行自动映射。鉴于以下文件

public class MyDocument
{
    public Guid UserId { get; set; }
}

和以下映射

var client = new ElasticClient();

var createIndexResponse = client.CreateIndex("foo", c => c
    .Mappings(m => m
        .Map<MyDocument>(mm => mm
            .AutoMap()
        )
    )
);

会产生

{
  "mappings": {
    "mydocument": {
      "properties": {
        "userId": {
          "type": "keyword"
        }
      }
    }
  }
}

现在,对于要映射为 keyword 类型的您自己的类型,如果您不想将 POCO 属性化,则可以使用流畅的映射。鉴于以下 POCO 和自定义 Uuid 类型

public class Uuid
{
    private string _value;

    public Uuid(string value) => _value = value;

    public override string ToString() => _value;
}

public class MyDocument
{
    public Uuid UserId { get; set; }
}

这些可以映射为

var createIndexResponse = client.CreateIndex("foo", c => c
    .Mappings(m => m
        .Map<MyDocument>(mm => mm
            .AutoMap()
            .Properties(p => p
                .Keyword(k => k
                    .Name(n => n.UserId)
                )
            )
        )
    )
);

生成与以前相同的映射。然而,这只是故事的一半,因为我们还需要控制Uuid的序列化和反序列化方式,使其序列化为JSONstring 并且可以从 string 构造一个实例。在 NEST 6.x 中,我们需要 use our own serializer for this,因为 NEST 使用的序列化程序是内部的。

NEST.JsonSerializer nuget package 包含一个使用 Json.NET 的自定义序列化程序,因此您可以编写一个 JsonConverter 来处理 Uuid 类型的序列化

public class UuidConverter : JsonConverter
{
    public override bool CanConvert(Type objectType) =>
        typeof(Uuid).IsAssignableFrom(objectType);

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) =>
        reader.TokenType == JsonToken.String
            ? new Uuid((string)reader.Value)
            : null;

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value != null)
            writer.WriteValue(value.ToString());
        else
            writer.WriteNull();       
    }
}

private static void Main()
{
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));

    // configure NEST to use Json.NET for serialization of your documents
    // and register a custom converter to handle Uuid type
    var settings = new ConnectionSettings(pool, (builtin, s) => 
        new JsonNetSerializer(builtin, s, contractJsonConverters:
            new [] { new UuidConverter() }
        ))
        .DefaultIndex("foo");

    var client = new ElasticClient(settings);

    var createIndexResponse = client.CreateIndex("foo", c => c
        .Mappings(m => m
            .Map<MyDocument>(mm => mm
                .AutoMap()
                .Properties(p => p
                    .Keyword(k => k
                        .Name(n => n.UserId)
                    )
                )
            )
        )
    );

    var document = new MyDocument
    {
        UserId = new Uuid("123e4567-e89b-12d3-a456-426655440000")  
    };

    var indexResponse = client.IndexDocument(document);
}

文档索引请求随后将 Uuid 序列化为字符串

POST http://localhost:9200/foo/mydocument
{
  "userId": "123e4567-e89b-12d3-a456-426655440000"
}