В статье рассмотрим, как и зачем применять mapping. Нужен ли он вообще и в каких случаях. Я приведу примеры его установки, а так же постараюсь поделиться некоторыми полезными хитростями, которые могут помочь вам в усовершенствование поиска на вашем сайте.
Всем, кому интересен современный поисковый движок ElasticSearch, прошу под кат.
В прошлой статье общим голосование была выбрана эта тема. В этой статье я размещу опять голосование, прошу принять участие. Я постараюсь написать максимально полный цикл статей по ES, если это будет интересно публике.
Mapping похож на определение таблицы в sql базах данных. Мы явно указываем тип каждого поля и дополнительные параметры, такие как анализатор, дефолтное значение, source и так далее. Подробнее ниже.
Мы можем указать mapping при создании индекса, тем самым за один запрос определить для всех типов в индексе.
Так же можем указать mapping напрямую для определённого типа в индексе:
А можем указать mapping сразу для нескольких индексов:
ES не требует явного определения типов данных в документе. В большинстве простых случаев он определяет тип данных верно.
Так зачем тогда его нужно определять?
Ну во первых, это полезно для чистоты кода и уверенности в том, что в данный момент хранится в индексе.
Важная особенность mapping это тонкая настройка данных и их обработка, т.к. мы можем указать, нужно ли анализировать поле, нужно ли хранить исходник. Давайте посмотрим большинство возможностей на примере.
Думаю, все уже догадались, о чём пойдёт речь. Базовых типов всего 7: string, integer/long, float/double, boolean, null
Пример:
Тут мы указали дополнительных параметры:
Примечание: По умолчанию _source = true и весь документ хранится в индексе в исходном состояние и возвращается по запросу. И это работает быстрее, чем хранить в индексе отдельные поля, при условии, что ваш документ не огромен. Тогда хранение только необходимых полей может дать профит. Поэтому я не рекомендую трогать это поле без веской на то причины.
Мы можем указать не только тип массив для поля, но и указать тип для каждого поля внутри массива, вот пример:
Для объектов всё то же самое, за исключение того, что он может быть динамичным (по умолчанию так и есть).
Т.е. вы в любое время можете добавить новое поле в объект и он добавится без ошибок.
Отключить можно так:
По сути, мы определяем документ внутри документа. Зачем это нужно? Отличный пример из документации:
Если мы будем искать
Пример:
Указывать properties для элементов объекта не обязательно, ES сделает это автоматически.
Для поиска по nested типу следует использовать nested query или nested filter.
Начиная с версии 1.0 этот прекрасный параметр был добавлен ко все базовым типам (кроме nested и object).
Что он делает? Этот параметр позволяет указать разные настройки маппинга для одного поля.
Зачем это может быть нужно? например, у вас есть поле, по которому вы хотите и искать и группировать. Если отключить анализатор, поиск будет работать не на полную катушку, а если включить, то группировать мы будем не по сырым данным, а по обработанным. Например, Санкт-Петербург после анализатора будет «Санкт» и «Петербург» (возможно слегка по-другому, но для примера сойдёт). Если мы будет группировать по этому полю, то получим не то, что хотели.
Пример:
Теперь мы можем обращаться к «title» за поиском и к «raw» за группировкой и любыми другими видами сортировки.
ES поддерживает еще 4 типа данных:
Я не стал рассматривать эти типы подробно, т.к. они довольно специфичны или ничем кардинально не отличаются от выше рассмотренных (например IP).
Надеюсь, что я смог доходчиво рассказать о главных функциях mapping'a в ES. Если у вас есть вопросы, рад буду ответить.
Другие статьи по ES:
ElasticSearch — агрегация данных
ElasticSearch и поиск наоборот. Percolate API

— Достижение целей
Всем, кому интересен современный поисковый движок ElasticSearch, прошу под кат.
В прошлой статье общим голосование была выбрана эта тема. В этой статье я размещу опять голосование, прошу принять участие. Я постараюсь написать максимально полный цикл статей по ES, если это будет интересно публике.
Зачем нужен mapping?
Mapping похож на определение таблицы в sql базах данных. Мы явно указываем тип каждого поля и дополнительные параметры, такие как анализатор, дефолтное значение, source и так далее. Подробнее ниже.
Мы можем указать mapping при создании индекса, тем самым за один запрос определить для всех типов в индексе.
curl -XPOST 'http://localhost:9200/test' -d '{
"settings" : {
"number_of_shards" : 1
},
"mappings" : {
"type1" : {
"_source" : { "enabled" : false },
"properties" : {
"field1" : { "type" : "string", "index" : "not_analyzed" }
}
}
}
}'
Так же можем указать mapping напрямую для определённого типа в индексе:
$ curl -XPUT 'http://localhost:9200/twitter/tweet/_mapping' -d '{
"tweet" : {
"properties" : {
"message" : {"type" : "string", "store" : true }
}
}
}'
А можем указать mapping сразу для нескольких индексов:
$ curl -XPUT 'http://localhost:9200/kimchy,elasticsearch/tweet/_mapping' -d '{ ... }'
Так ли он нужен?
ES не требует явного определения типов данных в документе. В большинстве простых случаев он определяет тип данных верно.
Так зачем тогда его нужно определять?
Ну во первых, это полезно для чистоты кода и уверенности в том, что в данный момент хранится в индексе.
Важная особенность mapping это тонкая настройка данных и их обработка, т.к. мы можем указать, нужно ли анализировать поле, нужно ли хранить исходник. Давайте посмотрим большинство возможностей на примере.
Базовые типы данных
Думаю, все уже догадались, о чём пойдёт речь. Базовых типов всего 7: string, integer/long, float/double, boolean, null
Пример:
$ curl -XPUT 'http://localhost:9200/twitter/tweet/_mapping' -d '{
"tweet" : {
"_source" : {"enabled" : false},
"properties" : {
"user" : {"type" : "string", "index" : "not_analyzed"},
"message" : {"type" : "string", "null_value" : "na", "store": true},
"postDate" : {"type" : "date"},
"priority" : {"type" : "integer"},
"rank" : {"type" : "float", "index_name" : "rating"}
}
}
}'
Тут мы указали дополнительных параметры:
"_source" : {"enabled" : false}
— Тем самым мы указали, что хранить исходные данные для этого типа не нужно. Когда это может понадобится? Например у вас есть очень тяжелый документ с кучей информации, которую нужно только индексировать, но не нужно выводить в ответе"store": true
для поля message говорит о том, что это исходник поля необходимо сохранять в индексе"index" : "not_analyzed"
— тут мы указали, что это поле не должно анализироваться, т.е. должно хранится как есть. Какие бывают анализаторы"null_value" : "na"
— дефолтное значение для поля"index_name" : "rating"
— тут мы указали алиас для поля. Теперь мы можем обращаться к нему как к «rank» так и к «rating»
Примечание: По умолчанию _source = true и весь документ хранится в индексе в исходном состояние и возвращается по запросу. И это работает быстрее, чем хранить в индексе отдельные поля, при условии, что ваш документ не огромен. Тогда хранение только необходимых полей может дать профит. Поэтому я не рекомендую трогать это поле без веской на то причины.
Типы array/object/nested
Мы можем указать не только тип массив для поля, но и указать тип для каждого поля внутри массива, вот пример:
#source
{
"tweet" : {
"message" : "some arrays in this tweet...",
"lists" : [
{
"name" : "prog_list",
"description" : "programming list"
},
{
"name" : "cool_list",
"description" : "cool stuff list"
}
]
}
}
#mapping
{
"tweet" : {
"properties" : {
"message" : {"type" : "string"},
"lists" : {
"properties" : {
"name" : {"type" : "string"},
"description" : {"type" : "string"}
}
}
}
}
}
Для объектов всё то же самое, за исключение того, что он может быть динамичным (по умолчанию так и есть).
Т.е. вы в любое время можете добавить новое поле в объект и он добавится без ошибок.
Отключить можно так:
"dynamic" : false
. Подробнее можно почитать тут.Nested(вложенный) type
По сути, мы определяем документ внутри документа. Зачем это нужно? Отличный пример из документации:
{
"obj1" : [
{
"name" : "blue",
"count" : 4
},
{
"name" : "green",
"count" : 6
}
]
}
Если мы будем искать
name = blue && count>5
то этот документ будет найден, что бы избежать такого сценария, стоит использовать nested тип.Пример:
{
"type1" : {
"properties" : {
"obj1" : {
"type" : "nested",
"properties": {
"name" : {"type": "string", "index": "not_analyzed"},
"count" : {"type": "integer"}
}
}
}
}
}
Указывать properties для элементов объекта не обязательно, ES сделает это автоматически.
Для поиска по nested типу следует использовать nested query или nested filter.
Multi-fields
Начиная с версии 1.0 этот прекрасный параметр был добавлен ко все базовым типам (кроме nested и object).
Что он делает? Этот параметр позволяет указать разные настройки маппинга для одного поля.
Зачем это может быть нужно? например, у вас есть поле, по которому вы хотите и искать и группировать. Если отключить анализатор, поиск будет работать не на полную катушку, а если включить, то группировать мы будем не по сырым данным, а по обработанным. Например, Санкт-Петербург после анализатора будет «Санкт» и «Петербург» (возможно слегка по-другому, но для примера сойдёт). Если мы будет группировать по этому полю, то получим не то, что хотели.
Пример:
"title": {
"type": "string",
"fields": {
"raw": { "type": "string", "index": "not_analyzed" }
}
}
Теперь мы можем обращаться к «title» за поиском и к «raw» за группировкой и любыми другими видами сортировки.
Остальные типы
ES поддерживает еще 4 типа данных:
- ip type — хранение ip в виде цифр
- geo point type — хранение координат (удобно при поиске ближайших объектов к определённой координате)
- geo point type — довольно специфичный тип для хранение определённых полигонов
- attachment type — Хранение файлов в базе закодированных в base64. Обычно используется с связке с собственным анализатором. (Хотя как по мне, удовольствие сомнительное)
Я не стал рассматривать эти типы подробно, т.к. они довольно специфичны или ничем кардинально не отличаются от выше рассмотренных (например IP).
Надеюсь, что я смог доходчиво рассказать о главных функциях mapping'a в ES. Если у вас есть вопросы, рад буду ответить.
Другие статьи по ES:
ElasticSearch — агрегация данных
ElasticSearch и поиск наоборот. Percolate API

— Достижение целей
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Тема следующей статьи
56.39% ElasticSearch и river. Перебрасываем данных из SQL/NoSQL базы в ES75
42.86% Warmer — подогреваем и ускоряем ES перед боем57
0.75% Другое (в комментариях)1
Проголосовали 133 пользователя. Воздержались 35 пользователей.