Как избежать взрыва индекса в ElasticSearch

У меня есть два документа из одного и того же индекса, которые изначально выглядят так (здесь показано только значение _source)

{
    "id" : "3",
    "name": "Foo",
    "property":{
        "schemaId":"guid_of_the_RGB_schema_defined_extenally",
        "value":{
            "R":255,
            "G":100,
            "B":20
        }
    }
}
{
    "id" : "2",
    "name": "Bar",
    "property":{
        "schemaId":"guid_of_the_HSL_schema_defined_extenally",
        "value":{
            "H":255,
            "S":100,
            "L":20
        }
    }
}

Схема (используемая для проверки value) хранится вне ES, поскольку она не имеет ничего общего с индексацией. Если я не определяю сопоставление, поле value будет считаться сопоставлением Object. И его подполе будет расти, как только появится новое подполе.

В настоящее время ElasticSearch поддерживает плоское сопоставление https://www.elastic.co/guide/en/elasticsearch/reference/current/flattened.html, чтобы предотвратить взрывной рост индекса. Однако он имеет ограниченную поддержку поиска внутреннего поля из-за его ограничения: As with queries, there is no special support for numerics — all values in the JSON object are treated as keywords. When sorting, this implies that values are compared lexicographically.

Мне нужно иметь возможность запросить индекс, чтобы найти документ, соответствующий данному документу (например, B в диапазоне [10,30])

Пока я придумал решение, которое структурирует мой документ следующим образом.

{
    "id":4,
    "name":"Boo",
    "property":
    {
        "guid_of_the_normalized_RGB_schema_defined_extenally":
        {
           "R":0.1,
           "G":0.2,
           "B":0.5
        }
}

Хотя это не решает мою проблему резкого роста карт, но смягчает некоторые другие проблемы. Мое сопоставление теперь будет выглядеть примерно так для поля property

"property": {
        "properties": {
          "guid_of_the_RGB_schema_defined_extenally": {
            "properties": {
              "B": {
                "type": "long"
              },
              "G": {
                "type": "long"
              },
              "R": {
                "type": "long"
              }
            }
          },
          "guid_of_the_normalized_RGB_schema_defined_extenally": {
            "properties": {
              "B": {
                "type": "float"
              },
              "G": {
                "type": "float"
              },
              "R": {
                "type": "float"
              }
            },
          "guid_of_the_HSL_schema_defined_extenally": {
            "properties": {
              "B": {
                "type": "float"
              },
              "G": {
                "type": "float"
              },
              "R": {
                "type": "float"
              }
            }
          }
        }
      }

Это решает проблему, когда поле имеет одинаковое имя, но другой тип данных.

Может ли кто-нибудь предложить мне решение, которое могло бы решить проблему взрыва индексов, не страдая от ограничения, которое имеет Flattened при поиске?


person LxL    schedule 06.10.2020    source источник


Ответы (1)


Чтобы избежать взрывного картографирования, лучшее решение — лучше нормализовать данные. Вы можете установить dynamic: strict в вашем сопоставлении, тогда документ будет отклонен, если он содержит поле, которого еще нет в сопоставлении. После этого вы все еще можете добавлять новые поля, но вам нужно будет добавить их явно в сопоставление раньше.

Вы можете добавить определение конвейер для очистки и нормализации данных перед их добавлением.

Если вы не хотите или не можете переиндексировать:

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

GET myindex/_search
{
  "query": {
    "multi_match": {
      "query": 0.5,
      "fields": ["property.*.B"]
    }
  }
}

Но вы все равно не сможете отсортировать его так, как вам хочется. Для упорядочивания нескольких «неизвестных» имен полей, не касаясь данных, вы можете использовать скрипт: https://www.elastic.co/guide/en/elasticsearch/painless/current/painless-sort-context.html

Но, возможно, вы могли бы упростить весь процесс, добавив в свой индекс динамический шаблон.

PUT test/_mapping
{
  "dynamic_templates": [
    {
      "unified_red": {
        "path_match": "property.*.R",
        "mapping": {
          "type": "float",
          "copy_to": "unified_color.R"
        }
      }
    },
    {
      "unified_green": {
        "path_match": "property.*.G",
        "mapping": {
          "type": "float",
          "copy_to": "unified_color.G"
        }
      }
    },
    {
      "unified_blue": {
        "path_match": "property.*.B",
        "mapping": {
          "type": "float",
          "copy_to": "unified_color.B"
        }
      }
    }
  ],
  "properties": {
    "unified_color": {
      "properties": {
        "R": {
          "type": "float"
        },
        "G": {
          "type": "float"
        },
        "B": {
          "type": "float"
        }
      }
    }
  }
}

Затем вы сможете запросить любое значение с помощью одного и того же запроса:

GET test/_search
{
  "query": {
    "range": {
      "unified_color.B": {
        "gte": 0.1,
        "lte": 0.6
      }
    }
  }
}

Для уже существующих полей вам нужно будет самостоятельно добавить copy_to в сопоставление, а после этого запустить _update_by_query для их заполнения.

person Jaycreation    schedule 06.10.2020