我最近继承了我们的应用程序使用的一些搜索代码的所有权,并且正在清理最后一位开发人员的一些更改。当我开始使用 PostMan 挖掘索引结构时,我们在尝试查询排序的文档列表时遇到了问题。我遇到了一些事情,从我们的索引结构的最后一个版本更改为更改后的新版本。保存我们动态生成的值的树结构发生了变化,现在两次包含相同的两个标题。这是我的意思的一个例子:
原始结构:
"_doc": {
"properties": {
*some other properties*
"values": {
"properties": {
"field_10": {
"type": "text"
},
"field_11": {
"type": "text"
},
*more dynamically generated fields*
}
}
}
}
和新结构,唯一的区别是重复值:
"_doc": {
"properties": {
*some other properties*
"values": {
"properties": {
"values": {
"properties": {
"f_10": {
"type": "text"
},
"f_11": {
"type": "text"
},
*more dynamically generated fields*
}
}
}
}
}
}
我相信当我们尝试获取排序列表时,这些标题是导致问题的原因。当我发送查询以对字段 f_5 进行排序时,从 NEST 返回的错误如下。
Invalid NEST response built from a unsuccessful low level call on POST: /td_3dfb600bfd4140d4bd229a356496aca4_documents/_search?typed_keys=true
# Audit trail of this API call:
- [1] BadResponse: Node: http://localhost:9200/ Took: 00:00:00.0150146
# OriginalException: Elasticsearch.Net.ElasticsearchClientException: The remote server returned an error: (400) Bad Request.. Call: Status code 400 from: POST /td_3dfb600bfd4140d4bd229a356496aca4_documents/_search?typed_keys=true. ServerError: Type: search_phase_execution_exception Reason: "all shards failed" ---> System.Net.WebException: The remote server returned an error: (400) Bad Request.
at System.Net.HttpWebRequest.GetResponse()
at Elasticsearch.Net.HttpWebRequestConnection.Request[TResponse](RequestData requestData)
--- End of inner exception stack trace ---
# Request:
{"from":0,"query":{"bool":{"must":[{"term":{"formTypeProductId":{"value":1}}},{"bool":{"minimum_should_match":1,"should":[{"term":{"activeStep":{"value":5}}}]}},{"bool":{"minimum_should_match":1,"should":[{"term":{"documentStatus":{"value":1}}},{"term":{"documentStatus":{"value":0}}},{"term":{"documentStatus":{"value":2}}}]}}]}},"size":100,"sort":[{"values.f_5.keyword":{"missing":"_last","order":"asc"}},{"documentId":{"order":"asc"}}]}
# Response:
{"error":{"root_cause":[{"type":"query_shard_exception","reason":"No mapping found for [values.f_5.keyword] in order to sort on","index_uuid":"Fz6gWcm4TdGmh1bDAspjBg","index":"td_3dfb600bfd4140d4bd229a356496aca4_documents"}],"type":"search_phase_execution_exception","reason":"all shards failed","phase":"query","grouped":true,"failed_shards":[{"shard":0,"index":"td_3dfb600bfd4140d4bd229a356496aca4_documents","node":"uM9FlJg1SuCN4-gZdeDHig","reason":{"type":"query_shard_exception","reason":"No mapping found for [values.f_5.keyword] in order to sort on","index_uuid":"Fz6gWcm4TdGmh1bDAspjBg","index":"td_3dfb600bfd4140d4bd229a356496aca4_documents"}}]},"status":400}
我们用来查询的代码没有改变,之前运行得很好。我相信添加的索引树对象是导致客户端无法找到有效映射的原因。
到目前为止,我已经尝试修改对 NEST 的 .CreateIndex() 方法的调用,在该方法中,我们使用 .AutoMap 从类 SearchDocument.cs 中提取有效的文档信息。我还尝试修改 SearchDocument 类本身,因为这是最近发生更改的地方,但没有任何改变。
CreateIndex 中的调用使用以下方法完成:
var createResponse = client.CreateIndex(
index,
c => c
.Settings(
s => s
.NumberOfShards(1)
.NumberOfReplicas(0))
.Mappings(
ms => ms
.Map<SearchDocument>(
m => m
.DateDetection(false)
.NumericDetection(false)
.AutoMap(new ValuesVisitor())
.Properties(
properties => properties
*Some other mappings*
.Object<Dictionary<string, string>>(obj => obj
.Name(name => name.Values)
)
同时,SearchDocument.cs 类使用以下方法填充 AutoMap 使用的成员以生成值结构。我们有 2 个:保存字符串的 Values 和保存小数的 ValuesAsNumber。最近的更改是添加此 ValuesAsNumber 属性并将其添加到索引中。
private void BuildValuesFields(IEnumerable<MetaDataValue> metaDataValues, IEnumerable<TableValue> tableValues)
{
Values = new Dictionary<string, string>();
ValuesAsNumber = new Dictionary<string, decimal?>();
if (metaDataValues != null)
{
foreach (var value in metaDataValues)
{
var field = _fields.GetOrDefault(value.FieldId, null);
var processedValue = PrepareValue(value.TextValue);
Values[SearchDocumentFields.GetValueFieldName(value.FieldId)] = processedValue;
// if field is Number or Date, we store a numerical representation for sorting
if (field != null && (field.DataType == FieldType.Number || field.DataType == FieldType.Date))
{
ValuesAsNumber[SearchDocumentFields.GetValueFieldAsNumberName(value.FieldId)] =
MetaDataValue.ConvertToDecimal(processedValue);
}
}
}
if (tableValues is null)
{
return;
}
foreach (var value in tableValues)
{
var fieldName = SearchDocumentFields.GetValueFieldName(value.FieldId);
if (!Values.ContainsKey(fieldName))
{
Values[fieldName] = string.Empty;
}
Values[fieldName] += $"{PrepareValue(value.TextValue)} ";
}
}
这在 SearchDocument 类构造函数中调用,以在我们实例化类时填充属性。
有人对寻找这些额外索引对象的创建位置有任何建议吗?我一直想不通。