首页 > 解决方案 > 使用嵌套客户端将嵌套属性复制到弹性搜索中的父对象

问题描述

如何将嵌套属性复制到索引映射定义中包含 POCO 的字段中?

当两个字段处于同一对象级别时,我能够成功地将一个属性复制到另一个属性中。.CopyTo

但是,我正在努力将嵌套对象上的属性复制到父对象上的属性中。

鉴于以下对象,我想将 Person 的 Address 属性中的“Street”复制到 Person 的“Search”属性中

Person
{
    public string Search { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
}

Address 
{
    public string Street { get; set; }
}

将“姓氏”映射到“搜索”很简单,如下所示。

.Map<Person>(map => map
                .AutoMap()
                .Properties(properties => properties
                .Text(text => 
                    text.Name(name => name.LastName)
                        .CopyTo(copyTo => 
                            copyTo.Field(field => field.Search)
                        )
                    )
                )

但是我无法弄清楚将“Person.Address.Street”复制到“Person.Search”的嵌套语法

标签: elasticsearchnest

解决方案


这是你可以做到的

private static void Main()
{
    var defaultIndex = "my_index";
    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)
        client.DeleteIndex(defaultIndex);

    var createIndexResponse = client.CreateIndex(defaultIndex, c => c
        .Settings(s => s
            .NumberOfShards(1)
            .NumberOfReplicas(0)
        )
        .Mappings(m => m
            .Map<Person>(mm => mm
                .AutoMap()
                .Properties(p => p
                    .Object<Address>(o => o
                        .Name(n => n.Address)
                        .AutoMap()
                        .Properties(pp => pp
                            .Text(t => t
                                .Name(nn => nn.Street)
                                .CopyTo(co => co
                                    .Field(Infer.Field<Person>(ff => ff.Search))
                                )
                            )
                        )
                    )
                )
            )
        )
    );

    var indexResponse = client.Index(new Person
        {
            LastName = "foo",
            Address = new Address
            {
                Street = "bar"
            }
        } , i => i
        .Refresh(Refresh.WaitFor)
    );

    var searchResponse = client.Search<Person>(s => s
        .Query(q => q
            .Match(m => m
                .Field(f => f.Search)
                .Query("bar")
            )
        )
    );
}

public class Person
{
    public string Search { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
}

本质上

  1. 自动映射Person属性
  2. Address将属性显式映射到Person
  3. 自动映射Address属性
  4. 显式映射Street属性并设置CopyTo(...). 此时,泛型类型参数就是Address类型,所以要么需要使用Nest.Infer.Field<T>来访问 的Search属性Person,要么使用字符串。

搜索返回预期的文档

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "my_index",
        "_type" : "person",
        "_id" : "5tQDEWgBrKRHlz9qAve8",
        "_score" : 0.2876821,
        "_source" : {
          "lastName" : "foo",
          "address" : {
            "street" : "bar"
          }
        }
      }
    ]
  }
}

copy_toElasticsearch 中的字段不一定需要作为 C# POCO 上的属性公开,因为_source不会包含它们的值。然而,作为属性公开可能对强类型字段访问很有用。


推荐阅读