首页 > 解决方案 > 为什么 ElasticSearch Nest Query 中会出现转义反斜杠?

问题描述

我正在尝试编写一个获取queryString控制器并将其转换为ElasticSearch查询的 C# 方法,如下所示:

public QueryContainerDescriptor<T> Convert<T> (IQueryCollection query) where T: class
{
    var selector = new QueryContainerDescriptor<T>();
    List<QueryContainer> Must = new List<QueryContainer>();
    foreach(var key in query.keys)
    {
        string value = query[key];
        var match = new MatchQuery { Field = $"{key}.keyword", Query = value };
        list.Add(match)
    }
    selector.Bool(q => q.Must(Must.ToArray()));
    return selector;
}

queryString它按预期工作,但如果我用反斜杠传递一个值,例如:

http://localhost:5000/api/indexData?user=ESKA\\USER

它应该被转换成这个查询:

{ "bool": { "must": [ { "match" : { "user.keyword": "ESKA\\USER" } } ] }

但是ElasticSearch不会返回任何内容,因为查询的值将是:ESKA\\\\USER带有 4 个反斜杠,例如:

{ "bool": { "must": [ { "match" : { "user.keyword": "ESKA\\\\USER" } } ] }

我该如何解决这个问题?

标签: c#.netstringelasticsearchnest

解决方案


我不认为 N​​est 正在执行任何反斜杠转义。这是一个写出请求(和响应,如果使用IConnection发送请求的)的示例

private static void Main()
{
    var pool = new SingleNodeConnectionPool(new Uri($"http://localhost:9200"));
    var settings = new ConnectionSettings(pool, new InMemoryConnection())
        .DefaultIndex("default_index")
        .DisableDirectStreaming()
        .PrettyJson()
        .OnRequestCompleted(callDetails =>
        {
            if (callDetails.RequestBodyInBytes != null)
            {
                var json = JObject.Parse(Encoding.UTF8.GetString(callDetails.RequestBodyInBytes));
    
                Console.WriteLine(
                    $"{callDetails.HttpMethod} {callDetails.Uri} \n" +
                    $"{json.ToString(Newtonsoft.Json.Formatting.Indented)}");
            }
            else
            {
                Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}");
            }
    
            Console.WriteLine();
    
            if (callDetails.ResponseBodyInBytes != null)
            {
                Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
                         $"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}\n" +
                         $"{new string('-', 30)}\n");
            }
            else
            {
                Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
                         $"{new string('-', 30)}\n");
            }
        });
        
    var client = new ElasticClient(settings);
    
    var collection = new QueryCollection(new Dictionary<string, StringValues>
    {
        { "user", "ESKA\\USER" }
    });
    
    var response = client.Search<object>(s => s
        .Query(q => Convert<object>(q, collection))
    );
}

public static QueryContainerDescriptor<T> Convert<T>(QueryContainerDescriptor<T> selector, IQueryCollection query) where T : class
{
    List<QueryContainer> Must = new List<QueryContainer>();
    foreach (var key in query.Keys)
    {
        string value = query[key];
        var match = new MatchQuery { Field = $"{key}.keyword", Query = value };
        Must.Add(match);
    }
    selector.Bool(q => q.Must(Must.ToArray()));
    return selector;
}

结果查询是

POST http://localhost:9200/default_index/_search?pretty=true&typed_keys=true 
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "user.keyword": {
              "query": "ESKA\\USER"
            }
          }
        }
      ]
    }
  }
}

如果该user值是逐字字符串文字 @"ESKA\\USER",那么结果查询将是

"user.keyword": {
    "query": "ESKA\\\\USER"
}

因为\逐字字符串文字中的每个都需要转义。


推荐阅读