Невозможно добавить это как явное отображение, но это происходит через динамический шаблон.
Давайте посмотрим, почему это невозможно с помощью явного отображения. Посмотрите, как 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
, нам нужно было бы знать в точке сопоставления все ключи словаря, которые будут использоваться.
Однако вы можете настроить динамический шаблон, который будет отображать любой MyDto.Name
как тип keyword
, используя 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>
или подобную коллекцию , отображаемую как nested
тип данных , а не Dictionary<string, MyDto>
, если пользователи могут добавлять любые произвольные имена ключей, которые они хотят. С большим количеством словарных ключей вы рискуете взорвать карту и достичь мягкого предела максимального количества полей и большого количества разреженных полей, которые могут повлиять на производительность. С типом свойства List<MyDto>
у вас не было бы этой проблемы, и вы все равно могли бы запрашивать ключевые поля за счет компромисса, что List<MyDto>
может быть менее оптимальным для кода вашего приложения, чем Dictionary<string, MyDto>
. Что-то, чтобы рассмотреть:)