幽映每白日,清辉照衣裳。这篇文章主要讲述ElasticsearchNEST高级客户端--Mapping映射相关的知识,希望能为你提供帮助。
要使用NEST与Elasticsearch进行交互,我们需要能够将我们的解决方案中的POCO类型映射到存储在Elasticsearch中的反向索引中的JSON文档和字段。本节介绍NEST中可用的所有不同功能,使POCO和Elasticsearch变得轻而易举。
在Elasticsearch中显式映射文档对于为给定的问题域提供定制搜索解决方案至关重要。虽然Elasticsearch能够基于遇到的该类型的第一个文档来推断索引中给定类型的映射,但推测的映射有时不足以构建一个非常优秀的搜索体验。
要显式控制映射,可以在创建索引时指定显式类型映射,或者在索引该类型的第一个文档之前添加到现有索引(因为索引没有显式映射的文档将导致Elasticsearch推断映射)。
有几种方式来控制NEST中的映射
自动映射(从POCO属性类型推断)
属性映射
Fluent映射
通过访客模式
并且这些可以组合以形成整体映射方法。另外还有办法控制
忽略属性
多个字段
自动映射在创建索引或通过Put Mapping API创建映射时,NEST提供了一个称为自动映射的功能,可以从您正在映射的CLR POCO属性类型自动推断出正确的Elasticsearch字段数据类型。
我们将通过一些示例来看自动映射的功能。 为此,我们将定义两个POCO
Company
,其有名称和Employees的集合以及具有不同类型的各种属性的Employee
,并且本身具有Employee
类型的集合。public class Company
{
public string Name { get;
set;
}
public List<
Employee>
Employees { get;
set;
}
}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;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
Company>
(m =>
m.AutoMap())
.Map<
Employee>
(m =>
m.AutoMap())
);
- 1
- 2
- 3
- 4
- 5
{
"mappings": {
"company": {
"properties": {
"employees": {
"properties": {
"birthday": {
"type": "date"
},
"employees": {
"properties": {},
"type": "object"
},
"firstName": {
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"type": "text"
},
"hours": {
"type": "long"
},
"isManager": {
"type": "boolean"
},
"lastName": {
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"type": "text"
},
"salary": {
"type": "integer"
}
},
"type": "object"
},
"name": {
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"type": "text"
}
}
},
"employee": {
"properties": {
"birthday": {
"type": "date"
},
"employees": {
"properties": {},
"type": "object"
},
"firstName": {
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"type": "text"
},
"hours": {
"type": "long"
},
"isManager": {
"type": "boolean"
},
"lastName": {
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"type": "text"
},
"salary": {
"type": "integer"
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
Birthday映射为`date`,
Hours被映射为一个`long` `TimeSpan ticks`)
IsManager映射为`boolean`,
Salary被映射为`integer`
Employees被映射为对象`object`
剩余的字符串属性作为多字段
text
数据类型,每个都有一个keyword
数据类型子字段。NEST已经推断出对以下.NET类型的映射支持
String映射到"text"与"keyword"子字段。请参阅[Multi Fields]
Int32映射到"integer"
UInt16映射到"integer"
Int16映射到"short"
Byte映射到"short"
Int64映射到"long"
UInt32映射到"long"
TimeSpan映射到"long"
Single映射到"float"
Double映射到"double"
Decimal映射到"double"
UInt64映射到"double"
DateTime映射到"date"
DateTimeOffset映射到"date"
Boolean映射到"boolean"
Char映射到"keyword"
Guid映射到"keyword"
并支持NEST中定义的一些特殊类型
Nest.GeoLocation映射到"geo_point"
Nest.CompletionField映射到"completion"
Nest.Attachment映射到"attachment"
Nest.DateRange映射到"date_range"
Nest.DoubleRange映射到"double_range"
Nest.FloatRange映射到"float_range"
Nest.IntegerRange映射到"integer_range"
Nest.LongRange映射到"long_range"
所有其他类型默认映射到
"object"
。某些.NET类型不具有直接等效的Elasticsearch类型。例如,
System.Decimal
是一种通常用于表示货币和其他财务计算的类型,需要大量有效的积分和分数位数,并且没有舍入误差。 Elasticsearch中没有等效的类型,最近的类型是double,双精度64位IEEE 754浮点数。当POCO具有
System.Decimal
属性时,它将自动映射到Elasticsearch
double
类型。由于潜在的精度损失的警告,这在很多用例中通常是可以接受的,但是在某些边缘情况下可能会导致问题。正如C#规范所述,
【ElasticsearchNEST高级客户端--Mapping映射】对于从十进制到float或double的转换,十进制值将舍入为最接近的double或float值。虽然这种转换可能会失去精度,但它并不会导致抛出异常。
- C#规范部分6.2.1
Decimal.MinValue
和Decimal.MaxValue
的反序列化时抛出异常,因为在序列化时,转换为最接近的双精度值分别在Decimal.MinValue
或Decimal.MaxValue
范围之外。在这些情况下,建议使用double作为POCO属性类型。映射递归如果您注意到我们以前的公司和员工示例,
Employee
类型是递归的,因为Employee
类本身包含Employee
类型的集合。 默认情况下,.AutoMap()
只会在遇到像这样的递归实例时穿过一个深度;
Employee
类中的Employee
类的集合没有映射其任何属性。这是一个安全防范,以防止堆栈溢出和无限递归的函数。 此外,在大多数情况下,当涉及到Elasticsearch映射时,通常有一个这样的深度嵌套映射的边缘案例。 但是,您仍然可能需要执行此操作,因此您可以控制
.AutoMap()
的递归深度。我们来介绍一个非常简单的类
A
,它本身有一个属性为A
类的Child。public class A
{
public A Child { get;
set;
}
}
- 1
- 2
- 3
- 4
.AutoMap()
只能进入深度1var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
A>
(m =>
m.AutoMap())
);
- 1
- 2
- 3
- 4
{
"mappings": {
"a": {
"properties": {
"child": {
"properties": {},
"type": "object"
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
var withMaxRecursionDescriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
A>
(m =>
m.AutoMap(3))
);
- 1
- 2
- 3
- 4
.AutoMap()
现在已经映射了我们的Child属性的三个层级{
"mappings": {
"a": {
"properties": {
"child": {
"type": "object",
"properties": {
"child": {
"type": "object",
"properties": {
"child": {
"type": "object",
"properties": {
"child": {
"type": "object",
"properties": {}
}
}
}
}
}
}
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
.AutoMap()
从POCO的属性推断出POCO的类型映射。 但是,当您想要映射到推测的映射时,您会做什么? 这是属性映射可以帮助的地方。可以使用您的POCO类型和属性上的属性来定义您的映射。 使用属性属性并调用
.AutoMap()
,NEST将从POCO属性类型推断映射,并考虑映射属性。当您使用属性时,还必须调用
.AutoMap()
来获取要应用的属性。这里我们定义与以前相同的两种类型,但这次使用属性来定义映射:
[ElasticsearchType(Name = "company")]
public class Company
{
[Keyword(NullValue = "https://www.songbingjia.com/android/null", Similarity = "BM25")]
public string Name { get;
set;
}[Text(Name = "office_hours")]
public TimeSpan? HeadOfficeHours { get;
set;
}[Object(Store = false)]
public List<
Employee>
Employees { get;
set;
}
}[ElasticsearchType(Name = "employee")]
public class Employee
{
[Text(Name = "first_name")]
public string FirstName { get;
set;
}[Text(Name = "last_name")]
public string LastName { get;
set;
}[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public int Salary { get;
set;
}[Date(Format = "MMddyyyy")]
public DateTime Birthday { get;
set;
}[Boolean(NullValue = https://www.songbingjia.com/android/false, Store = true)]
public bool IsManager { get;
set;
}[Nested]
[JsonProperty("empl")]
public List<
Employee>
Employees { get;
set;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
.AutoMap()
来映射类型var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
Company>
(m =>
m.AutoMap())
.Map<
Employee>
(m =>
m.AutoMap())
);
- 1
- 2
- 3
- 4
- 5
{
"mappings": {
"company": {
"properties": {
"employees": {
"properties": {
"birthday": {
"format": "MMddyyyy",
"type": "date"
},
"empl": {
"properties": {},
"type": "nested"
},
"first_name": {
"type": "text"
},
"isManager": {
"null_value": false,
"store": true,
"type": "boolean"
},
"last_name": {
"type": "text"
},
"salary": {
"coerce": true,
"doc_values": false,
"ignore_malformed": true,
"type": "float"
}
},
"type": "object",
"store": false
},
"name": {
"null_value": "null",
"similarity": "BM25",
"type": "keyword"
},
"office_hours": {
"type": "text"
}
}
},
"employee": {
"properties": {
"birthday": {
"format": "MMddyyyy",
"type": "date"
},
"empl": {
"properties": {},
"type": "nested"
},
"first_name": {
"type": "text"
},
"isManager": {
"null_value": false,
"store": true,
"type": "boolean"
},
"last_name": {
"type": "text"
},
"salary": {
"coerce": true,
"doc_values": false,
"ignore_malformed": true,
"type": "float"
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
Fluent映射Fluent映射POCO属性到Elasticsearch类型映射中的字段提供了对该过程的最大控制。 通过Fluent映射,POCO的每个属性都被显式映射到一个Elasticsearch类型的字段映射。
为了演示,我们将定义两个POCO
Company拥有员工姓名和员工人数
Employee具有不同类型的各种属性,并且拥有Employee类型的集合。
public class Company
{
public string Name { get;
set;
}
public List<
Employee>
Employees { get;
set;
}
}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;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
Company>
(m =>
m
.Properties(ps =>
ps
.Text(s =>
s
.Name(c =>
c.Name)
)
.Object<
Employee>
(o =>
o
.Name(c =>
c.Employees)
.Properties(eps =>
eps
.Text(s =>
s
.Name(e =>
e.FirstName)
)
.Text(s =>
s
.Name(e =>
e.LastName)
)
.Number(n =>
n
.Name(e =>
e.Salary)
.Type(NumberType.Integer)
)
)
)
)
)
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
Company
类型的Name属性已被映射为文本数据类型,Employees
属性映射为对象数据类型。 在此对象映射中,仅映射了Employee
类型的FirstName
,LastName
和Salary
属性。这个例子的json映射看起来像
{
"mappings": {
"company": {
"properties": {
"name": {
"type": "text"
},
"employees": {
"type": "object",
"properties": {
"firstName": {
"type": "text"
},
"lastName": {
"type": "text"
},
"salary": {
"type": "integer"
}
}
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
这是与自动映射相结合的Fluent映射.
自动映射与fluent 覆盖在大多数情况下,您将需要映射不仅仅是vanilla数据类型,还可以为您的属性提供各种选项,例如要使用的分词器,是否启用
doc_values
等。在这种情况下,可以将
.AutoMap()
与显式映射的属性结合使用。在这里我们使用
.AutoMap()
自动推断Company
类型从CLR属性类型的映射,但是我们覆盖Employees
属性以使其成为一个嵌套的数据类型,因为默认情况下.AutoMap()
将推断List<
Employee>
属性作为object
数据类型var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
Company>
(m =>
m
.AutoMap()
.Properties(ps =>
ps
.Nested<
Employee>
(n =>
n
.Name(c =>
c.Employees)
)
)
)
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
{
"mappings": {
"company": {
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"employees": {
"type": "nested"
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
.AutoMap()
是幂等的,因此在手动映射属性之前或之后调用它将仍然产生相同的结果。 下一个示例生成与上一个相同的映射descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
Company>
(m =>
m
.Properties(ps =>
ps
.Nested<
Employee>
(n =>
n
.Name(c =>
c.Employees)
)
)
.AutoMap()
)
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
考虑以下两个POCOS
[ElasticsearchType(Name = "company")]
public class CompanyWithAttributes
{
[Keyword(NullValue = "https://www.songbingjia.com/android/null", Similarity = "BM25")]
public string Name { get;
set;
}[Text(Name = "office_hours")]
public TimeSpan? HeadOfficeHours { get;
set;
}[Object(Store = false)]
public List<
Employee>
Employees { get;
set;
}
}[ElasticsearchType(Name = "employee")]
public class EmployeeWithAttributes
{
[Text(Name = "first_name")]
public string FirstName { get;
set;
}[Text(Name = "last_name")]
public string LastName { get;
set;
}[Number(DocValues = false, IgnoreMalformed = true, Coerce = true)]
public int Salary { get;
set;
}[Date(Format = "MMddyyyy")]
public DateTime Birthday { get;
set;
}[Boolean(NullValue = https://www.songbingjia.com/android/false, Store = true)]
public bool IsManager { get;
set;
}[Nested]
[JsonProperty("empl")]
public List<
Employee>
Employees { get;
set;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
AutoMap()
来推断来自POCO属性类型和属性的映射,并且通过fluent映射来覆盖 推断的映射var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
CompanyWithAttributes>
(m =>
m
.AutoMap()
.Properties(ps =>
ps
.Nested<
Employee>
(n =>
n
.Name(c =>
c.Employees)
)
)
)
.Map<
EmployeeWithAttributes>
(m =>
m
.AutoMap()
.Properties(ps =>
ps
.Text(s =>
s
.Name(e =>
e.FirstName)
.Fields(fs =>
fs
.Keyword(ss =>
ss
.Name("firstNameRaw")
)
.TokenCount(t =>
t
.Name("length")
.Analyzer("standard")
)
)
)
.Number(n =>
n
.Name(e =>
e.Salary)
.Type(NumberType.Double)
.IgnoreMalformed(false)
)
.Date(d =>
d
.Name(e =>
e.Birthday)
.Format("MM-dd-yy")
)
)
)
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
{
"mappings": {
"company": {
"properties": {
"employees": {
"type": "nested"
},
"name": {
"null_value": "null",
"similarity": "BM25",
"type": "keyword"
},
"office_hours": {
"type": "text"
}
}
},
"employee": {
"properties": {
"birthday": {
"format": "MM-dd-yy",
"type": "date"
},
"empl": {
"properties": {
"birthday": {
"type": "date"
},
"employees": {
"properties": {},
"type": "object"
},
"firstName": {
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"type": "text"
},
"hours": {
"type": "long"
},
"isManager": {
"type": "boolean"
},
"lastName": {
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
},
"type": "text"
},
"salary": {
"type": "integer"
}
},
"type": "nested"
},
"first_name": {
"fields": {
"firstNameRaw": {
"type": "keyword"
},
"length": {
"analyzer": "standard",
"type": "token_count"
}
},
"type": "text"
},
"isManager": {
"null_value": false,
"store": true,
"type": "boolean"
},
"last_name": {
"type": "text"
},
"salary": {
"ignore_malformed": false,
"type": "double"
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
Company
上的Employees
属性的属性未映射。 这是因为automapping 应用仅在Company
映射的根级别。通过在
.Nested <
Employee>
映射中调用.AutoMap()
,可以自动映射Employee
嵌套属性,并再次通过手动映射来覆盖自动映射过程中的任何推断映射var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(m =>
m
.Map<
Company>
(mm =>
mm
.AutoMap()
.Properties(p =>
p
.Nested<
Employee>
(n =>
n
.Name(c =>
c.Employees)
.AutoMap()
.Properties(pp =>
pp
.Text(t =>
t
.Name(e =>
e.FirstName)
)
.Text(t =>
t
.Name(e =>
e.LastName)
)
.Nested<
Employee>
(nn =>
nn
.Name(e =>
e.Employees)
)
)
)
)
)
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
{
"mappings": {
"company": {
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"employees": {
"type": "nested",
"properties": {
"firstName": {
"type": "text"
},
"lastName": {
"type": "text"
},
"salary": {
"type": "integer"
},
"birthday": {
"type": "date"
},
"isManager": {
"type": "boolean"
},
"employees": {
"type": "nested"
},
"hours": {
"type": "long"
}
}
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
.AutoMap()
在内部实现访问者模式。 默认访问者NoopPropertyVisitor
不执行任何操作,也可以作为空白画布来实现您自己的访问方法。例如,让我们创建一个自定义访问者,禁用数字和布尔类型的文档值(实际上不是一个好主意,但是为了清楚的例子,我们来做)。
public class Company
{
public string Name { get;
set;
}
public List<
Employee>
Employees { get;
set;
}
}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;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
NoopPropertyVisitor
继承,并覆盖Visit
方法以实现约定 是最简单的方法public class DisableDocValuesPropertyVisitor : NoopPropertyVisitor
{
public override void Visit(
INumberProperty type,
PropertyInfo propertyInfo,
ElasticsearchPropertyAttributeBase attribute)
{
type.DocValues = false;
}public override void Visit(
IBooleanProperty type,
PropertyInfo propertyInfo,
ElasticsearchPropertyAttributeBase attribute)
{
type.DocValues = false;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
.AutoMap()
var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
Employee>
(m =>
m.AutoMap(new DisableDocValuesPropertyVisitor()))
);
- 1
- 2
- 3
- 4
Visit()
调用中定义的转换,在此示例中禁用doc_values。var expected = new
{
mappings = new
{
employee = new
{
properties = new
{
birthday = new
{
type = "date"
},
employees = new
{
properties = new { },
type = "object"
},
firstName = new
{
type = "string"
},
isManager = new
{
doc_values = false,
type = "boolean"
},
lastName = new
{
type = "string"
},
salary = new
{
doc_values = false,
type = "integer"
}
}
}
}
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
IProperty
类型,直接访问您的POCO反射的PropertyInfo
属性。例如,让我们创建一个访问者,将所有CLR类型映射到Elasticsearch文本数据类型
ITextProperty
)。public class EverythingIsATextPropertyVisitor : NoopPropertyVisitor
{
public override IProperty Visit(PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) =>
new TextProperty();
}var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
Employee>
(m =>
m.AutoMap(new EverythingIsATextPropertyVisitor()))
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
{
"mappings": {
"employee": {
"properties": {
"birthday": {
"type": "text"
},
"employees": {
"type": "text"
},
"firstName": {
"type": "text"
},
"isManager": {
"type": "text"
},
"lastName": {
"type": "text"
},
"salary": {
"type": "text"
},
"hours": {
"type": "text"
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
对派生的ElasticsearchPropertyAttribute类型使用Ignore属性应用于在POCO上应该被忽略的属性
在ConnectionSettings上使用.InferMappingFor <
TDocument>
(Func <
ClrTypeMappingDescriptor <
TDocument>
,IClrTypeMapping <
TDocument >
>
选择器)
使用应用于使用的IElasticsearchSerializer所理解的POCO属性的ignore属性,并在序列化器上的CreatePropertyMapping()内进行检查。 在默认JsonNetSerializer的情况下,这是Json.NET JsonIgnoreAttribute
此示例演示了所有方法,使用属性上的Ignore属性忽略属性PropertyToIgnore,推断映射忽略属性AnotherPropertyToIgnore和json serializer特定属性以忽略属性JsonIgnoredProperty
[ElasticsearchType(Name = "company")]
public class CompanyWithAttributesAndPropertiesToIgnore
{
public string Name { get;
set;
}[Text(Ignore = true)]
public string PropertyToIgnore { get;
set;
}public string AnotherPropertyToIgnore { get;
set;
}[JsonIgnore]
public string JsonIgnoredProperty { get;
set;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
Name
之外的所有属性都在映射中被忽略var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
CompanyWithAttributesAndPropertiesToIgnore>
(m =>
m
.AutoMap()
)
);
var settings = WithConnectionSettings(s =>
s
.InferMappingFor<
CompanyWithAttributesAndPropertiesToIgnore>
(i =>
i
.Ignore(p =>
p.AnotherPropertyToIgnore)
)
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
{
"mappings": {
"company": {
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
ConnectionSettings
上使用POCO的推断映射配置,也可以忽略继承的属性。public class Parent
{
public int Id { get;
set;
}
public string Description { get;
set;
}
public string IgnoreMe { get;
set;
}
}public class Child : Parent { }var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
Child>
(m =>
m
.AutoMap()
)
);
var settings = WithConnectionSettings(s =>
s
.InferMappingFor<
Child>
(m =>
m
.Rename(p =>
p.Description, "desc")
.Ignore(p =>
p.IgnoreMe)
)
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
IgnoreMe
属性被忽略{
"mappings": {
"child": {
"properties": {
"id": {
"type": "integer"
},
"desc": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
string
属性映射为全文搜索的text
数据类型,以及作为结构化搜索,排序和聚合的keyword
数据类型的映射。 另一个例子是将POCO字符串属性映射为使用不同的分词器,以提供不同的全文搜索需求。我们来看几个例子。 对于每个,我们使用以下简单的POCO
public class Person
{
public string Name { get;
set;
}
}
- 1
- 2
- 3
- 4
当使用自动映射时,字符串POCO类型的推断映射是具有多字段的
text
数据类型,包括keyword
子字段var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
Person>
(m =>
m
.AutoMap()
)
);
- 1
- 2
- 3
- 4
- 5
- 6
{
"mappings": {
"person": {
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
var searchResponse = client.Search<
Person>
(s =>
s
.Query(q =>
q
.Match(m =>
m
.Field(f =>
f.Name)
.Query("Russ")
)
)
.Sort(ss =>
ss
.Descending(f =>
f.Name.Suffix("keyword"))
)
.Aggregations(a =>
a
.Terms("peoples_names", t =>
t
.Field(f =>
f.Name.Suffix("keyword"))
)
)
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
{
"query": {
"match": {
"name": {
"query": "Russ"
}
}
},
"sort": [
{
"name.keyword": {
"order": "desc"
}
}
],
"aggs": {
"peoples_names": {
"terms": {
"field": "name.keyword"
}
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
_source
字段;
它们仅影响一个字段的索引。可以使用Put Mapping API将新的多个字段添加到现有的字段。
创建多个字段可以使用字段映射中的
.Fields()
方法在映射上创建多个字段var descriptor = new CreateIndexDescriptor("myindex")
.Mappings(ms =>
ms
.Map<
Person>
(m =>
m
.Properties(p =>
p
.Text(t =>
t
.Name(n =>
n.Name)
.Fields(ff =>
ff
.Text(tt =>
tt
.Name("stop")
.Analyzer("stop")
)
.Text(tt =>
tt
.Name("shingles")
.Analyzer("name_shingles")
)
.Keyword(k =>
k
.Name("keyword")
.IgnoreAbove(256)
)
)
)
)
)
);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
{
"mappings": {
"person": {
"properties": {
"name": {
"type": "text",
"fields": {
"stop": {
"type": "text",
"analyzer": "stop"
},
"shingles": {
"type": "text",
"analyzer": "name_shingles"
},
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
推荐阅读
- $digest / $apply digest in progress报错
- Android 长按识别图中二维码 zxing
- Appium遇到的问题(持续更新....)
- Android控件之CalendarView 日历对话框
- Android开发中几种有用的的日历控件实现
- Java FileWriter类
- Java FilterInputStream类
- Java FileReader类
- Java FileDescriptor