【问题标题】:NEST V7.12.1 - Self referencing loop detected for property 'response' with type 'Elasticsearch.Net.ApiCallDetails'NEST V7.12.1 - 为“Elasticsearch.Net.ApiCallDetails”类型的属性“响应”检测到自引用循环
【发布时间】:2021-07-31 16:37:23
【问题描述】:

我对 ElasticSearch 还很陌生,目前正在尝试使用它,但是在尝试进行正则表达式查询时,它会出现以下错误:

Newtonsoft.Json.JsonSerializationException:检测到类型为“Elasticsearch.Net.ApiCallDetails”的属性“响应”的自引用循环。路径“apiCall.originalException”。 在 Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer,对象值,JsonProperty 属性,JsonContract 合同,JsonContainerContract containerContract,JsonProperty containerProperty) 在 Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter 编写器,对象值,JsonContainerContract 合同,JsonProperty 成员,JsonProperty 属性,JsonContract& memberContract,Object& memberValue) ......

查询:

var ChildFileItems = ElasticClient.Search<FileData>(s => s
                //.From(0).Size(10)
                .Query(q => q
                    .Regexp(r => r
                        .Field(p => p.FilePath)
                        //.Value($"/{SearchPath}\\\\([A-Z a-z0-9_.-]+)[.]([A-Z a-z0-9]+)/g")
                        .Value(@$"/([A-Z a-z:0-9_.\\-]+)/g")
                    )
                )
            );

(我只是想让任何正则表达式查询工作)。 当我执行一个没有找到任何结果的正则表达式查询时,它没有给出错误,所以它(我猜)是我的对象中的一些东西。在线我发现你可以忽略这个错误,但是这些都是针对版本 6 的,我无法让它在版本 7 中工作。这是最好的(阅读:我没有错误)版本,但是有了这个我仍然得到错误。

当我执行“正常”匹配查询时,它确实可以正常工作并且我得到了我的结果。

var settings = new ConnectionSettings(pool, (builtInSerializer, connectionSettings) =>
                new JsonNetSerializer(builtInSerializer, connectionSettings, () => new JsonSerializerSettings
                {
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                }))
                .DefaultFieldNameInferrer(p => p)
                .PrettyJson();
            ;

【问题讨论】:

    标签: elasticsearch nest


    【解决方案1】:

    错误很奇怪;是Newtonsoft.Json.JsonSerializationException,但 7.12.1 客户端内部不使用 Newtonsoft.Json。

    使用 Newtonsoft.Json 的序列化程序可以根据您的第二个代码示例配置为 JsonNetSerializer,但此序列化程序用于反序列化您的文档,不会用于反序列化 Elasticsearch.Net.ApiCallDetails,这是一个低级别的客户类型。

    我尝试使用 Nest 7.12.1 复制错误,但无法复制。然而,正则表达式存在一些问题;

    1. 封闭的/g 修饰符无效或不受the regular expression engine 支持,可以省略。
    2. 由于正则表达式值是verbatim string,所以\\ 在查询中发送时就是文字\\\\,这会导致错误:
    // Request
    POST http://localhost:9200/default_index/_search?pretty=true&typed_keys=true 
    {
      "query": {
        "regexp": {
          "FilePath": {
            "value": "/([A-Z a-z:0-9_.\\\\-]+)/g"
          }
        }
      }
    }
    
    // Response
    Status: 400
    
    {
      "error" : {
        "root_cause" : [
          {
            "type" : "query_shard_exception",
            "reason" : "failed to create query: expected ']' at position 24",
            "index_uuid" : "83Lsg5kRR32c6iSK-1L5rw",
            "index" : "default_index"
          }
        ],
        "type" : "search_phase_execution_exception",
        "reason" : "all shards failed",
        "phase" : "query",
        "grouped" : true,
        "failed_shards" : [
          {
            "shard" : 0,
            "index" : "default_index",
            "node" : "1k1iMRXORXSEKvOH4Iz46Q",
            "reason" : {
              "type" : "query_shard_exception",
              "reason" : "failed to create query: expected ']' at position 24",
              "index_uuid" : "83Lsg5kRR32c6iSK-1L5rw",
              "index" : "default_index",
              "caused_by" : {
                "type" : "illegal_argument_exception",
                "reason" : "expected ']' at position 24"
              }
            }
          }
        ]
      },
      "status" : 400
    }
    
    1. 我认为. 也需要转义(否则匹配任何字符)。

    总而言之,这是一个工作示例

    private static void Main()
    {
        var defaultIndex = "default_index";
        var pool = new SingleNodeConnectionPool(new Uri($"http://localhost:9200"));
        var settings = new ConnectionSettings(pool, JsonNetSerializer.Default)
            .DefaultIndex(defaultIndex)
            .DefaultFieldNameInferrer(p => p)
            // The following settings are useful during development but come
            // with overhead and so likely don't want them in production.
            .DisableDirectStreaming()
            .PrettyJson()
            .OnRequestCompleted(callDetails =>
            {
                // Added this so that you can see the requests/responses to and
                // from Elasticsearch.
    
                if (callDetails.RequestBodyInBytes != null)
                {
                    var serializer = new JsonSerializer();
                    var jObjects = new List<JObject>();
                    using (var sr = new StringReader(Encoding.UTF8.GetString(callDetails.RequestBodyInBytes)))
                    using (var jsonTextReader = new JsonTextReader(sr))
                    {
                        jsonTextReader.SupportMultipleContent = true;
                        while (jsonTextReader.Read())
                            jObjects.Add((JObject)JObject.ReadFrom(jsonTextReader));
                    }
                    
                    var formatting =  jObjects.Count == 1 
                        ? Newtonsoft.Json.Formatting.Indented 
                        : Newtonsoft.Json.Formatting.None;
                    var json = string.Join("\n", jObjects.Select(j => j.ToString(formatting)));
                    
                    Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri} \n{json}");
                }
                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);
    
        if (client.Indices.Exists(defaultIndex).Exists)
            client.Indices.Delete(defaultIndex);
        
        client.Bulk(b => b
            .Index(defaultIndex)
            .IndexMany(new [] {
                new FileData { FilePath = "Foo.jpg" },
                new FileData { FilePath = "^$%*#@" },
            })
            .Refresh(Refresh.WaitFor)
        );
        
        var searchResponse = client.Search<FileData>(s => s
            .Query(q => q
                .Regexp(r => r
                    .Field(p => p.FilePath)
                    .Value(@"([A-Z a-z:0-9_\.\-]+)")
                )
            )
        );
    }
    
    public class FileData 
    {
        public string FilePath {get;set;}
    }
    

    查找文件路径为Foo.jpg的文档

    【讨论】:

    • 这似乎太有效了!我自己也进行了一些测试,但由于正则表达式不起作用,我确实收到了错误,因为使用您的代码,无论是否设置 JsonNetSerializer,我都不会收到错误。非常感谢:)
    猜你喜欢
    • 1970-01-01
    • 2016-11-27
    • 2018-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-11
    • 2017-02-13
    • 2021-12-26
    相关资源
    最近更新 更多