Невозможно получить ключ-словарь _source словаря из эластичного клиентского ответа - PullRequest
0 голосов
/ 11 января 2019

Я пытаюсь получить доступ к словарю хитов _source для загрузки в БД. Хиты возвращают ноль, что я делаю не так?

Примечания: searchResponse возвращается с данными JSON, и отладочная информация подтверждает это.

Однако класс Hit, класс _Source и переменные, лежащие в их основе, недоступны, и попадания переменных возвращают ноль.

Приведенный ниже код локальной переменной в режиме отладки показывает данные. При необходимости я могу добавить больше данных или изображения локальных переменных или окна отладочной информации, если это поможет решить проблему.

Заранее спасибо.

Попытка доступа к парам значений ключа _source с помощью searchResponse.Documents и оператора foreach для доступа к элементам внутри попаданий. Но не удалось получить доступ к парам значений ключей _source.

/*Declared classes in visual studio console application for c#:
.NET framework 4.5*/

class Program
{

    public class Doc
    {
        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 int duration { get; set; }
        public string group_id { get; set; }
        public DateTime var_time { get; set; }
        public string var_name { get; set; }
    }

    static void Main(string[] args)
    {
        var uri = new Uri("http://domain_name.val.url:9203/");
        var pool = new SingleNodeConnectionPool(uri);
        var connectionSettings = new ConnectionSettings(pool)
                                .DisableDirectStreaming();
        var resolver = new IndexNameResolver(connectionSettings);
        var client = new ElasticClient(connectionSettings);

        if (!client.IndexExists("test_index").Exists)
        {
            client.CreateIndex("test_index");
        }

        var searchResponse = client.Search<Doc>(s => s
        .Index("test_index")
        .AllTypes()
        .Size(1)
        .Query(q => q
        .MatchAll())
        .TypedKeys(null)
        .SearchType(Elasticsearch.Net.SearchType.DfsQueryThenFetch)
        .Scroll("30s")
      );
    MessageBox.Show("searchResponse.DebugInformation=" + searchResponse.DebugInformation);
    }
}





Образец данных Elastic Search URL:

{
  "took" : 12,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2700881,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "test_index",
        "_type" : "doc",
        "_id" : "R22224!!5333e7e4-9ee3-45f4-9dc3-2a8b8d8cdcf8",
        "_score" : 1.0,
        "_source" : {
          "duration" : 14986283,
          "group_id" : "com",
          "var_time" : "2018-04-24T17:05:13.082+02:00",
          "var_name" : "2",
        }
      }
    ]
  }
}



Обновление: Кто-то внутри офиса предложил использовать следующее решение кода, а затем итерацию по паре ключ-значение.

        var searchResponse = client.Search<Doc>(s => s
            .Index("test_index")
            .AllTypes()
            .Size(10)
            .Query(q => q
            .MatchAll())
            .TypedKeys(null)
            .SearchType(Elasticsearch.Net.SearchType.DfsQueryThenFetch)
            .Scroll("30s")
            .RequestConfiguration(r=>r
            .DisableDirectStreaming()
            )
            );
        var raw = Encoding.UTF8.GetString(searchResponse.ApiCall.ResponseBodyInBytes);  
        JavaScriptSerializer jss = new JavaScriptSerializer();
        jss.MaxJsonLength = Int32.MaxValue;
        var pairs = jss.Deserialize<Dictionary<string, dynamic>>(raw); 

1 Ответ

0 голосов
/ 13 января 2019

Похоже, вы неправильно поняли API клиента; вам не нужно указывать _Shards, Hit, Hits, _Source и т. д., клиент позаботится о десериализации этих частей API Elasticsearch.

Единственная часть, которую вам нужно определить - это POCO, который будет сопоставляться с объектом JSON в каждом поле "_source" в ответе, т.е.

{
  "duration" : 14986283,
  "group_id" : "com",
  "var_time" : "2018-04-24T17:05:13.082+02:00",
  "var_name" : "2",
}

, что похоже на _Source POCO (хотя я был бы склонен дать ему более осмысленное имя!). Давайте сейчас просто назовем это MyDocument.

С MyDocument определяется как

public class MyDocument
{
    [PropertyName("duration")]
    public int Duration { get; set; }

    [PropertyName("group_id")]
    public string GroupId { get; set; }

    [PropertyName("var_time")]
    public DateTime Time { get; set; }

    [PropertyName("var_name")]
    public string Name { get; set; }
}

Простой поиск будет

var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));

var settings = new ConnectionSettings(pool)
    .DefaultMappingFor<MyDocument>(m => m
        .IndexName("test_index")
        .TypeName("doc")
    );

var client = new ElasticClient(settings);

var searchResponse = client.Search<MyDocument>();

// A collection of the top 10 matching documents
var documents = searchResponse.Documents;

DefaultMappingFor<MyDocument>(...) будет использовать имя индекса "test_index" и имя типа "doc" всякий раз, когда универсальный тип документа равен MyDocument, и они явно не определены в запросе.

Вышеуказанный поиск создает следующий запрос к Elasticsearch

POST http://localhost:9200/test_index/doc/_search
{}

Похоже, вы хотите использовать Scroll API для возврата всех соответствующих документов. Чтобы сделать это с помощью API прокрутки, вы должны написать цикл, чтобы продолжать делать запросы прокрутки, пока документы возвращаются

var searchResponse = client.Search<MyDocument>(s => s
    .Size(1000)
    .Scroll("30s")
);

while (searchResponse.Documents.Any())
{
    foreach (var document in searchResponse.Documents)
    {
        // do something with this set of 1000 documents
    }

    // make an additional request
    searchResponse = client.Scroll<MyDocument>("30s", searchResponse.ScrollId);
}

// clear scroll id at the end
var clearScrollResponse = client.ClearScroll(c => c.ScrollId(searchResponse.ScrollId));

Существует ScrollAll наблюдаемый помощник, который вы можете использовать для упрощения написания, и распараллеливает операцию, используя sliced_scroll. Та же операция, что и выше, но с использованием ScrollAll

// set to number of shards in targeted indices
var numberOfSlices = 4;

var scrollAllObservable = client.ScrollAll<MyDocument>("30s", numberOfSlices);

Exception exception = null;
var manualResetEvent = new ManualResetEvent(false);

var scrollAllObserver = new ScrollAllObserver<MyDocument>(
    onNext: s => 
    {
        var documents = s.SearchResponse.Documents;

        foreach (var document in documents)
        {
            // do something with this set of documents
        }
    },
    onError: e =>
    {
        exception = e;
        manualResetEvent.Set();
    },
    onCompleted: () => manualResetEvent.Set()
);

scrollAllObservable.Subscribe(scrollAllObserver);

manualResetEvent.WaitOne();

if (exception != null)
    throw exception;

Если вам не нужен полный контроль над наблюдателем, вы можете использовать упрощенную версию. При этом вам необходимо указать максимальное время выполнения всей операции, хотя

var numberOfSlices = 4;

var scrollAllObservable = client.ScrollAll<MyDocument>("30s", numberOfSlices)
    .Wait(TimeSpan.FromHours(2), onNext: s =>
        {
           var documents = s.SearchResponse.Documents;

           foreach (var document in documents)
           {
                // do something with this set of documents
            }
        });
...