Как добавить произвольное поле в Elasticsearch: ingest pipeline, mapping и проверка
Ниже — рабочий пример добавления поля app.session_id на стороне Elasticsearch. Сначала задаём тип поля, затем создаём ingest pipeline, проверяем его через _simulate и только после этого отправляем реальные документы.
1. Проверяем доступ к Elasticsearch
export ES_URL=https://elasticsearch.example.com
export ES_API_KEY=CHANGE_ME
curl -sS -H "Authorization: ApiKey $ES_API_KEY" "$ES_URL/"
curl -sS -H "Authorization: ApiKey $ES_API_KEY" "$ES_URL/_cluster/health?pretty"2. Создаём component template с mapping
curl -sS -X PUT "$ES_URL/_component_template/app-custom-fields" \
-H "Authorization: ApiKey $ES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"template": {
"mappings": {
"properties": {
"app": {
"properties": {
"session_id": { "type": "keyword" },
"environment": { "type": "keyword" }
}
}
}
}
}
}'3. Подключаем template к тестовым индексам
curl -sS -X PUT "$ES_URL/_index_template/app-logs-template" \
-H "Authorization: ApiKey $ES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"index_patterns": ["app-logs-*"],
"composed_of": ["app-custom-fields"],
"priority": 200
}'4. Создаём ingest pipeline
curl -sS -X PUT "$ES_URL/_ingest/pipeline/app-add-fields" \
-H "Authorization: ApiKey $ES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"description": "Add application fields",
"processors": [
{
"set": {
"field": "app.environment",
"value": "production",
"override": false
}
},
{
"rename": {
"field": "session_id",
"target_field": "app.session_id",
"ignore_missing": true
}
}
]
}'5. Проверяем pipeline через _simulate
curl -sS -X POST "$ES_URL/_ingest/pipeline/app-add-fields/_simulate?pretty" \
-H "Authorization: ApiKey $ES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"docs": [
{
"_source": {
"message": "login ok",
"session_id": "sess-123"
}
}
]
}'В результате должны появиться app.session_id и app.environment, а исходное поле session_id должно исчезнуть.
6. Отправляем тестовый документ
curl -sS -X POST "$ES_URL/app-logs-test/_doc?pipeline=app-add-fields&refresh=true" \
-H "Authorization: ApiKey $ES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"@timestamp": "2026-08-02T06:30:00Z",
"message": "login ok",
"session_id": "sess-123"
}'7. Проверяем mapping и документ
curl -sS -H "Authorization: ApiKey $ES_API_KEY" \
"$ES_URL/app-logs-test/_mapping/field/app.session_id?pretty"
curl -sS -H "Authorization: ApiKey $ES_API_KEY" \
"$ES_URL/app-logs-test/_search?q=app.session_id:sess-123&pretty"8. Проверяем конфликт типов до production
curl -sS -X POST "$ES_URL/app-logs-test/_doc?refresh=true" \
-H "Authorization: ApiKey $ES_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"app":{"session_id":123}}'Запись должна завершиться ошибкой типа, потому что поле объявлено как keyword. Такую проверку лучше выполнить на тестовом индексе до подключения основного потока.
9. Пример Logstash
filter {
if [session_id] {
mutate {
rename => { "session_id" => "[app][session_id]" }
add_field => { "[app][environment]" => "production" }
}
}
}10. Rollback
curl -sS -X DELETE -H "Authorization: ApiKey $ES_API_KEY" "$ES_URL/_ingest/pipeline/app-add-fields"
curl -sS -X DELETE -H "Authorization: ApiKey $ES_API_KEY" "$ES_URL/_index_template/app-logs-template"
curl -sS -X DELETE -H "Authorization: ApiKey $ES_API_KEY" "$ES_URL/_component_template/app-custom-fields"
curl -sS -X DELETE -H "Authorization: ApiKey $ES_API_KEY" "$ES_URL/app-logs-test"Критерий успеха: _simulate формирует нужные поля, mapping показывает тип keyword, тестовый документ находится по точному значению, а конфликтующий тип отклоняется.