Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Guide [8.17] ›Mapping ›Типы данных полей

Тип поля Flattened

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

Тип flattened предоставляет альтернативный подход, где весь объект отображается как одно поле. Учитывая объект, отображение flattened разобъёт его листовые значения и проиндексирует их в одно поле в качестве ключевых слов. Затем содержимое объекта можно искать с помощью простых запросов и агрегаций.

Этот тип данных может быть полезен для индексирования объектов с большим или неизвестным количеством уникальных ключей. Создаётся только одно отображение поля для всего JSON-объекта, что может помочь предотвратить взрыв отображений из-за слишком большого количества различных отображений полей.

С другой стороны, сглаженные поля объектов представляют собой компромисс с точки зрения функциональности поиска. Разрешены только базовые запросы без поддержки запросов по числовым диапазонам или выделения ключевых слов. Дополнительную информацию о ограничениях можно найти в разделе Поддерживаемые операции.

Тип отображения flattened следует не использовать для индексирования всего содержимого документа, так как он обрабатывает все значения как ключевые слова и не обеспечивает полную функциональность поиска. Стандартный подход, при котором каждое подполе имеет свою запись в отображениях, работает хорошо в большинстве случаев.

Сглаженное поле объекта можно создать следующим образом:

resp = client.indices.create(
    index="bug_reports",
    mappings={
        "properties": {
            "title": {
                "type": "text"
            },
            "labels": {
                "type": "flattened"
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="bug_reports",
    id="1",
    document={
        "title": "Results are not sorted correctly.",
        "labels": {
            "priority": "urgent",
            "release": [
                "v1.2.5",
                "v1.3.0"
            ],
            "timestamp": {
                "created": 1541458026,
                "closed": 1541457010
            }
        }
    },
)
print(resp1)
response = client.indices.create(
  index: 'bug_reports',
  body: {
    mappings: {
      properties: {
        title: {
          type: 'text'
        },
        labels: {
          type: 'flattened'
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'bug_reports',
  id: 1,
  body: {
    title: 'Results are not sorted correctly.',
    labels: {
      priority: 'urgent',
      release: [
        'v1.2.5',
        'v1.3.0'
      ],
      timestamp: {
        created: 1_541_458_026,
        closed: 1_541_457_010
      }
    }
  }
)
puts response
const response = await client.indices.create({
  index: "bug_reports",
  mappings: {
    properties: {
      title: {
        type: "text",
      },
      labels: {
        type: "flattened",
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "bug_reports",
  id: 1,
  document: {
    title: "Results are not sorted correctly.",
    labels: {
      priority: "urgent",
      release: ["v1.2.5", "v1.3.0"],
      timestamp: {
        created: 1541458026,
        closed: 1541457010,
      },
    },
  },
});
console.log(response1);
PUT bug_reports
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "labels": {
        "type": "flattened"
      }
    }
  }
}

POST bug_reports/_doc/1
{
  "title": "Results are not sorted correctly.",
  "labels": {
    "priority": "urgent",
    "release": ["v1.2.5", "v1.3.0"],
    "timestamp": {
      "created": 1541458026,
      "closed": 1541457010
    }
  }
}

Во время индексирования для каждого листового значения в JSON-объекте создаются токены. Значения индексируются как строковые ключевые слова без анализа или специальной обработки чисел или дат.

Поиск по верхнему полю flattened выполняется по всем листовым значениям в объекте:

resp = client.search(
    index="bug_reports",
    query={
        "term": {
            "labels": "urgent"
        }
    },
)
print(resp)
response = client.search(
  index: 'bug_reports',
  body: {
    query: {
      term: {
        labels: 'urgent'
      }
    }
  }
)
puts response
const response = await client.search({
  index: "bug_reports",
  query: {
    term: {
      labels: "urgent",
    },
  },
});
console.log(response);
POST bug_reports/_search
{
  "query": {
    "term": {"labels": "urgent"}
  }
}

Для поиска по определенному ключу в сглаженном объекте используется нотация точки объекта:

resp = client.search(
    index="bug_reports",
    query={
        "term": {
            "labels.release": "v1.3.0"
        }
    },
)
print(resp)
response = client.search(
  index: 'bug_reports',
  body: {
    query: {
      term: {
        'labels.release' => 'v1.3.0'
      }
    }
  }
)
puts response
const response = await client.search({
  index: "bug_reports",
  query: {
    term: {
      "labels.release": "v1.3.0",
    },
  },
});
console.log(response);
POST bug_reports/_search
{
  "query": {
    "term": {"labels.release": "v1.3.0"}
  }
}

Поддерживаемые операции

Из-за сходства способов индексирования значений поля flattened делят большую часть функциональности отображения и поиска с полями keyword.

В настоящее время сглаженные поля объектов можно использовать со следующими типами запросов:

  • term, terms и terms_set
  • prefix
  • range
  • match и multi_match
  • query_string и simple_query_string
  • exists

При поиске невозможно ссылаться на ключи полей с помощью подстановок, как в { "term": {"labels.time*": 1541457010}}. Обратите внимание, что все запросы, включая range, обрабатывают значения как строковые ключевые слова. Выделение не поддерживается для полей flattened.

Можно сортировать по сглаженному полю объекта, а также выполнять простые агрегации в стиле ключевых слов, такие как terms. Как и в случае с запросами, нет специальной поддержки чисел — все значения в JSON-объекте обрабатываются как ключевые слова. При сортировке это подразумевает сравнение значений лексикографически.

Сглаженные поля объектов в настоящее время не могут храниться. Невозможно указать параметр store в отображении.

Получение сглаженных полей

Значения полей и конкретные подполя можно получить, используя параметр fields. Так как поле flattened отображает весь объект с потенциально многими подполями как одно поле, ответ содержит неизмененную структуру из _source.

Однако отдельные подполя можно извлечь, явно указав их в запросе. Это работает только для конкретных путей, но не с использованием подстановок:

resp = client.indices.create(
    index="my-index-000001",
    mappings={
        "properties": {
            "flattened_field": {
                "type": "flattened"
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="my-index-000001",
    id="1",
    refresh=True,
    document={
        "flattened_field": {
            "subfield": "value"
        }
    },
)
print(resp1)

resp2 = client.search(
    index="my-index-000001",
    fields=[
        "flattened_field.subfield"
    ],
    source=False,
)
print(resp2)
response = client.indices.create(
  index: 'my-index-000001',
  body: {
    mappings: {
      properties: {
        flattened_field: {
          type: 'flattened'
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'my-index-000001',
  id: 1,
  refresh: true,
  body: {
    flattened_field: {
      subfield: 'value'
    }
  }
)
puts response

response = client.search(
  index: 'my-index-000001',
  body: {
    fields: [
      'flattened_field.subfield'
    ],
    _source: false
  }
)
puts response
const response = await client.indices.create({
  index: "my-index-000001",
  mappings: {
    properties: {
      flattened_field: {
        type: "flattened",
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "my-index-000001",
  id: 1,
  refresh: "true",
  document: {
    flattened_field: {
      subfield: "value",
    },
  },
});
console.log(response1);

const response2 = await client.search({
  index: "my-index-000001",
  fields: ["flattened_field.subfield"],
  _source: false,
});
console.log(response2);
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "flattened_field": {
        "type": "flattened"
      }
    }
  }
}

PUT my-index-000001/_doc/1?refresh=true
{
  "flattened_field" : {
    "subfield" : "value"
  }
}

POST my-index-000001/_search
{
  "fields": ["flattened_field.subfield"],
  "_source": false
}
{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.0,
    "hits": [{
      "_index": "my-index-000001",
      "_id": "1",
      "_score": 1.0,
      "fields": {
        "flattened_field.subfield" : [ "value" ]
      }
    }]
  }
}

Вы также можете использовать сценарий Painless для извлечения значений из подполей сглаженных полей. Вместо включения doc['<field_name>'].value в ваш сценарий Painless, используйте doc['<field_name>.<sub-field_name>'].value. Например, если у вас есть сглаженное поле с именем label с подполем release, ваш сценарий Painless будет doc['labels.release'].value.

Например, предположим, что ваше отображение содержит два поля, одно из которых является типа flattened:

resp = client.indices.create(
    index="my-index-000001",
    mappings={
        "properties": {
            "title": {
                "type": "text"
            },
            "labels": {
                "type": "flattened"
            }
        }
    },
)
print(resp)
response = client.indices.create(
  index: 'my-index-000001',
  body: {
    mappings: {
      properties: {
        title: {
          type: 'text'
        },
        labels: {
          type: 'flattened'
        }
      }
    }
  }
)
puts response
const response = await client.indices.create({
  index: "my-index-000001",
  mappings: {
    properties: {
      title: {
        type: "text",
      },
      labels: {
        type: "flattened",
      },
    },
  },
});
console.log(response);
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "labels": {
        "type": "flattened"
      }
    }
  }
}

Индексируем несколько документов, содержащих ваши сопоставленные поля. Поле labels имеет три подполя:

resp = client.bulk(
    index="my-index-000001",
    refresh=True,
    operations=[
        {
            "index": {}
        },
        {
            "title": "Something really urgent",
            "labels": {
                "priority": "urgent",
                "release": [
                    "v1.2.5",
                    "v1.3.0"
                ],
                "timestamp": {
                    "created": 1541458026,
                    "closed": 1541457010
                }
            }
        },
        {
            "index": {}
        },
        {
            "title": "Somewhat less urgent",
            "labels": {
                "priority": "high",
                "release": [
                    "v1.3.0"
                ],
                "timestamp": {
                    "created": 1541458026,
                    "closed": 1541457010
                }
            }
        },
        {
            "index": {}
        },
        {
            "title": "Not urgent",
            "labels": {
                "priority": "low",
                "release": [
                    "v1.2.0"
                ],
                "timestamp": {
                    "created": 1541458026,
                    "closed": 1541457010
                }
            }
        }
    ],
)
print(resp)
response = client.bulk(
  index: 'my-index-000001',
  refresh: true,
  body: [
    {
      index: {}
    },
    {
      title: 'Something really urgent',
      labels: {
        priority: 'urgent',
        release: [
          'v1.2.5',
          'v1.3.0'
        ],
        timestamp: {
          created: 1_541_458_026,
          closed: 1_541_457_010
        }
      }
    },
    {
      index: {}
    },
    {
      title: 'Somewhat less urgent',
      labels: {
        priority: 'high',
        release: [
          'v1.3.0'
        ],
        timestamp: {
          created: 1_541_458_026,
          closed: 1_541_457_010
        }
      }
    },
    {
      index: {}
    },
    {
      title: 'Not urgent',
      labels: {
        priority: 'low',
        release: [
          'v1.2.0'
        ],
        timestamp: {
          created: 1_541_458_026,
          closed: 1_541_457_010
        }
      }
    }
  ]
)
puts response
const response = await client.bulk({
  index: "my-index-000001",
  refresh: "true",
  operations: [
    {
      index: {},
    },
    {
      title: "Something really urgent",
      labels: {
        priority: "urgent",
        release: ["v1.2.5", "v1.3.0"],
        timestamp: {
          created: 1541458026,
          closed: 1541457010,
        },
      },
    },
    {
      index: {},
    },
    {
      title: "Somewhat less urgent",
      labels: {
        priority: "high",
        release: ["v1.3.0"],
        timestamp: {
          created: 1541458026,
          closed: 1541457010,
        },
      },
    },
    {
      index: {},
    },
    {
      title: "Not urgent",
      labels: {
        priority: "low",
        release: ["v1.2.0"],
        timestamp: {
          created: 1541458026,
          closed: 1541457010,
        },
      },
    },
  ],
});
console.log(response);
POST /my-index-000001/_bulk?refresh
{"index":{}}
{"title":"Something really urgent","labels":{"priority":"urgent","release":["v1.2.5","v1.3.0"],"timestamp":{"created":1541458026,"closed":1541457010}}}
{"index":{}}
{"title":"Somewhat less urgent","labels":{"priority":"high","release":["v1.3.0"],"timestamp":{"created":1541458026,"closed":1541457010}}}
{"index":{}}
{"title":"Not urgent","labels":{"priority":"low","release":["v1.2.0"],"timestamp":{"created":1541458026,"closed":1541457010}}}

Поскольку labels является полем типа flattened, весь объект отображается как одно поле. Для извлечения значений из этого подполя в сценарии Painless используйте формат doc['<field_name>.<sub-field_name>'].value.

"script": {
  "source": """
    if (doc['labels.release'].value.equals('v1.3.0'))
    {emit(doc['labels.release'].value)}
    else{emit('Version mismatch')}
  """

Параметры для сглаженных полей объектов

Принимаются следующие параметры отображения:

depth_limit

Максимальная разрешенная глубина сглаженного поля объекта в терминах вложенных внутренних объектов. Если сглаженное поле объекта превысит этот предел, будет выброшено исключение. Значение по умолчанию — 20. Обратите внимание, что depth_limit может быть обновлено динамически через API обновления отображения.

doc_values

Следует ли хранить поле на диске в формате столбцов, чтобы его можно было использовать для сортировки, агрегаций или сценариев? Принимает true (по умолчанию) или false.

eager_global_ordinals

Следует ли загружать глобальные порядковые номера в режиме ожидания при обновлении? Принимает true или false (по умолчанию). Включить это рекомендуется для полей, которые часто используются в агрегациях по терминам.

ignore_above

Листовые значения, длина которых превышает этот предел, не будут индексироваться. По умолчанию ограничения нет, и все значения индексируются. Обратите внимание, что это ограничение применяется к листовым значениям внутри сглаженного поля объекта, а не к длине всего поля.

index

Определяет, должно ли поле быть доступным для поиска. Принимает true (по умолчанию) или false.

index_options

Какая информация должна храниться в индексе для целей оценки. По умолчанию устанавливается значение docs, но также может быть установлено значение freqs, чтобы учесть частоту термина при вычислении оценок.

null_value

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

similarity

Какой алгоритм оценки или сходства следует использовать. По умолчанию используется BM25.

split_queries_on_whitespace

Следует ли разбивать входные данные на пробелы при построении запроса для этого поля в полных текстовых запросах. Принимает true или false (по умолчанию).

time_series_dimensions

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

Синтетические _source

Синтетические _source доступны только для индексов TSDB (индексы, у которых index.mode установлено в time_series). Для других индексов синтетические _source находятся в техническом предварительном просмотре. Функции в техническом предварительном просмотре могут быть изменены или удалены в будущих выпусках. Elastic будет работать над устранением любых проблем, но функции в техническом предварительном просмотре не подпадают под SLA поддержки официальных функций GA.

Поддержка сглаженных полей включает синтетический`_source` в их конфигурации по умолчанию.

Синтетический источник может сортировать значения поля flattened и удалять дубликаты. Например:

resp = client.indices.create(
    index="idx",
    settings={
        "index": {
            "mapping": {
                "source": {
                    "mode": "synthetic"
                }
            }
        }
    },
    mappings={
        "properties": {
            "flattened": {
                "type": "flattened"
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="idx",
    id="1",
    document={
        "flattened": {
            "field": [
                "apple",
                "apple",
                "banana",
                "avocado",
                "10",
                "200",
                "AVOCADO",
                "Banana",
                "Tangerine"
            ]
        }
    },
)
print(resp1)
const response = await client.indices.create({
  index: "idx",
  settings: {
    index: {
      mapping: {
        source: {
          mode: "synthetic",
        },
      },
    },
  },
  mappings: {
    properties: {
      flattened: {
        type: "flattened",
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "idx",
  id: 1,
  document: {
    flattened: {
      field: [
        "apple",
        "apple",
        "banana",
        "avocado",
        "10",
        "200",
        "AVOCADO",
        "Banana",
        "Tangerine",
      ],
    },
  },
});
console.log(response1);
PUT idx
{
  "settings": {
    "index": {
      "mapping": {
        "source": {
          "mode": "synthetic"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "flattened": { "type": "flattened" }
    }
  }
}
PUT idx/_doc/1
{
  "flattened": {
    "field": [ "apple", "apple", "banana", "avocado", "10", "200", "AVOCADO", "Banana", "Tangerine" ]
  }
}

Превратится в:

{
  "flattened": {
    "field": [ "10", "200", "AVOCADO", "Banana", "Tangerine", "apple", "avocado", "banana" ]
  }
}

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

resp = client.indices.create(
    index="idx",
    settings={
        "index": {
            "mapping": {
                "source": {
                    "mode": "synthetic"
                }
            }
        }
    },
    mappings={
        "properties": {
            "flattened": {
                "type": "flattened"
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="idx",
    id="1",
    document={
        "flattened": {
            "field": [
                {
                    "id": 1,
                    "name": "foo"
                },
                {
                    "id": 2,
                    "name": "bar"
                },
                {
                    "id": 3,
                    "name": "baz"
                }
            ]
        }
    },
)
print(resp1)
const response = await client.indices.create({
  index: "idx",
  settings: {
    index: {
      mapping: {
        source: {
          mode: "synthetic",
        },
      },
    },
  },
  mappings: {
    properties: {
      flattened: {
        type: "flattened",
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "idx",
  id: 1,
  document: {
    flattened: {
      field: [
        {
          id: 1,
          name: "foo",
        },
        {
          id: 2,
          name: "bar",
        },
        {
          id: 3,
          name: "baz",
        },
      ],
    },
  },
});
console.log(response1);
PUT idx
{
  "settings": {
    "index": {
      "mapping": {
        "source": {
          "mode": "synthetic"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "flattened": { "type": "flattened" }
    }
  }
}
PUT idx/_doc/1
{
  "flattened": {
      "field": [
        { "id": 1, "name": "foo" },
        { "id": 2, "name": "bar" },
        { "id": 3, "name": "baz" }
      ]
  }
}

Превратится в (обратите внимание на вложенные объекты вместо "сглаженного" массива):

{
    "flattened": {
      "field": {
          "id": [ "1", "2", "3" ],
          "name": [ "bar", "baz", "foo" ]
      }
    }
}

Синтетический источник всегда использует однозначные поля для массивов из одного элемента. Например:

resp = client.indices.create(
    index="idx",
    settings={
        "index": {
            "mapping": {
                "source": {
                    "mode": "synthetic"
                }
            }
        }
    },
    mappings={
        "properties": {
            "flattened": {
                "type": "flattened"
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="idx",
    id="1",
    document={
        "flattened": {
            "field": [
                "foo"
            ]
        }
    },
)
print(resp1)
const response = await client.indices.create({
  index: "idx",
  settings: {
    index: {
      mapping: {
        source: {
          mode: "synthetic",
        },
      },
    },
  },
  mappings: {
    properties: {
      flattened: {
        type: "flattened",
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "idx",
  id: 1,
  document: {
    flattened: {
      field: ["foo"],
    },
  },
});
console.log(response1);
PUT idx
{
  "settings": {
    "index": {
      "mapping": {
        "source": {
          "mode": "synthetic"
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "flattened": { "type": "flattened" }
    }
  }
}
PUT idx/_doc/1
{
  "flattened": {
    "field": [ "foo" ]
  }
}

Превратится в (обратите внимание на вложенные объекты вместо "сглаженного" массива):

{
  "flattened": {
    "field": "foo"
  }
}

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/flattened.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API