Create index with multi field mapping syntax with NEST 2.x

前端 未结 4 1276
野趣味
野趣味 2021-02-09 21:54

I just can\'t seem to get the syntax correct for multi field mapping in NEST 2.0--if that\'s the correct terminology. Every example I\'ve found for mapping seems to be <= the

4条回答
  •  悲哀的现实
    2021-02-09 22:43

    At the time of writing, Nest does not offer a way to map a property in your class to multiple fields in your document mapping using built in attributes. However, it does provide the facilities needed to do anything with your mappings that you could do if you wrote the JSON yourself.

    Here's a solution I've put together for my own needs. It shouldn't be hard to use it as the starting point for whatever you need to do.

    First, here's an example of the mapping I want to generate

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

    The product document would then have the name field, which is indexed but not analyzed, and the name.standard field, which uses the standard analyzer.

    The C# class that I generate the mapping from looks like this

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

    Note the WantsStandardAnalysisField attribute. That's a custom attribute with no special properties added. Literally just:

    public class WantsStandardAnalysisField : Attribute {}
    

    If I were to use AutoMap as-is, my custom attribute would be ignored and I would get a mapping that has the name field, but not name.standard. Luckily, AutoMap accepts an instance of IPropertyVisitor. A base class called NoopPropertyVisitor implements the interface and does nothing at all, so you can subclass it and override only the methods you care about. When you use a property visitor with AutoMap, it will generate a document mapping for you but give you a chance to modify it before it gets sent to Elastic Search. All we need to do is look for properties marked with our custom attribute and add a field to them.

    Here's an example that does that:

    public class ProductPropertyVisitor : NoopPropertyVisitor
    {
        public override void Visit(IStringProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute)
        {
            base.Visit(type, propertyInfo, attribute);
    
            var wsaf = propertyInfo.GetCustomAttribute();
            if (wsaf != null)
            {
                type.Index = FieldIndexOption.NotAnalyzed;
                type.Fields = new Properties
                {
                    {
                        "standard",
                        new StringProperty
                        {
                            Index = FieldIndexOption.Analyzed,
                            Analyzer = "standard"
                        }
                    }
                };
            }
        }
    }
    

    As you can see, we can do pretty much anything we want with the generated property, including turning off analysis for the main property and adding a new field with its own settings. For fun, you could add a couple properties to the custom attribute allowing you to specify the name of the field you want and the analyzer to use. You could even modify the code to see if the attribute has been added multiple times, letting you add as many fields as you want.

    If you were to run this through any method that generates a mapping using AutoMap, such as:

    new TypeMappingDescriptor().AutoMap(new ProductPropertyVisitor())
    

    You'll get the desired multi-field mapping. Now you can customize mappings to your heart's content. Enjoy!

提交回复
热议问题