自动映射(Auto mapping)

1245 更新于: 2021-04-07 读完约需 8 分钟

前言

使用NEST与Elasticsearch进行交互,我们需要知道C#中的实体类型数据是如何转换成JSON文档并存储在Elasticsearch中的。接下来的这一章节,我们将介绍NEST与Elasticsearch之间不同的实体映射方式。

NEST提供了几种处理C#数据类型与Elasticsearch数据类型之间映射关系的方法,包括:自动映射(Auto mapping),特性映射(Attribute mapping),链式映射(Fluent mapping),访问者模式映射(Visitor pattern)和父子关系映射(Parent/Child relationships)等。

本节将为大家分享的是自动映射(Auto mapping)。

自动映射

无论通过Create方法或PutMapping方法创建映射时, NEST均提供了自动映射的特性,它可以自动地从CLR POCO属性类型推断对应的正确的Elasticsearch字段数据类型。

我们将通过一系列的示例来学习NEST的自动映射。为此,我们定义两个实例,分别为Company实体(它包含了一个Name字符串属性成员以及一个Employees集合属性成员)和Employee实体(它包含了多个不同数据类型的属性成员以及一个自包含的Employee集合),示例代码如下:

public abstract class Document
{
    public JoinField Join { get; set; }
}

public class Company : Document
{
    public string Name { get; set; }
    public List<Employee> Employees { get; set; }
}

public class Employee : Document
{
    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; }
}

自动映射可以省去为实体上的所有属性定义手动映射的麻烦。在本例中,我们希望将两个子类索引到一个索引中。我们为基类调用Map方法,然后为其中的成员调用AutoMap方法,示例如下:

var createIndexResponse = _client.Indices.Create("myindex", c => c
    .Map<Document>(m => m
        .AutoMap<Company>() 
        .AutoMap(typeof(Employee)) 
    )
);

生成的Elasticsearch映射结果为:

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

从JSON结果可以看到,NEST基于POCO属性的CLR类型推断出了Elasticsearch类型。在本示例中:

  • Birthday被映射成了date数据类型
  • Hours被映射成了long数据类型
  • IsManager被映射成了boolean
  • Salary被映射成了integer数据类型
  • Employees被映射成了object数据类型

其余的字符串属性作为多字段text数据类型,每个都有一个keyword数据类型子字段。

.NET与Elasticsearch的数据类型映射关系

NEST为以下.NET类型提供了推断映射支持:

.NET数据类型 Elasticsearch数据类型
String maps to "text" with a "keyword" sub field. See Multi Fields.
Int32 maps to "integer"
UInt16 maps to "integer"
Int16 maps to "short"
Byte maps to "short"
Int64 maps to "long"
UInt32 maps to "long"
TimeSpan maps to "long"
Single maps to "float"
Double maps to "double"
Decimal maps to "double"
UInt64 maps to "double"
DateTime maps to "date"
DateTimeOffset maps to "date"
Boolean maps to "boolean"
Char maps to "keyword"
Guid maps to "keyword"

另外,NEST还内置了一些特殊的映射:

.NET数据类型 Elasticsearch数据类型
Nest.QueryContainer maps to "percolator"
Nest.GeoLocation maps to "geo_point"
Nest.IGeoShape maps to "geo_shape" (if you want to map to a "shape" type use explicit mapping or the [Shape] attribute on the property)
Nest.CompletionField maps to "completion"
Nest.DateRange maps to "date_range"
Nest.DoubleRange maps to "double_range"
Nest.FloatRange maps to "float_range"
Nest.IntegerRange maps to "integer_range"
Nest.LongRange maps to "long_range"
Nest.IpAddressRange maps to "ip_range"

默认情况下,以上列举之外的数据类型都将被映射成object

循环映射

细心的你可能已经注意到,在前面的示例中,Employee类型是递归的,因为Employee类本身包含一个Employee类型的集合。默认情况下,.AutoMap()在遇到像这样的递归实例时只会遍历一级深度,Employee类上的Employee集合并没有任何属性映射。

这样做的目的是为了防止堆栈溢出和无限递归带的问题。但是在大多数情况下,当涉及到Elasticsearch映射时,通常会出现这样的深度嵌套映射。你可能需要嵌套多级的递归深度。这时,你可以使用AutoMap()的参数来控制递归的深度。

比如下面有一个非常简单的类A,它自包含了一个属性A成员,如下:

public class A
{
    public A Child { get; set; }
}

默认情况下,.AutoMap()只会递归一级的深度:

var createIndexResponse = _client.Indices.Create("myindex", c => c
    .Map<A>(m => m.AutoMap())
);

得到的Elasticsearch映射关系如下:

{
  "mappings": {
    "properties": {
      "child": {
        "properties": {},
        "type": "object"
      }
    }
  }
}

现在,我们使用.AutoMap(3)来指定递归的层级为3层,如下:

createIndexResponse = _client.Indices.Create("myindex", c => c
    .Map<A>(m => m.AutoMap(3))
);

得到的Elasticsearch映射关系如下:

{
  "mappings": {
    "properties": {
      "child": {
        "type": "object",
        "properties": {
          "child": {
            "type": "object",
            "properties": {
              "child": {
                "type": "object",
                "properties": {
                  "child": {
                    "type": "object",
                    "properties": {}
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

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

发表评论

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