c# elasticsearch json.net

c# - Deserialización de los resultados de Elasticsearch a través de JSON.NET



(5)

Bueno, eres DeserializeObject<T> T no coincide con el Json. Su Json comienza con un { por lo que su T debe ser una clase (no un tipo IEnumerable ).

Empecemos afuera y trabajemos en nuestro camino en:

{ "took":31, "timed_out":false, "_shards": <object> "hits": <object> }

asi que:

public class SearchResult { [JsonProperty("took")] public int Took { get; set; } [JsonProperty("timed_out")] public bool TimedOut { get; set; } [JsonProperty("_shards")] public Shards Shards { get; set; } [JsonProperty("hits")] public Hits Hits { get; set; } }

el siguiente es

"_shards": { "total":91, "successful":91, "skipped":0, "failed":0 },

asi que

public class Shards { [JsonProperty("total")] public int Total { get; set; } // etc... }

Entonces hits

{ "total":1, "max_score":1.0, "hits": <IEnumerable because []> }

asi que

public class Hits { [JsonProperty("total")] public int Total { get; set; } [JsonProperty("max_score")] public int MaxScore { get; set; } [JsonProperty("hits")] public List<Hit> Hits { get; set; } }

entonces Hits lista:

{ "_index":"my-index", "_type":"doc", "_id":"TrxrZGYQRaDom5XaZp23", "_score":1.0, "_source": <object> },

asi que

public class Hit { [JsonProperty("_index")] public string Index { get; set; } // etc }

Y una vez que haya creado todos los que necesita, deserialice:

JsonConvert.DeserializeObject<SearchResult>(json);

Tengo una aplicación .NET que quiero usar para consultar Elasticsearch. Estoy consultando con éxito mi índice de Elasticsearch. El resultado se parece a esto:

{ "took":31, "timed_out":false, "_shards": { "total":91, "successful":91, "skipped":0, "failed":0 }, "hits":{ "total":1, "max_score":1.0, "hits":[ { "_index":"my-index", "_type":"doc", "_id":"TrxrZGYQRaDom5XaZp23", "_score":1.0, "_source":{ "my_id":"65a107ed-7325-342d-adab-21fec0a97858", "host":"something", "zip":"12345" } }, ] } }

En este momento, estos datos están disponibles a través de la propiedad Body en el StringResponse que estoy recibiendo de Elasticsearch. Quiero deserializar los registros reales (no quiero ni necesito las propiedades timed_out , timed_out , etc.) en un objeto C # denominado results . En un intento de hacer esto, tengo:

var results = JsonConvert.DeserializeObject<List<Result>>(response.Body);

La clase de Result ve así:

public class Result { [JsonProperty(PropertyName = "my_id")] public string Id { get; set; } [JsonProperty(PropertyName = "host")] public string Host { get; set; } [JsonProperty(PropertyName = "zip")] public string PostalCode { get; set; } }

Cuando ejecuto esto, me sale el siguiente error:

No se puede deserializar el objeto JSON actual en el tipo ''System.Collections.Generic.List`1 [Result]'' porque el tipo requiere una matriz JSON para deserializar correctamente.

Si bien el error tiene sentido, no sé cómo analizar los hits para simplemente extraer los datos de _source . La propiedad _source contiene los datos que quiero deserializar. Todo lo demás son solo metadatos que no me importan.

¿Hay alguna forma de hacer esto? ¿Si es así, cómo?


Primero deberá deserializar a un JToken genérico o un JToken JObject , como este:

var token = JsonConvert.DeserializeObject<JToken>(jsonString);

Y luego puede navegar a la propiedad _source que contiene los datos de su interés:

var hitsArray = token["hits"]["hits"] as JArray; var result = hitsArray[0]["_source"].ToObject<Result>();


Prueba la siguiente estructura generada por la función de pegado especial de VS:

public class Rootobject { public int took { get; set; } public bool timed_out { get; set; } public _Shards _shards { get; set; } public Hits hits { get; set; } } public class _Shards { public int total { get; set; } public int successful { get; set; } public int skipped { get; set; } public int failed { get; set; } } public class Hits { public int total { get; set; } public float max_score { get; set; } public Hit[] hits { get; set; } } public class Hit { public string _index { get; set; } public string _type { get; set; } public string _id { get; set; } public float _score { get; set; } public _Source _source { get; set; } } public class _Source { public string my_id { get; set; } public string host { get; set; } public string zip { get; set; } }


Puede usar la API LINQ-to-JSON de Json.Net para obtener solo los nodos en los que está interesado y luego convertirlos en una lista de resultados:

var results = JToken.Parse(response.Body) .SelectTokens("hits.hits[*]._source") .Select(t => t.ToObject<Result>()) .ToList();

Demostración de trabajo: https://dotnetfiddle.net/OkEpPA


http://json2csharp.com/ para convertir un json a clases c # y para mi prueba obtuve una cadena json de la conversión realizada en http://easyonlineconverter.com/converters/dot-net-string-escape.html

entonces he creado una aplicación de consola con esta clase:

using System.Collections.Generic; using Newtonsoft.Json; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string json = "{ /"took/":31, /"timed_out/":false, /"_shards/": { /"total/":91, /"successful/":91, /"skipped/":0, /"failed/":0 }, /"hits/":{ /"total/":1, /"max_score/":1.0, /"hits/":[ { /"_index/":/"my-index/", /"_type/":/"doc/", /"_id/":/"TrxrZGYQRaDom5XaZp23/", /"_score/":1.0, /"_source/":{ /"my_id/":/"65a107ed-7325-342d-adab-21fec0a97858/", /"host/":/"something/", /"zip/":/"12345/" } }, ] }}"; RootObject t = JsonConvert.DeserializeObject<RootObject>(json); } public class Shards { public int total { get; set; } public int successful { get; set; } public int skipped { get; set; } public int failed { get; set; } } public class Source { public string my_id { get; set; } public string host { get; set; } public string zip { get; set; } } public class Hit { public string _index { get; set; } public string _type { get; set; } public string _id { get; set; } public double _score { get; set; } public Source _source { get; set; } } public class Hits { public int total { get; set; } public double max_score { get; set; } public List<Hit> hits { get; set; } } public class RootObject { public int took { get; set; } public bool timed_out { get; set; } public Shards _shards { get; set; } public Hits hits { get; set; } } } }

espero que esto ayude