如何使用流畅的映射映射类型为 Dictionary<string, MyDto> 的 属性
How to map a property of type Dictionary<string, MyDto> using fluent mapping
我有一个字典,我想使用流畅的映射来映射它,对于 MyDto class 的某些属性,我需要添加规范化器。
new CreateIndexDescriptor("indexName")
.Mappings(ms => ms.Map<Entity>(e => new PutMappingDescriptor<Entity>()
.AutoMap()
.Properties(o => o.Object<IDictionary<string, MyDto>>(
m => m.AutoMap().Name(f => f.SomeProperty))
我的 class 定义:
class MyEntity {
...
Dictionary<string, MyDto> SomeProperty {get;set;}
...
}
class MyDto {
...
string Name {get;set;}
...
}
无法将其添加为显式映射,但可以通过动态模板添加。
我们来看看为什么不能通过显式映射。考虑 Dictionary<string, MyDto> SomeProperty
将如何序列化为 JSON。例如
client.IndexDocument(new MyEntity
{
SomeProperty = new Dictionary<string, UserQuery.MyDto>
{
{ "field_1", new MyDto { Name = "foo" } },
{ "field_2", new MyDto { Name = "bar" } }
}
});
默认会序列化为
{
"someProperty": {
"field_1": {
"name": "foo"
},
"field_2": {
"name": "bar"
}
}
}
如果我们想将显式映射应用到 MyDto.Name
,我们需要在映射点知道将使用的所有字典键。
但是你可以,configure a dynamic template that will map any MyDto.Name
as a keyword
type, using path_match
private static void Main()
{
var defaultIndex = "my_index";
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(pool)
.DefaultIndex(defaultIndex);
var client = new ElasticClient(settings);
if (client.IndexExists(defaultIndex).Exists)
client.DeleteIndex(defaultIndex);
var createIndexResponse = client.CreateIndex(defaultIndex, c => c
.Settings(s => s
.NumberOfShards(1)
.NumberOfReplicas(0)
)
.Mappings(m => m
.Map<MyEntity>(mm => mm
.AutoMap()
.DynamicTemplates(dt => dt
.DynamicTemplate("MyDto", dtd => dtd
.PathMatch("someProperty.*.name")
.Mapping(dm => dm
.Keyword(k => k)
)
)
)
.Properties(p => p
.Object<Dictionary<string, MyDto>>(o => o
.Name(n => n.SomeProperty)
)
)
)
)
);
var indexResponse = client.Index(new MyEntity
{
SomeProperty = new Dictionary<string, UserQuery.MyDto>
{
{ "field_1", new MyDto { Name = "foo" } },
{ "field_2", new MyDto { Name = "bar" } }
}
}, i => i.Refresh(Refresh.WaitFor));
var mappingResponse = client.GetMapping<MyEntity>();
}
public class MyEntity
{
public Dictionary<string, MyDto> SomeProperty { get; set; }
}
public class MyDto
{
public string Name { get; set; }
}
映射响应确认 someProperty.field_1.name
和 someProperty.field_2.name
被映射为 keyword
{
"my_index" : {
"mappings" : {
"myentity" : {
"dynamic_templates" : [
{
"MyDto" : {
"path_match" : "someProperty.*.name",
"mapping" : {
"type" : "keyword"
}
}
}
],
"properties" : {
"someProperty" : {
"properties" : {
"field_1" : {
"properties" : {
"name" : {
"type" : "keyword"
}
}
},
"field_2" : {
"properties" : {
"name" : {
"type" : "keyword"
}
}
}
}
}
}
}
}
}
}
关于映射爆炸的旁白
你可能要考虑在MyDto
中添加一个属性来保存字典键,并使用一个List<MyDto>
或类似的集合mapped as a nested
datatype, rather than Dictionary<string, MyDto>
, if users can add any arbitrary key names they wish. With a high cardinality of dictionary keys, you run the risk of a mapping explosion and hitting the maximum number of fields soft limit和大量的稀疏字段,这会影响性能。使用 List<MyDto>
属性 类型,您不会遇到此问题并且仍然可以在关键字段上查询,但代价是 List<MyDto>
可能不太适合您应用代码比Dictionary<string, MyDto>
。需要考虑的事情:)
我有一个字典,我想使用流畅的映射来映射它,对于 MyDto class 的某些属性,我需要添加规范化器。
new CreateIndexDescriptor("indexName")
.Mappings(ms => ms.Map<Entity>(e => new PutMappingDescriptor<Entity>()
.AutoMap()
.Properties(o => o.Object<IDictionary<string, MyDto>>(
m => m.AutoMap().Name(f => f.SomeProperty))
我的 class 定义:
class MyEntity {
...
Dictionary<string, MyDto> SomeProperty {get;set;}
...
}
class MyDto {
...
string Name {get;set;}
...
}
无法将其添加为显式映射,但可以通过动态模板添加。
我们来看看为什么不能通过显式映射。考虑 Dictionary<string, MyDto> SomeProperty
将如何序列化为 JSON。例如
client.IndexDocument(new MyEntity
{
SomeProperty = new Dictionary<string, UserQuery.MyDto>
{
{ "field_1", new MyDto { Name = "foo" } },
{ "field_2", new MyDto { Name = "bar" } }
}
});
默认会序列化为
{
"someProperty": {
"field_1": {
"name": "foo"
},
"field_2": {
"name": "bar"
}
}
}
如果我们想将显式映射应用到 MyDto.Name
,我们需要在映射点知道将使用的所有字典键。
但是你可以,configure a dynamic template that will map any MyDto.Name
as a keyword
type, using path_match
private static void Main()
{
var defaultIndex = "my_index";
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(pool)
.DefaultIndex(defaultIndex);
var client = new ElasticClient(settings);
if (client.IndexExists(defaultIndex).Exists)
client.DeleteIndex(defaultIndex);
var createIndexResponse = client.CreateIndex(defaultIndex, c => c
.Settings(s => s
.NumberOfShards(1)
.NumberOfReplicas(0)
)
.Mappings(m => m
.Map<MyEntity>(mm => mm
.AutoMap()
.DynamicTemplates(dt => dt
.DynamicTemplate("MyDto", dtd => dtd
.PathMatch("someProperty.*.name")
.Mapping(dm => dm
.Keyword(k => k)
)
)
)
.Properties(p => p
.Object<Dictionary<string, MyDto>>(o => o
.Name(n => n.SomeProperty)
)
)
)
)
);
var indexResponse = client.Index(new MyEntity
{
SomeProperty = new Dictionary<string, UserQuery.MyDto>
{
{ "field_1", new MyDto { Name = "foo" } },
{ "field_2", new MyDto { Name = "bar" } }
}
}, i => i.Refresh(Refresh.WaitFor));
var mappingResponse = client.GetMapping<MyEntity>();
}
public class MyEntity
{
public Dictionary<string, MyDto> SomeProperty { get; set; }
}
public class MyDto
{
public string Name { get; set; }
}
映射响应确认 someProperty.field_1.name
和 someProperty.field_2.name
被映射为 keyword
{
"my_index" : {
"mappings" : {
"myentity" : {
"dynamic_templates" : [
{
"MyDto" : {
"path_match" : "someProperty.*.name",
"mapping" : {
"type" : "keyword"
}
}
}
],
"properties" : {
"someProperty" : {
"properties" : {
"field_1" : {
"properties" : {
"name" : {
"type" : "keyword"
}
}
},
"field_2" : {
"properties" : {
"name" : {
"type" : "keyword"
}
}
}
}
}
}
}
}
}
}
关于映射爆炸的旁白
你可能要考虑在MyDto
中添加一个属性来保存字典键,并使用一个List<MyDto>
或类似的集合mapped as a nested
datatype, rather than Dictionary<string, MyDto>
, if users can add any arbitrary key names they wish. With a high cardinality of dictionary keys, you run the risk of a mapping explosion and hitting the maximum number of fields soft limit和大量的稀疏字段,这会影响性能。使用 List<MyDto>
属性 类型,您不会遇到此问题并且仍然可以在关键字段上查询,但代价是 List<MyDto>
可能不太适合您应用代码比Dictionary<string, MyDto>
。需要考虑的事情:)