NEST V7.12.1 - 检测到类型为 'Elasticsearch.Net.ApiCallDetails' 的 属性 'response' 的自引用循环
NEST V7.12.1 - Self referencing loop detected for property 'response' with type 'Elasticsearch.Net.ApiCallDetails'
我对 ElasticSearch 还很陌生,目前正在尝试使用它来工作,但是在尝试进行 Regex 查询时,出现以下错误:
Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'response' with type 'Elasticsearch.Net.ApiCallDetails'. Path 'apiCall.originalException'.
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, 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")
)
)
);
(我只是想让任何正则表达式查询正常工作)。
当我执行一个没有找到任何结果的 Regex 查询时,它没有给出任何错误,所以它是(我猜)我的对象中的东西。在网上我发现你可以忽略这个错误,但是这些都是针对版本 6 的,我无法在版本 7 中使用它。这是最好的(阅读:我没有错误)版本,但是我仍然得到了错误。
当我执行“正常”匹配查询时,它确实工作正常并且我得到了我的结果。
var settings = new ConnectionSettings(pool, (builtInSerializer, connectionSettings) =>
new JsonNetSerializer(builtInSerializer, connectionSettings, () => new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
}))
.DefaultFieldNameInferrer(p => p)
.PrettyJson();
;
错误很奇怪;它是 Newtonsoft.Json.JsonSerializationException
,但 7.12.1 客户端不在内部使用 Newtonsoft.Json。
使用 Newtonsoft.Json 的序列化程序可以根据您的第二个代码示例配置为 JsonNetSerializer
,但此序列化程序用于反序列化您的文档,不会用于反序列化 Elasticsearch.Net.ApiCallDetails
,这是一个低级别的客户端类型。
我试图用 Nest 7.12.1 复制错误,但我做不到。然而,正则表达式存在一些问题;
- 封闭的
/
和 g
修饰符无效或不受 the regular expression engine 支持,可以省略。
- 由于正则表达式值是 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
}
- 我认为
.
也需要转义(否则匹配任何字符)。
综上所述,这是一个工作示例
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
的文档
我对 ElasticSearch 还很陌生,目前正在尝试使用它来工作,但是在尝试进行 Regex 查询时,出现以下错误:
Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'response' with type 'Elasticsearch.Net.ApiCallDetails'. Path 'apiCall.originalException'. at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, 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")
)
)
);
(我只是想让任何正则表达式查询正常工作)。 当我执行一个没有找到任何结果的 Regex 查询时,它没有给出任何错误,所以它是(我猜)我的对象中的东西。在网上我发现你可以忽略这个错误,但是这些都是针对版本 6 的,我无法在版本 7 中使用它。这是最好的(阅读:我没有错误)版本,但是我仍然得到了错误。
当我执行“正常”匹配查询时,它确实工作正常并且我得到了我的结果。
var settings = new ConnectionSettings(pool, (builtInSerializer, connectionSettings) =>
new JsonNetSerializer(builtInSerializer, connectionSettings, () => new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
}))
.DefaultFieldNameInferrer(p => p)
.PrettyJson();
;
错误很奇怪;它是 Newtonsoft.Json.JsonSerializationException
,但 7.12.1 客户端不在内部使用 Newtonsoft.Json。
使用 Newtonsoft.Json 的序列化程序可以根据您的第二个代码示例配置为 JsonNetSerializer
,但此序列化程序用于反序列化您的文档,不会用于反序列化 Elasticsearch.Net.ApiCallDetails
,这是一个低级别的客户端类型。
我试图用 Nest 7.12.1 复制错误,但我做不到。然而,正则表达式存在一些问题;
- 封闭的
/
和g
修饰符无效或不受 the regular expression engine 支持,可以省略。 - 由于正则表达式值是 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
}
- 我认为
.
也需要转义(否则匹配任何字符)。
综上所述,这是一个工作示例
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