A text field is analysed into tokens and cannot be sorted or aggregated; a keyword field is stored whole and cannot be searched for a word inside it.
{
"name": {
"type": "text",
"fields": {
"raw": { "type": "keyword", "ignore_above": 256 }
}
}
}
// search: name
// sort: name.raw
// aggregate: name.raw
// ignore_above matters: a longer value is not indexed at
// all in the keyword field, silently.
The multi-field pattern is the standard answer and the ignore_above default of 256 is the detail that produces a missing aggregation bucket — a product name longer than the limit simply does not appear, with no error. Raising it costs index size; leaving it means knowing that long values are excluded.