访问者模式映射

1191 发布于: 2021-04-14 读完约需 2 分钟

NEST中,可以对所有属性或者指定属性进行映射转换。

.AutoMap()方法内部实现了访问者模式,默认的访问者是NoopPropertyVisitor,它只提供了一个空白的访问者实现,并没有任何方法,这样你可以允许你实现自已的访问者方法。

在以下示例中,将创建一个禁用文档数字和布尔值的访问者类—这可能不符合实际应用程序的场景,仅仅为了示例。

先定义一个Employee的实体类:

public class Employee
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Salary { get; set; }
    public DateTime Birthday { get; set; }
    public bool IsManager { get; set; }
    public List<Employee> Employees { get; set; }
    public TimeSpan Hours { get; set; }
}

在创建一个自定义的访问者类DisableDocValuePropertyVisitor,它继承自NoopPropertyVisitor,并重写Visit方法:

public class DisableDocValuesPropertyVisitor : NoopPropertyVisitor
{
    public override void Visit(
        INumberProperty type,
        PropertyInfo propertyInfo,
        ElasticsearchPropertyAttributeBase attribute) 
    {
        type.DocValues = false; // 重写INumberProperty参数的Visit方法,以禁用文档的数字
    }

    public override void Visit(
        IBooleanProperty type,
        PropertyInfo propertyInfo,
        ElasticsearchPropertyAttributeBase attribute) 
    {
        type.DocValues = false; // 重写IBooleanProperty参数的Visit方法,以禁用文档的布尔值
    }
}

现在使用自定义的访问者DisableDocValuePropertyVisitor来进行映射:

var createIndexResponse = client.Indices.Create("myindex", c => c
    .Map<Employee>(m => m.AutoMap(new DisableDocValuesPropertyVisitor()))
);

以后在进行实体(本例为Employee)的任何属性映射时,只要是数字或者布尔值的属性,doc_values都将被映射成禁用状态,如下:

{
  "mappings": {
    "properties": {
      "birthday": {
        "type": "date"
      },
      "employees": {
        "properties": {},
        "type": "object"
      },
      "firstName": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "isManager": {
        "doc_values": false,
        "type": "boolean"
      },
      "lastName": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      "salary": {
        "doc_values": false,
        "type": "integer"
      },
      "hours": {
        "doc_values": false,
        "type": "long"
      }
    }
  }
}

访问PropertyInfo属性

NEST重写访问者时,还可以直接访问PropertyInfo属性,而不是访问IProperty类型。

比如,下面这个示例将所有CLR类型映射成了Elasticsearch中的text类型:

public class EverythingIsATextPropertyVisitor : NoopPropertyVisitor
{
    public override IProperty Visit(PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) => new TextProperty();
}

var createIndexResponse = client.Indices.Create("myindex", c => c
        .Map<Employee>(m => m.AutoMap(new EverythingIsATextPropertyVisitor()))
    );
{
  "mappings": {
    "properties": {
      "birthday": {
        "type": "text"
      },
      "employees": {
        "type": "text"
      },
      "firstName": {
        "type": "text"
      },
      "isManager": {
        "type": "text"
      },
      "lastName": {
        "type": "text"
      },
      "salary": {
        "type": "text"
      },
      "hours": {
        "type": "text"
      }
    }
  }
}

跳过某些属性的映射

通过在访问者上实现SkipProperty,可以防止某些属性被映射。在以下示例中,将跳过派生自DictionaryDocument的类型的继承属性:

public class DictionaryDocument : SortedDictionary<string, dynamic>
{
    public int Id { get; set; }
}

public class IgnoreInheritedPropertiesVisitor<T>  : NoopPropertyVisitor
{
    public override bool SkipProperty(PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute)
    {
        return propertyInfo?.DeclaringType != typeof(T);
    }
}

var createIndexResponse = client.Indices.Create("myindex", c => c
        .Map<DictionaryDocument>(m => m.AutoMap(new IgnoreInheritedPropertiesVisitor<DictionaryDocument>()))
    );
{
  "mappings": {
    "properties": {
      "id": {
        "type": "integer"
      }
    }
  }
}

版权声明:本作品系原创,版权归码友网所有,如未经许可,禁止任何形式转载,违者必究。

发表评论

登录用户才能发表评论, 请 登 录 或者 注册