Elasticsearch NEST使用空嵌套对象

时间:2015-12-22 21:04:57

标签: elasticsearch nest

尝试重置"文档中的嵌套对象,但不会将其设置为空。

我有一个POCO:

public class StreetAddress 
{
    public int HouseNumber { get; set; }
    public string Street { get; set; }
}

public class FullAddress
{
    public string City{ get; set; }

    public string State { get; set; }

    public StreetAddress StreetAddress { get; set; }

    public int Zip { get; set; }

    public List<string> Codes { get; set; }
}

所以目前如果我为FullAddress创建了这个新文档并且已经设置了StreetAddress,那么在查询时文档就像这样:

"_source": {          
    "city": "Los Angeles",          
    "state": "California",          
    "zip": 90019,            
    "streetAddress": {            
        "houseNumber": 1,
        "street": "Apple Street"          
    },
    "codes" : [
        { "la-601" }
    ]     
}

现在我想调用NEST客户端更新来重置StreetAddress嵌套对象:

StreetAddress localStreetAddress = new StreetAddress();

var partialAddress = new 
{ 
    City = "NewCity",
    Zip = 11111,
    StreetAddress = localStreetAddress
};

this._client.Update<ElasticsearchProject, object>(update => update
    .Id(1) 
    .Doc(partialAddress)
);

我在查询之前希望的最终结果是在上述更新调用之后:

"_source": {          
    "city": "NewCity",          
    "state": "California",          
    "zip": 11111,            
    "streetAddress": {}     
}

但是,部分更新会做两件不受欢迎的事情:

  1. 它只更新City和Zip字段并离开StreetAddress 就像以前一样,并没有清除它为空或空。
  2. 它将代码清单清除为空,因为部分更新不包含该清单。
  3. 我知道我可以将StreetAddress设置为null并添加JSON属性以包含null,如下所示:

    [JsonProperty(NullValueHandling = NullValueHandling.Include)]
    public StreetAddress StreetAddress { get; set; }
    

    但是所有这一切都会导致文档更新将其设置为null而不是为空,我不确定这是否是文档的预期结果:

    "_source": {          
            "city": "NewCity",          
            "state": "California",          
            "zip": 11111,            
            "streetAddress": null     
        }
    

    不确定是否有办法在不下载脚本路径的情况下进行部分更新,以将嵌套对象设置为空。

1 个答案:

答案 0 :(得分:0)

Nested objects实际上是在Elasticsearch中映射为单独的隐藏文档,正如您所发现的,默认情况下NEST配置为不通过空值发送。最终结果是嵌套类型不受您对顶级属性的部分更新的影响。

处理此问题的一种方法是在没有StreetAddress的情况下重新索引文档。无论如何,更新本质上是删除并插入幕后。

作为一个例子

void Main()
{
    var settings = new ConnectionSettings(new Uri("http://localhost:9200"), "address");

    var client = new ElasticClient(settings);

    // create the index
    client.CreateIndex("address", c => c
        .AddMapping<FullAddress>(m => m
            .MapFromAttributes()
        )
    );

    // index our document
    client.Index(new FullAddress
    {
        City = "Los Angeles",
        State = "California",
        Zip = 90019,
        Codes = new List<string>
        {
            "la-601"
        },
        StreetAddress = new StreetAddress
        {
            HouseNumber = 1,
            Street = "Apple Street"
        }
    }, c => c.Id(1));

    // Now at some later point, we need to update it,
    // so get the current document
    var response = client.Get<FullAddress>(1);

    // make the changes to the current document
    var address = response.Source;
    address.StreetAddress = null;

    // and re-index
    client.Index<FullAddress>(address, c => c.Id(1));
}

public class StreetAddress
{
    public int HouseNumber { get; set; }
    public string Street { get; set; }
}

public class FullAddress
{
    public string City { get; set; }

    public string State { get; set; }

    public StreetAddress StreetAddress { get; set; }

    public int Zip { get; set; }

    public List<string> Codes { get; set; }
}

最终结果符合预期

{
  "_index": "address",
  "_type": "fulladdress",
  "_id": "1",
  "_version": 2,
  "found": true,
  "_source": {
    "city": "Los Angeles",
    "state": "California",
    "zip": 90019,
    "codes": [
      "la-601"
    ]
  }
}

您也可以在执行此操作时使用optimistic concurrency control来处理getindex之间的任何更改。