【问题标题】:How do you debug your Nest queries?你如何调试你的 Nest 查询?
【发布时间】:2015-03-24 05:53:08
【问题描述】:

我是 Nest 新手,我很可能不会像我想的那样创建查询。我的问题更像是教人钓鱼而不是给我一条鱼。不过,我会以我目前的问题为例。

我在 ElasticSearch 中有几个 Series 类型的文档。我将在下面使用与查询相关的信息将其存根,而不使用属性和公共修饰符:

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

这些都很好,花花公子。我可以Get() 一个Series 对象没问题。我遇到的问题是试图弄清楚 Nest 是如何格式化我的查询的。我的直接目标是找到可发布到Role.Visitor 的最新Series。我这样设置 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 的那些,按结束日期反向排序,并将结果限制为一个返回。那正是我想要的。在我为 Series 拥有的数千条记录中,大约 90% 符合此配置文件。不幸的是,查询返回 0 个结果。没有错误,只是没有结果。我不知道的是我是否错误地使用了 API,Nest 是否生成了一个没有意义的查询结构,或者我只是不太了解 ElasticSearch。当我删除 Filter 子句时,我会得到一个结果,但我不能保证每个人都可以看到它。

如何查看 Nest 生成并发送到 ElasticSearch 的 JSON?

【问题讨论】:

标签: c# elasticsearch nest


【解决方案1】:

您可以获取搜索请求 URL 和 JSON 请求正文的值,如下所示:

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

您可以在RequestInformation 中找到其他有用的属性进行调试。

【讨论】:

  • 如果我执行“查询”:{“match”:{“releasableTo”:“Visitor”)),我会得到我想要的。我认为我的索引需要一些微调。
【解决方案2】:

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);
        }                                                                         
    }

【讨论】:

  • PrettyJson、DisableDirectStreaming 和 OnRequestCompleted 都可以在较新版本的 Nest 中使用 EnableDebugMode 在一次调用中完成。例如,请参阅下面的答案。
【解决方案3】:

我喜欢比 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 2.4.5 中,Serialize 函数不再返回字符串,必须将目标 Stream 作为参数。例如使用 (var searchRequestStream = new MemoryStream()) { client.Serializer.Serialize(seriesSearch, searchRequestStream); var searchRequestString = Encoding.UTF8.GetString(searchRequestStream.GetBuffer()); }
【解决方案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 即时窗口中,输入:

?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"
            }
          }
        }
      ]
    }
  }
}

希望这会有所帮助。

【讨论】:

  • 这是一个非常有用的技术。
  • 不确定我缺少什么,但我在结果对象上看不到 ConnectionStatus 属性
【解决方案5】:

使用最新的弹性搜索 5+,我能够通过以下方式获得我的(感谢 Adrian Carr 的方法):

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

这给了我以下输出:

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

【讨论】:

    【解决方案6】:

    Elasticsearch.Net 和 NEST:.NET 客户端 [7.x]

    参考:https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/debug-information.html`

    1. 在 ES 全局设置中启用 DisableDirectStreaming,如下所示。

    参考代码

    Var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
    
    var settings = new ConnectionSettings(connectionPool)
        .DisableDirectStreaming(true); 
    
    var client = new ElasticClient(settings);
    

    2.) var response = client.Search&lt;Project&gt;(s =&gt;....)

    3.)

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

    可以根据每个请求通过以下方式实现上述目标。

    var response = client.Search<Project>(s => s
        .RequestConfiguration(r => r
            .DisableDirectStreaming() 
        )
        .Query(q => q
            .MatchAll()
        )
    );
    

    【讨论】:

      【解决方案7】:

      您可以使用EnableTraceConnectionStatusHandler。更多详情here.

      【讨论】:

        【解决方案8】:

        Nest 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会自动调用DisableDirectStreamingPrettyJson,然后是OnRequestCompleted,传入你给它的函数。

        注意:他们的回复内容中可能存在错误。由于某种原因,响应似乎缺少一些右括号。

        【讨论】:

          【解决方案9】:

          在我当前版本的 Elasticsearch.NET/NEST (7.13.2) 中,我可以捕获 ElasticsearchClientException 并利用 DebugInformation。如果DisableDirectStreaming 的设置与其他答案一样,则包含完整的请求正文。

          try {
              // do some elastic stuff
          } catch (ElasticsearchClientException e) {
              Logger.LogInformation(e.DebugInformation);
              // handle error
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-09-07
            • 2016-01-19
            • 2010-11-14
            • 2015-05-31
            • 2018-12-17
            • 1970-01-01
            • 2013-09-02
            • 2010-10-07
            相关资源
            最近更新 更多