NEST教程系列:字段映射-自动映射
NEST教程系列:字段映射-自动映射
自动映射
在创建映射时,无论是创建索引还是通过PUT Mapping API, NEST都提供了
Auto Mapping
特性,它可以从要映射的类的属性类型自动推断出正确的Elasticsearch字段数据类型
定义两个类,Company
有一个名称和一组雇员;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; }
}
将 Company
和 Employee
两个类索引为单个索引,先为基类调用Map,然后对我们想要实现的类型调用AutoMap
var createIndexResponse = _client.Indices.Create("myindex", c => c
.Map<Document>(m => m
.AutoMap<Company>()
.AutoMap(typeof(Employee))
));
上述请求JSON如下
{
"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
已经根据类中属性的CLR类型推断出Elasticsearch类型
属性名 | 属性类型 | Elasticsearch类型 |
---|---|---|
Birthday | DateTime | Date |
Hours | TimeSpan | long |
IsManager | bool | boolean |
Salary | int | integer |
Employees | List |
object |
- 其余的 string 类型被推断为了 ES 中的 text 类型,且每一个都被标记为了 keyword
数据类型映射
支持的 .NET 数据类型
.NET数据类型 | Elasticsearch数据类型 |
---|---|
String/string | text,包含 keyword 子属性 |
Int32/int | integer |
UInt16/ushort | integer |
Int16/short | short |
Byte/byte | short |
Int64/long | long |
UInt32/uint | long |
TimeSpan | long |
Single/float | float |
Double/double | double |
Decimal/decimal | double |
UInt64/ulong | double |
DateTime | date |
DateTimeOffset | date |
Boolean/bool | boolean |
Char/char | keyword |
Guid | keyword |
- 需要注意:.NET 中的 Decimal/decimal 类型在 ES 中没有直接等效的类型,这里用 double 来对应,但存在精度上存在差异(Decimal 精度 小于 Double 精度),在反序列化到 .NET 类的时候,如果 ES 中的值在 [Decimal.Min, Decimal.Max] 区间范围之外,则在映射到 POCO 模型 Decimal 类型的属性时由于超精度了,就会引发异常。为了避免这种情况,在设计 .NET 模型属性的时候,建议不要用 Decimal 数据类型,转而使用 Double。
NEST 特有的特殊类型映射
NEST 数据类型 | Elasticsearch数据类型 |
---|---|
Nest.QueryContainer | percolator |
Nest.GeoLocation | geo_point |
Nest.IGeoShape | geo_shape,如果你想要显式映射 shape 类型,则在对应的属性上使用 [Shape]特性 |
Nest.CompletionField | completion |
Nest.DateRange | date_range |
Nest.DoubleRange | double_range |
Nest.FloatRange | float_range |
Nest.IntegerRange | integer_range |
Nest.LongRange | long_range |
Nest.IpAddressRange | ip_range |
- 除去以上两大类,剩余其他类型默认都被映射为
object
递归映射
如果您注意到在前面的 Company
和 Employee
示例中,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()));
映射后的JSON,仅递归调用了1次
{
"mappings": {
"properties": {
"child": {
"properties": {},
"type": "object"
}
}
}}
修改递归次数为3次
createIndexResponse = _client.Indices.Create("myindex", c => c
.Map<A>(m => m.AutoMap(3)));
映射后的JSON,修改后调用了3次
{
"mappings": {
"properties": {
"child": {
"type": "object",
"properties": {
"child": {
"type": "object",
"properties": {
"child": {
"type": "object",
"properties": {
"child": {
"type": "object",
"properties": {}
}
}
}
}
}
}
}
}
}
}