elasticsearch,nest,elasticsearch.net,C#,elasticsearch,Nest,Elasticsearch.net" /> elasticsearch,nest,elasticsearch.net,C#,elasticsearch,Nest,Elasticsearch.net" />

C# 如何修复ElasticSearch索引中无意重复的值?

C# 如何修复ElasticSearch索引中无意重复的值?,c#,elasticsearch,nest,elasticsearch.net,C#,elasticsearch,Nest,Elasticsearch.net,我最近继承了应用程序使用的一些搜索代码的所有权,并且正在清理上一位开发人员所做的一些更改。当我开始使用PostMan挖掘索引结构时,我们在尝试查询已排序的文档列表时遇到了一些问题。我偶然发现,我们的索引结构从上一个版本变为新的版本。保存动态生成的值的树结构已更改,现在包含两个相同的头。这里有一个例子来说明我的意思: 原始结构: "_doc": { "properties": { *some other properties* "va

我最近继承了应用程序使用的一些搜索代码的所有权,并且正在清理上一位开发人员所做的一些更改。当我开始使用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)
                                                )


var createResponse=client.CreateIndex(
指数
c=>c
.设置(
s=>s
.NumberOfShard(1)
.numberofreplications(0))
.映射(
ms=>ms
.地图(
m=>m
.DateDetection(错误)
.数字检测(错误)
.AutoMap(新值visitor())
.物业(
属性=>属性
*其他一些映射*
.Object(obj=>obj
.Name(Name=>Name.Values)
)
同时,SearchDocument.cs类使用以下方法填充AutoMap用于生成值结构的成员。我们有2个:值,它包含字符串,ValuesNumber,它包含小数。最近的更改是添加此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)} ";
                }
            }


私有void构建值字段(IEnumerable metaDataValues、IEnumerable tableValues)
{
值=新字典();
ValuesAsNumber=新字典();
if(metaDataValues!=null)
{
foreach(metaDataValues中的var值)
{
var field=\u fields.GetOrDefault(value.FieldId,null);
var processedValue=PrepareValue(value.TextValue);
值[SearchDocumentFields.GetValueFieldName(value.FieldId)]=processedValue;
//若字段是数字或日期,我们存储一个数字表示以进行排序
if(field!=null&(field.DataType==FieldType.Number | | field.DataType==FieldType.Date))
{
ValuesAsNumber[SearchDocumentFields.GetValueFieldAsNumberName(value.FieldId)]=
MetaDataValue.ConvertToDecimal(processedValue);
}
}
}
如果(tableValues为空)
{
返回;
}
foreach(tableValues中的var值)
{
var fieldName=SearchDocumentFields.GetValueFieldName(value.FieldId);
如果(!Values.ContainsKey(fieldName))
{
值[fieldName]=字符串。空;
}
值[fieldName]+=$“{PrepareValue(value.TextValue)}”;
}
}
这在SearchDocument类构造函数中调用,以在实例化类时填充属性


有人对创建这些额外索引对象的位置有什么建议吗?我一直无法找到答案。

我为后来遇到这个问题的人找到了解决方案。在一个名为SearchDocumentFields.cs的类上有一个帮助器方法,该方法处理字段的名称格式设置。直到在使用时,它将存储的名称从“f_5”更改为“values.f_5”,自动映射使用该名称将多余的不必要对象强制放入索引结构的JSON继承结构中。