Как я могу исправить непреднамеренно повторяющиеся значения в индексе ElasticSearch? - PullRequest
2 голосов
/ 06 марта 2020

Я недавно унаследовал право собственности на некоторый поисковый код, используемый нашим приложением, и работаю над тем, чтобы исправить некоторые изменения последнего разработчика. Мы столкнулись с проблемами, пытаясь запросить отсортированные списки документов, когда я начал копаться в структуре индекса с помощью 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*
                   }
                }
             }
          }
       }
    }

I Поверьте, эти заголовки являются причиной проблемы, когда мы пытаемся получить отсортированный список. Ошибка, возвращаемая из NEST, заключается в следующем, когда я отправляю запрос для сортировки в поле f_5.


    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}

Код, который мы используем для запроса, не изменился и прекрасно работал ранее. Я полагаю, что добавленные объекты дерева индекса являются причиной того, что клиент не может найти правильное отображение.

До сих пор я пытался изменить наш вызов метода .CreateIndex () NEST, в котором мы используем. 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 для заполнения свойств при создании экземпляра класса.

Кто-нибудь есть какие-либо советы о местах, где искать эти дополнительные объекты индекса создаются? Я не смог понять это.

...