使用NEST 2.x创建具有多字段映射语法的索引

时间:2016-02-11 21:33:33

标签: c# elasticsearch nest

我似乎无法在NEST 2.0中获得多字段映射的语法 - 如果这是正确的术语。我发现用于映射的每个例子似乎都是< = NEST的1.x版本。我是Elasticsearch和NEST的新手,我一直在阅读他们的文档,但NEST文档还没有完全更新2.x。

基本上,我不需要索引或存储整个类型。我需要一些字段仅用于索引,有些字段我需要索引和检索,有些字段我不需要索引,只是为了检索。

MyType
{
    // Index this & allow for retrieval.
    int Id { get; set; } 

    // Index this & allow for retrieval.
    // **Also**, in my searching & sorting, I need to sort on this **entire** field, not just individual tokens.
    string CompanyName { get; set; } 

    // Don't index this for searching, but do store for display.
    DateTime CreatedDate { get; set; }

    // Index this for searching BUT NOT for retrieval/displaying.
    string CompanyDescription { get; set; } 

    // Nest this.
    List<MyChildType> Locations { get; set; }
}

MyChildType
{
    // Index this & allow for retrieval.
    string LocationName { get; set; }

    // etc. other properties.
}

能够使用以下内容作为示例对整个对象和子项进行索引:

client.Index(item, i => i.Index(indexName));

然而,实际对象比这个要大很多,我真的不需要大部分。我发现了这个,看起来就像我想要做的那样,但在旧版本中:multi field mapping elasticsearch

我认为&#34;映射&#34;是我想要的,但就像我说的,我是Elasticsearch和NEST的新手,我正在努力学习术语。

温柔! :)这是我第一次在SO上提问。谢谢!

4 个答案:

答案 0 :(得分:6)

据我所见,你没有任何复杂的类型,你正在尝试映射。因此,您可以轻松使用NEST属性来映射对象。

检查出来:

[Nest.ElasticsearchType]
public class MyType
{
    // Index this & allow for retrieval.
    [Nest.Number(Store=true)]
    int Id { get; set; }

    // Index this & allow for retrieval.
    // **Also**, in my searching & sorting, I need to sort on this **entire** field, not just individual tokens.
    [Nest.String(Store = true, Index=Nest.FieldIndexOption.Analyzed, TermVector=Nest.TermVectorOption.WithPositionsOffsets)]
    string CompanyName { get; set; }

    // Don't index this for searching, but do store for display.
    [Nest.Date(Store=true, Index=Nest.NonStringIndexOption.No)]
    DateTime CreatedDate { get; set; }

    // Index this for searching BUT NOT for retrieval/displaying.
    [Nest.String(Store=false, Index=Nest.FieldIndexOption.Analyzed)]
    string CompanyDescription { get; set; }

    [Nest.Nested(Store=true, IncludeInAll=true)]
    // Nest this.
    List<MyChildType> Locations { get; set; }
}

[Nest.ElasticsearchType]
public class MyChildType
{
    // Index this & allow for retrieval.
    [Nest.String(Store=true, Index = Nest.FieldIndexOption.Analyzed)]
    string LocationName { get; set; }

    // etc. other properties.
}

在此声明之后,要在elasticsearch中创建此映射,您需要进行类似于以下的调用:

var mappingResponse = elasticClient.Map<MyType>(m => m.AutoMap());

使用AutoMap()调用NEST将从您的POCO中读取您的属性并相应地创建映射请求。

另请参阅here中的“基于属性的映射”部分。

干杯!

答案 1 :(得分:6)

除了Colin'sSelçuk's答案之外,您还可以通过fluent(和对象初始化程序语法)映射API完全控制映射。以下是基于您的要求的示例

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

    var client = new ElasticClient(connectionSettings);

    client.Map<MyType>(m => m
        .Index("index-name")
        .AutoMap()
        .Properties(p => p
            .String(s => s
                .Name(n => n.CompanyName)
                .Fields(f => f
                    .String(ss => ss
                        .Name("raw")
                        .NotAnalyzed()
                    )
                )
            )
            .Date(d => d
                .Name(n => n.CreatedDate)
                .Index(NonStringIndexOption.No)         
            )
            .String(s => s
                .Name(n => n.CompanyDescription)
                .Store(false)
            )
            .Nested<MyChildType>(n => n
                .Name(nn => nn.Locations.First())
                .AutoMap()
                .Properties(pp => pp
                    /* properties of MyChildType */
                )
            )
        )
    );
}

public class MyType
{
    // Index this & allow for retrieval.
    public int Id { get; set; }

    // Index this & allow for retrieval.
    // **Also**, in my searching & sorting, I need to sort on this **entire** field, not just individual tokens.
    public string CompanyName { get; set; }

    // Don't index this for searching, but do store for display.
    public DateTime CreatedDate { get; set; }

    // Index this for searching BUT NOT for retrieval/displaying.
    public string CompanyDescription { get; set; }

    // Nest this.
    public List<MyChildType> Locations { get; set; }
}

public class MyChildType
{
    // Index this & allow for retrieval.
    public string LocationName { get; set; }

    // etc. other properties.
}

这会产生映射

{
  "properties": {
    "id": {
      "type": "integer"
    },
    "companyName": {
      "type": "string",
      "fields": {
        "raw": {
          "type": "string",
          "index": "not_analyzed"
        }
      }
    },
    "createdDate": {
      "type": "date",
      "index": "no"
    },
    "companyDescription": {
      "type": "string",
      "store": false
    },
    "locations": {
      "type": "nested",
      "properties": {
        "locationName": {
          "type": "string"
        }
      }
    }
  }
}

调用.AutoMap()会导致NEST根据属性类型和应用于它们的任何属性推断映射。然后.Properties()覆盖任何推断的映射。例如

  • CompanyName被映射为multi_field,其中使用标准分析器分析了字段companyName,并且未分析companyName.raw。您可以使用.Field(f => f.CompanyName.Suffix("raw"))
  • 在查询中引用后者
  • Locations被映射为nested类型(默认情况下自动将其推断为object类型映射)。然后,您可以使用MyChildType调用内的.Properties()Nested<MyChildType>()定义任何特定的映射。

答案 2 :(得分:3)

在撰写本文时, Nest 不提供使用内置属性将类中的属性映射到文档映射中的多个字段的方法。但是,如果您自己编写JSON,它确实提供了对映射执行任何操作所需的工具。

这是我为自己的需求而整理的解决方案。不管你需要做什么都不应该用它作为起点。

首先,这是我想要生成的映射的一个例子

{
   "product":{
      "properties":{
         "name":{
            "type":"string",
            "index":"not_analyzed",
            "fields":{
               "standard":{
                  "type":"string",
                  "analyzer":"standard"
               }
            }
         }
      }
   }
}

product文档将包含已被编入索引但尚未分析的name字段,以及使用标准分析器的name.standard字段。

我生成映射的C#类看起来像这样

[ElasticsearchType]
public class Product
{
    [WantsStandardAnalysisField]
    public string Name { get; set; }
}

请注意WantsStandardAnalysisField属性。这是一个自定义属性,没有添加任何特殊属性。字面意思是:

public class WantsStandardAnalysisField : Attribute {}

如果我按原样使用AutoMap,我的自定义属性将被忽略,我会得到一个包含name字段但不是name.standard的映射。幸运的是,AutoMap接受IPropertyVisitor的实例。名为NoopPropertyVisitor的基类实现了接口并且什么都不做,因此您可以对其进行子类化并仅覆盖您关心的方法。当您使用具有AutoMap的属性访问者时,它将为您生成文档映射,但在将其发送到Elastic Search之前,您有机会对其进行修改。我们需要做的就是查找标有自定义属性的属性,并为其添加一个字段。

以下是一个例子:

public class ProductPropertyVisitor : NoopPropertyVisitor
{
    public override void Visit(IStringProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute)
    {
        base.Visit(type, propertyInfo, attribute);

        var wsaf = propertyInfo.GetCustomAttribute<WantsStandardAnalysisField>();
        if (wsaf != null)
        {
            type.Index = FieldIndexOption.NotAnalyzed;
            type.Fields = new Properties
            {
                {
                    "standard",
                    new StringProperty
                    {
                        Index = FieldIndexOption.Analyzed,
                        Analyzer = "standard"
                    }
                }
            };
        }
    }
}

正如您所看到的,我们可以使用生成的属性执行任何我们想要的任何操作,包括关闭主属性的分析并添加具有自己设置的新字段。为了好玩,您可以向自定义属性添加一些属性,以允许您指定所需字段的名称以及要使用的分析器。您甚至可以修改代码以查看属性是否已多次添加,让您可以根据需要添加任意数量的字段。

如果您通过使用AutoMap生成映射的任何方法运行此操作,例如:

new TypeMappingDescriptor<Product>().AutoMap(new ProductPropertyVisitor())

您将获得所需的多字段映射。现在,您可以根据自己的内容自定义映射。享受!

答案 3 :(得分:0)

我认为你至少有两种可能性来解决你的问题:

  1. 关于索引:创建类似元数据模型的东西,仅存储用于检索。请参阅_source field以限制返回此字段。
  2. 搜索时:指定要查询的字段:如果您不想查询CreatedDate,请不要将其包含在搜索中。
  3. 在我的情况下,我使用这两种方法来获得非常快速的结果: - )