Как вы отлаживаете свои запросы в 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
, который можно разделить на 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
my Role.Visitor
, обратные сортировки по дате окончания и ограничивают результаты одним возвращенным. Это было бы именно то, что я хочу. В нескольких тысячах записей, которые у меня есть для Series, около 90% соответствуют этому профилю. К сожалению, запрос возвращает 0 результатов. Нет ошибки, просто никаких результатов. Я не знаю, если я неправильно использую API, если Nest создает структуру запроса, которая не имеет смысла, или я просто недостаточно знаю ElasticSearch. Когда я удаляю предложение Filter
, я получаю результат, но я не гарантирован, что каждому разрешено его видеть.
Как просмотреть JSON, который производит и отправляет Nest ElasticSearch?
Ответы
Ответ 1
Вы можете получить значения URL-адреса поискового запроса и тела запроса JSON следующим образом:
var requestURL = response.RequestInformation.RequestUrl;
var jsonBody = Encoding.UTF8.GetString(response.RequestInformation.Request);
Вы можете найти другие полезные свойства в RequestInformation
для отладки.
Ответ 2
Мне нравится делать это еще дальше, чем 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 node.
Ответ 3
NEST
- это барокко .NET 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);
}
}
Ответ 4
Действительно легко. Если это мой код, который ищет:
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 Window, я ввожу это:
?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
Используя последний эластичный поиск 5+, я смог получить мой (благодаря методу Адриана Карра) со следующим:
var jsonOutput = System.Text.Encoding.UTF8.GetString(
response.ApiCall.RequestBodyInBytes
)
Который дал мне следующий результат:
{
"from":0,
"size":0,
"query":{
"bool":{
...
}
}
}
Ответ 6
Вы можете использовать EnableTrace
или ConnectionStatusHandler
. Подробнее здесь.
Ответ 7
Протестировано в гнезде 6.2.0
Теперь вы можете просто сделать:
#if DEBUG
connectionSettings.EnableDebugMode(details =>
{
Logger.Debug($"ES Request: {Encoding.UTF8.GetString(details.RequestBodyInBytes ?? new byte[0])}");
Logger.Verbose($"ES Response: {Encoding.UTF8.GetString(details.ResponseBodyInBytes ?? new byte[0])}");
});
#endif
Вызов EnableDebugMode
будет автоматически вызывать DisableDirectStreaming
, PrettyJson
, а затем OnRequestCompleted
, передавая функцию, которую вы ему дали.
ПРИМЕЧАНИЕ. Может быть ошибка где-то в их ответе. По какой-то причине ответ, похоже, не имеет некоторых закрывающих скобок.