Удаление типов отображения
Индексы, созданные в Elasticsearch 7.0.0 или более поздней версии, больше не принимают отображение _default_. Индексы, созданные в 6.x, будут продолжать работать так же, как и раньше, в Elasticsearch 6.x. Типы устарели в API в версии 7.0, с изменениями, вносящими разрывы в API создания индекса, установки отображения, получения отображения, установки шаблона, получения шаблона и получения отображения полей.
Что такое типы отображения?
С момента первого выпуска Elasticsearch каждый документ хранился в одном индексе и ему назначался один тип отображения. Тип отображения использовался для представления типа документа или сущности, которая индексируется, например, индекс twitter может иметь тип user и тип tweet.
Каждый тип отображения мог иметь свои поля, поэтому тип user мог иметь поле full_name, поле user_name и поле email, а тип tweet мог иметь поле content, поле tweeted_at и, как и тип user, поле user_name.
Каждый документ имел метаданное поле _type, содержащее имя типа, и поиск можно было ограничить одним или несколькими типами, указав имя типа(ов) в URL:
GET twitter/user,tweet/_search
{
"query": {
"match": {
"user_name": "kimchy"
}
}
} Поле _type сочеталось с полем _id документа для генерации поля _uid, поэтому документы разных типов с одинаковым полем _id могли существовать в одном индексе.
Типы отображения также использовались для установления родительско-дочерних отношений между документами, поэтому документы типа question могли быть родителями документов типа answer.
Почему удаляются типы отображения?
Изначально мы говорили, что «индекс» похож на «базу данных» в базе данных SQL, а «тип» — на «таблицу».
Это было плохим аналогом, что привело к неверным предположениям. В базе данных SQL таблицы независимы друг от друга. Столбцы в одной таблице не влияют на столбцы с тем же именем в другой таблице. Это не относится к полям в типе отображения.
В индексе Elasticsearch поля, имеющие одинаковое имя в разных типах отображения, хранятся в одном и том же поле Lucene внутри. Другими словами, используя пример выше, поле user_name в типе user хранится в точно таком же поле, что и поле user_name в типе tweet, и оба поля user_name должны иметь такое же отображение (определение) в обоих типах.
Это может вызвать затруднения, когда, например, вы хотите, чтобы поле deleted было полем date в одном типе и полем boolean в другом типе в одном индексе.
Кроме того, хранение разных сущностей, у которых мало или нет общих полей, в одном индексе приводит к разреженным данным и мешает Lucene эффективно сжимать документы.
По этим причинам мы решили удалить понятие типов отображения из Elasticsearch.
Альтернативы типам отображения
Индекс на тип документа
Первая альтернатива — иметь отдельный индекс для каждого типа документа. Вместо хранения твитов и пользователей в одном индексе twitter, вы можете хранить твиты в индексе tweets, а пользователей — в индексе user. Индексы полностью независимы друг от друга, поэтому не будет конфликтов типов полей между индексами.
Этот подход имеет два преимущества:
- Данные с большей вероятностью будут плотными и, следовательно, получат выгоду от методов сжатия, используемых в Lucene.
- Статистические данные терминов, используемые для оценки в полнотекстовом поиске, с большей вероятностью будут точными, поскольку все документы в одном индексе представляют одну сущность.
Каждый индекс можно правильно масштабировать под количество содержащихся в нем документов: для users вы можете использовать меньшее количество первичных фрагментов, а для tweets — большее количество.
Пользовательское поле типа
Конечно, есть предел тому, сколько первичных фрагментов может существовать в кластере, поэтому вы можете не захотеть тратить весь фрагмент на набор из всего лишь нескольких тысяч документов. В этом случае вы можете реализовать собственное пользовательское поле type, которое будет работать аналогично старому полю _type.
Давайте рассмотрим пример user/tweet. Первоначально рабочий процесс выглядел примерно так:
PUT twitter
{
"mappings": {
"user": {
"properties": {
"name": { "type": "text" },
"user_name": { "type": "keyword" },
"email": { "type": "keyword" }
}
},
"tweet": {
"properties": {
"content": { "type": "text" },
"user_name": { "type": "keyword" },
"tweeted_at": { "type": "date" }
}
}
}
}
PUT twitter/user/kimchy
{
"name": "Shay Banon",
"user_name": "kimchy",
"email": "shay@kimchy.com"
}
PUT twitter/tweet/1
{
"user_name": "kimchy",
"tweeted_at": "2017-10-24T09:00:00Z",
"content": "Types are going away"
}
GET twitter/tweet/_search
{
"query": {
"match": {
"user_name": "kimchy"
}
}
} Вы можете добиться того же результата, добавив пользовательское поле type следующим образом:
PUT twitter
{
"mappings": {
"_doc": {
"properties": {
"type": { "type": "keyword" },
"name": { "type": "text" },
"user_name": { "type": "keyword" },
"email": { "type": "keyword" },
"content": { "type": "text" },
"tweeted_at": { "type": "date" }
}
}
}
}
PUT twitter/_doc/user-kimchy
{
"type": "user",
"name": "Shay Banon",
"user_name": "kimchy",
"email": "shay@kimchy.com"
}
PUT twitter/_doc/tweet-1
{
"type": "tweet",
"user_name": "kimchy",
"tweeted_at": "2017-10-24T09:00:00Z",
"content": "Types are going away"
}
GET twitter/_search
{
"query": {
"bool": {
"must": {
"match": {
"user_name": "kimchy"
}
},
"filter": {
"match": {
"type": "tweet"
}
}
}
}
} | Явное поле |
Родитель/ребенок без типов отображения
Ранее родительско-дочерние отношения представлялись назначением одного типа отображения в качестве родительского и одного или нескольких других типов отображения в качестве дочерних. Без типов мы больше не можем использовать эту синтаксическую конструкцию. Функция родитель-ребенок будет продолжать работать как и прежде, за исключением того, что способ выражения отношений между документами был изменен с использованием нового поля join.
График удаления типов отображения
Это большое изменение для наших пользователей, поэтому мы постарались сделать его максимально безболезненным. Изменения будут внедряться следующим образом:
- Elasticsearch 5.6.0
-
- Установка
index.mapping.single_type: trueдля индекса включит поведение одного типа на индекс, которое будет применено в 6.0. - Замена поля
joinдля родитель-ребенок доступна для индексов, созданных в 5.6.
- Установка
- Elasticsearch 6.x
-
- Индексы, созданные в 5.x, будут продолжать работать в 6.x так же, как и в 5.x.
- Индексы, созданные в 6.x, допускают только один тип на индекс. Любое имя можно использовать для типа, но может быть только одно. Предпочтительным именем типа является
_doc, чтобы API индекса имели тот же путь, что и в 7.0:PUT {index}/_doc/{id}иPOST {index}/_doc. - Имя
_typeбольше не может быть объединено с_idдля формирования поля_uid. Поле_uidстало псевдонимом для поля_id. - Новые индексы больше не поддерживают старый стиль родитель-ребенок и должны использовать поле
joinвместо него. - Тип отображения
_default_устарел. - В 6.8 API создания индекса, шаблона индекса и отображения поддерживают параметр запроса (
include_type_name), указывающий, следует ли включать имя типа в запросы и ответы. По умолчанию он равенtrue, и его следует установить в явное значение для подготовки к обновлению до 7.0. Не установкаinclude_type_nameприведет к предупреждению об устаревании. Индексы без явного типа будут использовать имя типа-заглушки_doc.
- Elasticsearch 7.x
-
- Указание типов в запросах устарело. Например, для индексирования документа больше не требуется документ
type. Новые API индекса —PUT {index}/_doc/{id}в случае явных идентификаторов иPOST {index}/_docдля автоматически сгенерированных идентификаторов. Обратите внимание, что в 7.0_docявляется постоянной частью пути и представляет собой имя конечной точки, а не тип документа. - Параметр
include_type_nameв API создания индекса, шаблона индекса и отображения будет по умолчанию равенfalse. Установка параметра вообще приведет к предупреждению об устаревании. - Тип отображения
_default_удален.
- Указание типов в запросах устарело. Например, для индексирования документа больше не требуется документ
- Elasticsearch 8.x
-
- Указание типов в запросах больше не поддерживается.
- Параметр
include_type_nameудален.
Миграция индексов с несколькими типами на индексы с одним типом
API переиндексирования можно использовать для преобразования индексов с несколькими типами в индексы с одним типом. Следующие примеры можно использовать в Elasticsearch 5.6 или Elasticsearch 6.x. В 6.x нет необходимости указывать index.mapping.single_type, так как это значение по умолчанию.
Индекс на тип документа
В этом первом примере наш индекс twitter разбивается на индекс tweets и индекс users:
PUT users
{
"settings": {
"index.mapping.single_type": true
},
"mappings": {
"_doc": {
"properties": {
"name": {
"type": "text"
},
"user_name": {
"type": "keyword"
},
"email": {
"type": "keyword"
}
}
}
}
}
PUT tweets
{
"settings": {
"index.mapping.single_type": true
},
"mappings": {
"_doc": {
"properties": {
"content": {
"type": "text"
},
"user_name": {
"type": "keyword"
},
"tweeted_at": {
"type": "date"
}
}
}
}
}
POST _reindex
{
"source": {
"index": "twitter",
"type": "user"
},
"dest": {
"index": "users",
"type": "_doc"
}
}
POST _reindex
{
"source": {
"index": "twitter",
"type": "tweet"
},
"dest": {
"index": "tweets",
"type": "_doc"
}
} Пользовательское поле типа
В этом следующем примере добавляется пользовательское поле type и устанавливается значение первоначального поля _type. Также добавляется тип в поле _id, на случай, если есть документы разных типов с конфликтующими идентификаторами:
PUT new_twitter
{
"mappings": {
"_doc": {
"properties": {
"type": {
"type": "keyword"
},
"name": {
"type": "text"
},
"user_name": {
"type": "keyword"
},
"email": {
"type": "keyword"
},
"content": {
"type": "text"
},
"tweeted_at": {
"type": "date"
}
}
}
}
}
POST _reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
},
"script": {
"source": """
ctx._source.type = ctx._type;
ctx._id = ctx._type + '-' + ctx._id;
ctx._type = '_doc';
"""
}
} API без типов в 7.0
В Elasticsearch 7.0 каждый API будет поддерживать запросы без типов, а указание типа будет вызывать предупреждение об устаревании.
API без типов работают даже если целевой индекс содержит пользовательский тип. Например, если индекс имеет пользовательское имя типа my_type, мы можем добавить документы в него с помощью вызовов index без типа, и загрузить документы с помощью вызовов get без типа.
API индекса
Создание индексов, шаблонов индексов и API отображения поддерживают новый параметр URL include_type_name, который определяет, должны ли определения отображения в запросах и ответах содержать имя типа. Параметр по умолчанию равен true в версии 6.8, чтобы соответствовать поведению до версии 7.0, которое использовало имена типов в отображениях. Он по умолчанию равен false в версии 7.0 и будет удален в версии 8.0.
Его следует явно задать в версии 6.8, чтобы подготовиться к обновлению до версии 7.0. Чтобы избежать предупреждений об устаревании в версии 6.8, параметр можно установить в значение true или false. В версии 7.0 установка include_type_name вообще приведет к предупреждению об устаревании.
Рассмотрим примеры взаимодействия с Elasticsearch с этим параметром, установленным в значение false:
PUT /my-index-000001?include_type_name=false
{
"mappings": {
"properties": {
"foo": {
"type": "keyword"
}
}
}
} | Отображения включаются непосредственно под ключом |
PUT /my-index-000001/_mappings?include_type_name=false
{
"properties": {
"bar": {
"type": "text"
}
}
} | Отображения включаются непосредственно под ключом |
GET /my-index-000001/_mappings?include_type_name=false
Вышеупомянутый вызов возвращает
{
"my-index-000001": {
"mappings": {
"properties": {
"foo": {
"type": "keyword"
},
"bar": {
"type": "text"
}
}
}
}
} | Отображения включаются непосредственно под ключом |
Документальные API
В версии 7.0 API индексов должны вызываться с путем {index}/_doc для автоматического создания _id и {index}/_doc/{id} с явными идентификаторами.
PUT /my-index-000001/_doc/1
{
"foo": "baz"
} {
"_index": "my-index-000001",
"_id": "1",
"_type": "_doc",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
} Аналогично, API get и delete используют путь {index}/_doc/{id}:
GET /my-index-000001/_doc/1
В версии 7.0 _doc представляет имя конечной точки вместо типа документа. Компонент _doc является постоянной частью пути для API документов index, get и delete впредь и не будет удален в версии 8.0.
Для путей API, которые содержат и тип, и имя конечной точки, например, _update, в версии 7.0 конечная точка будет сразу следовать за именем индекса:
POST /my-index-000001/_update/1
{
"doc" : {
"foo" : "qux"
}
}
GET /my-index-000001/_source/1 Типы также больше не должны появляться в теле запросов. Следующий пример массового индексирования опускает тип как в URL, так и в отдельных командах массового индексирования:
POST _bulk
{ "index" : { "_index" : "my-index-000001", "_id" : "3" } }
{ "foo" : "baz" }
{ "index" : { "_index" : "my-index-000001", "_id" : "4" } }
{ "foo" : "qux" } API поиска
При вызове API поиска, такого как _search, _msearch или _explain, типы не должны включаться в URL. Кроме того, поле _type не должно использоваться в запросах, агрегациях или скриптах.
Типы в ответах
API документов и поиска по-прежнему будут возвращать ключ _type в ответах, чтобы избежать разрывов в обработке ответов. Однако ключ считается устаревшим и больше не должен использоваться. Типы будут полностью удалены из ответов в версии 8.0.
Обратите внимание, что при использовании устаревшего API с типом тип отображения индекса будет возвращен как обычно, но API без типа вернут фиктивный тип _doc в ответе. Например, следующий вызов get без типа всегда вернет _doc в качестве типа, даже если отображение имеет пользовательское имя типа, такое как my_type:
PUT /my-index-000001/my_type/1
{
"foo": "baz"
}
GET /my-index-000001/_doc/1 {
"_index" : "my-index-000001",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found": true,
"_source" : {
"foo" : "baz"
}
} Шаблоны индексов
Рекомендуется сделать шаблоны индексов без типа, повторно добавив их с include_type_name, установленным в значение false. Под капотом, шаблоны без типа будут использовать фиктивный тип _doc при создании индексов.
В случае использования шаблонов без типа с вызовами создания индексов с типом или шаблонов с типом с вызовами создания индексов без типа шаблон по-прежнему будет применён, но вызов создания индекса решает, должен ли быть тип или нет. Например, в примере ниже index-1-01 будет иметь тип, несмотря на то, что он соответствует шаблону без типа, а index-2-01 будет без типа, несмотря на то, что он соответствует шаблону, определяющему тип. Оба index-1-01 и index-2-01 унаследуют поле foo от шаблона, которому они соответствуют.
PUT _template/template1
{
"index_patterns":[ "index-1-*" ],
"mappings": {
"properties": {
"foo": {
"type": "keyword"
}
}
}
}
PUT _template/template2?include_type_name=true
{
"index_patterns":[ "index-2-*" ],
"mappings": {
"type": {
"properties": {
"foo": {
"type": "keyword"
}
}
}
}
}
PUT index-1-01?include_type_name=true
{
"mappings": {
"type": {
"properties": {
"bar": {
"type": "long"
}
}
}
}
}
PUT index-2-01
{
"mappings": {
"properties": {
"bar": {
"type": "long"
}
}
}
} В случае неявного создания индекса из-за документов, которые индексируются в индексе, который ещё не существует, шаблон всегда учитывается. Это обычно не проблема, так как вызовы создания индексов без типа работают с индексами с типом.
Кластеры смешанных версий
В кластере, состоящем из узлов версии 6.8 и 7.0, параметр include_type_name должен быть указан в API создания индексов. Это связано с тем, что у параметра разные значения по умолчанию для 6.8 и 7.0, поэтому одно и то же определение отображения не будет действительным для обеих версий узлов.
API документов без типа, такие как bulk и update, доступны только начиная с версии 7.0 и не будут работать с узлами версии 6.8. Это также относится к версиям запросов без типа, которые выполняют поиск документов, таким как terms.
© 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/7.17/removal-of-types.html