使用高级Nest Client和AutoMap进行PUT映射

时间:2019-04-04 00:11:15

标签: c# elasticsearch nest

我正在使用以下代码段创建Elasticsearch索引:

ICreateIndexResponse createIndexResponse = elasticClient.CreateIndex(IndexName, c => c
    .Mappings(ms => ms
        .Map<Document>(m => m.AutoMap())
    )
);

Document类是具有属性映射的POCO。

我希望能够将字段添加到映射中。使用Put Mapping API似乎可以实现:

PUT my_index 
{
  "mappings": {
    "_doc": {
      "properties": {
        "name": {
          "properties": {
            "first": {
              "type": "text"
            }
          }
        },
        "user_id": {
          "type": "keyword"
        }
      }
    }
  }
}

PUT my_index/_mapping/_doc
{
  "properties": {
    "name": {
      "properties": {
        "last": { 
          "type": "text"
        }
      }
    },
    "user_id": {
      "type": "keyword",
      "ignore_above": 100 
    }
  }
}

https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html

请注意,第一个PUT正在创建索引和映射。第二个PUT是添加和修改字段。我希望能够执行第二个PUT。

理想的方案是将属性添加到我的Document类中,调用AutoMap,然后使用客户端调用PUT Mapping API。新属性将添加到我的映射中,并且适当时会更新/忽略以前存在的属性。

这可能吗?我是否应该使用某些参数再次调用CreateIndex方法?

1 个答案:

答案 0 :(得分:1)

Put Mapping API在客户端上显示为.Map<T>

var client = new ElasticClient();

var putMappingResponse = client.Map<Document>(m => m
    .AutoMap()
);

这将自动映射Document的所有属性。我相信Elasticsearch只会简单地对已经存在的那些映射不做任何操作,并添加新的映射。

如果您只想发送那些尚未映射的属性,则可以通过获取Document的自动映射属性,从索引中检索映射来实现,除了从前者发送,然后将其与.Map<T>()发送。像

var defaultIndex = "properties_example";
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));

var settings = new ConnectionSettings(pool)
    .DefaultIndex(defaultIndex);

var client = new ElasticClient(settings);

if (!client.IndexExists(defaultIndex).Exists)
{
    var createIndexResponse = client.CreateIndex(defaultIndex, c => c
        .Mappings(m => m
            .Map<Document>(mm => mm.AutoMap())
        )
    );
}

var properties = new PropertyWalker(typeof(Document), null).GetProperties();

// will use the index inferred for Document, or the default index if none
// specified. Can specify an index on this call if you want to  
var getMappingResponse = client.GetMapping<Document>();

var indexedMappings = getMappingResponse
    // Use the index name to which the call was made.
    .Indices[defaultIndex]
    .Mappings[typeof(Document)]
    .Properties;

var propertiesToIndex = new Dictionary<PropertyName, IProperty>();  
foreach(var property in properties)
{
    if (!indexedMappings.ContainsKey(property.Key))
    {
        propertiesToIndex.Add(property.Key, property.Value);
    }
}

// map new properties only if there are some to map
if (propertiesToIndex.Any())
{
    var request = new PutMappingRequest<Document>()
    {
        Properties = new Properties(propertiesToIndex)
    };

    var putMappingResponse = client.Map(request);
}