Как отлаживать запросы Nest?

Я новичок в Nest, и я, скорее всего, не создаю свой запрос, как я думаю. Мой вопрос больше похож на то, чтобы научить человека ловить рыбу, а не давать мне рыбу. Однако в качестве примера я приведу свою текущую проблему.

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

class Series
{
    string Id {get; set;}
    DateTime StartDate {get; set;}
    DateTime EndDate {get; set;}
    HashSet<Role> ReleasableTo {get; set;}
}

они все в порядке и денди. Я может Get() a Series объект без проблем. Проблема, с которой я сталкиваюсь, - это попытка выяснить, как Nest форматирует мой запрос. Моя непосредственная цель-найти самые последние Series то releasable к Role.Visitor. Я настроил запрос Nest следующим образом:

ISearchResponse<Series> response = client
    .Search<Series>(r => 
         r.Filter(f => 
             f.Term<Role>(t=>t.ReleasableTo.First(), Role.Visitor))
    .SortDescending(ser => ser.EndDate).Size(1));

на мой взгляд, это должно быть создание запроса, который фильтрует серию, поэтому он рассматривает только те, которые ReleasableTo мой Role.Visitor, обратные сортировки по дате окончания и ограничивает результаты одним возвращенным. Что будет именно этого я и хочу. В нескольких тысячах записей, которые у меня есть для серии, около 90% соответствуют этому профилю. К сожалению запрос возвращает 0 результатов. Ошибки нет, просто нет результатов. Я не знаю, неправильно ли я использую API, если Nest создает структуру запроса, которая не имеет смысла, или я просто недостаточно хорошо знаю ElasticSearch. Когда я удаляю Filter пункт я получаю результат, но я не гарантирую, что всем разрешено его видеть.

как просмотреть JSON, который Nest производит и отправляет ElasticSearch?

6 ответов


вы можете получить значения URL-адреса поискового запроса и тела запроса JSON, как показано ниже:

var requestURL = response.RequestInformation.RequestUrl;
var jsonBody = Encoding.UTF8.GetString(response.RequestInformation.Request);

Вы можете найти другие полезные свойства в RequestInformation для отладки.


Мне нравится делать шаг дальше, чем предлагает bsarkar, и полностью устранить необходимость в поездке туда и обратно:

var client = new ElasticClient();

var seriesSearch = new SearchDescriptor<Series>();
seriesSearch.Filter(f => f
    .Term<Role>(t => t.ReleasableTo.First(), Role.Visitor))
    .SortDescending(ser => ser.EndDate)
    .Size(1));

string searchJson = Encoding.UTF8.GetString(client.Serializer.Serialize(seriesSearch));

обратите внимание, что ваш ElasticClient не нуждается в каких-либо свойствах соединения, поэтому у вас нет зависимости от узла ES.


NEST - это барокко .Чистый API-интерфейсы. Для 2.1+ на уровне вызова:

IElasticClient client = new ElasticClient();
var searchDescriptor = new SearchDescriptor<Series>();
var query = Query<Series>.Term(...);
var pretty = query.ToPrettyString(query);
var json = client.ToRawRequest(searchDescriptor.Query(descriptor => query));

на уровне конфигурации:

    var settings = new ConnectionSettings()
                     .PrettyJson().DisableDirectStreaming()
                     .OnRequestCompleted(details=> Debug.WriteLine(Encoding.UTF8.GetString(details.RequestBodyInBytes)));

на уровне ответа посмотрите в CallDetails.RequestBodyInBytes.

используемые расширения:

    /// <summary>
    /// Converts search to raw JSON request for debugging.
    /// </summary>
    /// <typeparam name="T">The type.</typeparam>
    /// <param name="self">The self.</param>
    /// <param name="searchDescriptor">The search descriptor.</param>
    /// <returns>The string.</returns>
    public static string ToRawRequest<T>(this IElasticClient self, SearchDescriptor<T> searchDescriptor) where T : class
    {
        using (var output = new MemoryStream())
        {
            self.Serializer.Serialize(searchDescriptor, output);
            output.Position = 0;
            var rawQuery = new StreamReader(output).ReadToEnd();
            return rawQuery;
        }
    }

    /// <summary>
    /// Prints query into string.
    /// </summary>
    /// <param name="self">The self.</param>
    /// <returns>The value.</returns>
    public static string ToPrettyString(this QueryContainer self)
    {
        using (var settings = new ConnectionSettings())
        {
            var visitor = new DslPrettyPrintVisitor(settings);
            self.Accept(visitor);
            return visitor.PrettyPrint.Replace(Environment.NewLine, string.Empty);
        }                                                                         
    }

очень легко. Если это мой код, который ищет:

var results = client.Search<SearchItem>(s => s.AllIndices()
    .Query(q =>
            q.Term(p => p.LastName, searchItem.LastName)
            && q.Term(p => p.FirstName, searchItem.FirstName)
            && q.Term(p => p.ApplicationCode, searchItem.ApplicationCode)
            )
    .Size(1000)
    );
var list = results.Documents.ToList();

затем я устанавливаю точку останова на линии выше. Затем в окне Visual Studio Immediate я ввожу следующее:

?results.ConnectionStatus

и это дает мне следующее:

{StatusCode: 200, 
    Method: POST, 
    Url: http://localhost:9200/_all/searchitem/_search, 
    Request: {
  "size": 1000,
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "lastName": {
              "value": "carr"
            }
          }
        },
        {
          "term": {
            "firstName": {
              "value": "adrian"
            }
          }
        }
      ]
    }
  }
}

надеюсь, что это помогает.


используя последний эластичный поиск 5+, я смог получить свой (благодаря методу Адриана Карра) со следующим:

var jsonOutput = System.Text.Encoding.UTF8.GetString(
    response.ApiCall.RequestBodyInBytes
)

что дало мне следующий результат:

{
   "from":0,
   "size":0,
   "query":{
      "bool":{
      ...
      }
   }
}

можно использовать EnableTrace или ConnectionStatusHandler. Подробнее здесь.