How do I map a single .NET type to multiple nested

2020-03-08 08:58发布

问题:

I'm using the NEST library to interact with ElasticSearch, and I'm trying to figure out a way to build index types/nested objects based on non-type data. The type has the following basic structure.

 public class Entity : DynamicObject
 {
        public string Id { get; set; }
        // a bunch of other simple properties

        public override IEnumerable<string> GetDynamicMemberNames()
        {
                return Data.Select(x => x.Name);
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {

            var dictionary = Data.First(x => x.Name == binder.Name);
            result = dictionary;
            return true;
        }

        // each instance of one these should be a nested object type
        public IList<NestedType> Data { get; set; } 

        public class NestedType
        {
            // How do I make Name be the nest type name?
            public string Name { get; set; }
            public IDictionary<string, string> Values { get; set; } 
        }
}

I want to create a nested object/type for each instance of NestedType. So if there are two instances of NestedType, there will then be two nested objects. I can inherit NestedType from DynamicObject to turn the dictionary into "real" properties that NEST then maps correctly (i.e., turn each dictionary key into a property). The problem is that I can't figure out how to set the name/type of the nested object.

There are two ways to map names that I know of: ElasticType attribute and NestedObject fluent interface. The problem here is that there is a single type that represents multiple nested object types. I could do some runtime type building, but I'd rather not if I can avoid it.

Is there a way to have a method or property be used as the nested object's name/type? Or is there a better approach to mapping this type of data to ElasticSearch (hopefully via NEST)?

Thanks! Erick

EDIT

I updated the entity definition to reflect what I'm doing (using DynamicObject to get the JsonSerializer to do what I want). What I want is the ability for the different dictionaries to have different mappings, (different stemming, analyzers, etc). If there were proper types, I could use the NEST fluent syntax to set it up, but when using dynamic, there is no type for the fluent API to use. Ultimately, I want to mix the fluent API with a string based on strings instead of types. Does this make sense?

回答1:

If I understand correctly your intention, Entity object will have only nested objects in it, won't it?

You can try to use dynamic mapping functionality of elasticsearch for entity object. I assume Entity is a root object.

curl -X POST localhost:9200/myindex/entity/_mapping
{"dynamic_templates": [
    {"nested_data_template": {
        "mapping": {
            "type": "nested" },
        "match_mapping_type": "object",
        "path_match": "*" }}]}

path_match: * and match_mapping_type: object mean that for all field names with object as a value nested type mapping will be applied.

Using NEST and Fluent API you can use the following API. IntelliSense will guide you how to build mapping above. ;)

descriptor.DynamicTemplates(DynamicTemplatesDescriptor<Entity>)

Every time when a new property matching this template appears, elasticsearch will update mapping based on dynamic mapping. After a while your mapping will look like:

{
  "entity": {
    "mappings": {
      "entity": {
        "dynamic_templates": [
          {
            "nested_data_template": {
              "mapping": {
                "type": "nested"
              },
              "match_mapping_type": "object",
              "path_match": "*"
            }
          }
        ],
        "properties": {
          "test": {
            "type": "nested",
            "properties": {
              "test": {
                "type": "string"
              },
              "another_property": {
                "type": "string"
              }
            }
          },
          "test1": {
            "type": "nested",
            "properties": {
              "test": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  }
}

Hope this will help!