通过JSON.NET反序列化Elasticsearch结果

use*_*554 19 c# json.net elasticsearch

我有一个.NET应用程序,我想用它来查询Elasticsearch.我成功查询了我的Elasticsearch索引.结果看起来类似于:

{
  "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"
        }
      },
    ]
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,这个数据可以通过我从Elasticsearch返回的Body属性StringResponse获得.我想反序列化的实际记录(我不想要或需要的took,timed_out等属性)到一个名为C#对象results.为了做到这一点,我有:

var results = JsonConvert.DeserializeObject<List<Result>>(response.Body);
Run Code Online (Sandbox Code Playgroud)

这个Result类看起来像这样:

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; }
}
Run Code Online (Sandbox Code Playgroud)

当我运行它时,我收到以下错误:

无法将当前JSON对象反序列化为类型'System.Collections.Generic.List`1 [Result]',因为该类型需要JSON数组才能正确反序列化.

虽然错误有意义,但我不知道如何解析hits只是提取_source数据.该_source属性包含我要反序列化的数据.其他一切都只是我不关心的元数据.

有没有办法做到这一点?如果是这样,怎么样?

Bri*_*ers 12

您可以使用Json.Net的LINQ-to-JSON API来获取您感兴趣的节点,然后将它们转换为结果列表:

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

工作演示:https://dotnetfiddle.net/OkEpPA


Eri*_*ips 8

嗯,你跟DeserializeObject<T> TJson不匹配.你的Json以a开头,{所以你的T需要是一个类(不是一个IEnumerable类).

让我们从外面开始,继续努力:

{
  "took":31,
  "timed_out":false,
  "_shards": <object>
  "hits": <object>
}
Run Code Online (Sandbox Code Playgroud)

所以:

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; }
}
Run Code Online (Sandbox Code Playgroud)

接下来是 _shards

"_shards": {
  "total":91,
  "successful":91,
  "skipped":0,
  "failed":0
},
Run Code Online (Sandbox Code Playgroud)

所以

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

然后 hits

{
  "total":1,
  "max_score":1.0,
  "hits": <IEnumerable because []>
}
Run Code Online (Sandbox Code Playgroud)

所以

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; }
}
Run Code Online (Sandbox Code Playgroud)

然后Hits列出:

{
    "_index":"my-index",
    "_type":"doc",
    "_id":"TrxrZGYQRaDom5XaZp23",
    "_score":1.0,
    "_source":  <object>
},
Run Code Online (Sandbox Code Playgroud)

所以

public class Hit
{
  [JsonProperty("_index")]
  public string Index { get; set; }
  // etc
}
Run Code Online (Sandbox Code Playgroud)

一旦你创建了所有你需要的东西,那么你反序列化:

JsonConvert.DeserializeObject<SearchResult>(json);
Run Code Online (Sandbox Code Playgroud)


the*_*000 5

您需要首先反序列化为泛型,JToken或者JObject像这样:

var token = JsonConvert.DeserializeObject<JToken>(jsonString);
Run Code Online (Sandbox Code Playgroud)

然后您可以导航到包含您感兴趣的数据的_source属性:

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