Клиент высокого уровня 6.x Elasticsearch, NEST, усвоил зависимость Json.NET на
- IL-сливающаяся сборка Json.NET
- преобразование всех типов в
internal
- переименуйте их в
Nest.*
На практике это означает, что клиент не имеет прямой зависимости от Json.NET (прочитайте сообщение о выпуске в блоге , чтобы понять, почему мы это сделали) и не знает о Json Типы .NET, включая JsonPropertyAttribute
или JsonConverter
.
Есть несколько способов решения этой проблемы. Для начала, следующие настройки могут быть полезны при разработке
var defaultIndex = "default-index";
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var settings = new ConnectionSettings(pool)
.DefaultMappingFor<DataEntity>(m => m
.IndexName(defaultIndex)
.TypeName("_doc")
)
.DisableDirectStreaming()
.PrettyJson()
.OnRequestCompleted(callDetails =>
{
if (callDetails.RequestBodyInBytes != null)
{
Console.WriteLine(
$"{callDetails.HttpMethod} {callDetails.Uri} \n" +
$"{Encoding.UTF8.GetString(callDetails.RequestBodyInBytes)}");
}
else
{
Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}");
}
Console.WriteLine();
if (callDetails.ResponseBodyInBytes != null)
{
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}\n" +
$"{new string('-', 30)}\n");
}
else
{
Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
$"{new string('-', 30)}\n");
}
});
var client = new ElasticClient(settings);
Это запишет все запросы и ответы на консоль, чтобы вы могли видеть, что клиент отправляет и получает от Elasticsearch. .DisableDirectStreaming()
буферизует байты запросов и ответов в памяти, чтобы сделать их доступными для делегата, переданного в .OnRequestCompleted()
, так что это полезно для разработки, но вы, вероятно, не захотите использовать его в производстве, так как это приводит к снижению производительности.
Теперь решения:
1. Используйте PropertyNameAttribute
Вместо использования JsonPropertyAttribute
вы можете использовать PropertyNameAttribute
для именования свойств для сериализации
public sealed class GeoLocationEntity
{
public GeoLocationEntity(
double latitude,
double longitude)
{
this.Latitude = latitude;
this.Longitude = longitude;
}
[PropertyName("lat")]
public double Latitude { get; }
[PropertyName("lon")]
public double Longitude { get; }
}
public sealed class DataEntity
{
public DataEntity(
GeoLocationEntity location)
{
this.Location = location;
}
[PropertyName("location")]
public GeoLocationEntity Location { get; }
}
и использовать
if (client.IndexExists(defaultIndex).Exists)
client.DeleteIndex(defaultIndex);
var createIndexResponse = client.CreateIndex(defaultIndex, c => c
.Mappings(m => m
.Map<DataEntity>(mm => mm
.AutoMap()
.Properties(p => p
.GeoPoint(g => g
.Name(n => n.Location)
)
)
)
)
);
var indexResponse = client.Index(
new DataEntity(new GeoLocationEntity(88.59, -98.87)),
i => i.Refresh(Refresh.WaitFor)
);
var searchResponse = client.Search<DataEntity>(s => s
.Query(q => q
.MatchAll()
)
);
PropertyNameAttribute
действует аналогично тому, как вы обычно используете JsonPropertAttribute
с Json.NET.
2. Используйте DataMemberAttribute
В этом случае это будет работать так же, как и PropertyNameAttribute
, если вы предпочитаете, чтобы ваши POCO не относились к типам NEST (хотя я бы сказал, что POCO привязаны к Elasticsearch, поэтому привязывайте их к .NET Типы Elasticsearch, вероятно, не проблема).
3. Используйте Geolocation
тип
Вы можете заменить тип GeoLocationEntity
типом Nest GeoLocation
, который сопоставляется с отображением типа поля geo_point
. При использовании этого POCO на единицу меньше, и правильное отображение может быть выведено из свойства типа
public sealed class DataEntity
{
public DataEntity(
GeoLocation location)
{
this.Location = location;
}
[DataMember(Name = "location")]
public GeoLocation Location { get; }
}
// ---
if (client.IndexExists(defaultIndex).Exists)
client.DeleteIndex(defaultIndex);
var createIndexResponse = client.CreateIndex(defaultIndex, c => c
.Mappings(m => m
.Map<DataEntity>(mm => mm
.AutoMap()
)
)
);
var indexResponse = client.Index(
new DataEntity(new GeoLocation(88.59, -98.87)),
i => i.Refresh(Refresh.WaitFor)
);
var searchResponse = client.Search<DataEntity>(s => s
.Query(q => q
.MatchAll()
)
);
4. Подключение JsonNetSerializer
NEST позволяет подключить пользовательский сериализатор , чтобы заботиться о сериализации ваших типов. Отдельный пакет nuget, NEST.JsonNetSerializer , позволяет использовать Json.NET для сериализации ваших типов, при этом сериализатор делегирует обратно внутреннему сериализатору свойства, относящиеся к типам NEST.
Сначала вам нужно передать JsonNetSerializer в ConnectionSettings
конструктор
var settings = new ConnectionSettings(pool, JsonNetSerializer.Default)
Тогда ваш исходный код будет работать как положено, без пользовательского JsonConverter
public sealed class GeoLocationEntity
{
public GeoLocationEntity(
double latitude,
double longitude)
{
this.Latitude = latitude;
this.Longitude = longitude;
}
[JsonProperty("lat")]
public double Latitude { get; }
[JsonProperty("lon")]
public double Longitude { get; }
}
public sealed class DataEntity
{
public DataEntity(
GeoLocationEntity location)
{
this.Location = location;
}
[JsonProperty("location")]
public GeoLocationEntity Location { get; }
}
// ---
if (client.IndexExists(defaultIndex).Exists)
client.DeleteIndex(defaultIndex);
var createIndexResponse = client.CreateIndex(defaultIndex, c => c
.Mappings(m => m
.Map<DataEntity>(mm => mm
.AutoMap()
.Properties(p => p
.GeoPoint(g => g
.Name(n => n.Location)
)
)
)
)
);
var indexResponse = client.Index(
new DataEntity(new GeoLocationEntity(88.59, -98.87)),
i => i.Refresh(Refresh.WaitFor)
);
var searchResponse = client.Search<DataEntity>(s => s
.Query(q => q
.MatchAll()
)
);
Я перечислил эту опцию последним, потому что внутренне существуют издержки на производительность и распределение при передаче сериализации Json.NET таким способом. Он включен для обеспечения гибкости, но я бы рекомендовал использовать его только тогда, когда вам действительно нужно, например, завершить пользовательскую сериализацию POCO, где сериализованная структура не является обычной. Мы работаем над гораздо более быстрой сериализацией, которая снизит эти издержки в будущем.