A mapping defines field representation, and an analyzer produces tokens for full-text search.
The mapping decides search quality first
An Elasticsearch mapping defines how each field in a JSON document is stored and indexed. It resembles a relational database schema and also controls how Lucene analyzes and indexes each field. The mapping determines whether a string supports full-text search or only exact matches.
Getting a field type wrong means the query you want either does not work at all or wastes memory. No amount of query tuning compensates for a mismatched mapping. Working out the expected search patterns during design is the safer approach.
Dynamic and static mappings
There are two ways to create a mapping. Dynamic mapping infers a type from the shape of the value when a document arrives with fields that were never declared. It speeds up ingestion in the early stage, before the data model is settled.
Unexpected fields or date-like strings can produce unwanted mappings. Numeric strings become numeric fields only when numeric_detection is enabled; its default is false. The dynamic mapping documentation defines these rules.
| Strategy | Characteristics | Caveat |
|---|---|---|
| Dynamic mapping | Fast initial ingestion | Unintended field growth and type misjudgment |
| Static mapping | Easy field control | Requires more design time |
| Multi-field | Keeps text and keyword together | Increases storage cost |
A static mapping declares field types, analyzers, and multi-field structure when the index is created. The three strategies in the table can be combined. A common design fixes core fields statically and permits limited dynamic mapping for other fields.
Common field types
Beyond strings, the type follows the search intent.
- text: full-text search material. Passes through an analyzer and is split into tokens.
- keyword: used for exact matching, aggregation, and sorting. Stores the value whole.
- date: used for time-based filtering and analysis.
- numeric (integer, long, and so on): used for range filters and numeric aggregation.
- dense_vector: used for embedding-based vector search.
The deciding factor is what you intend to do with the field. If you need to find words inside it, as with body text, text is right. If you need to filter or group by the value itself, as with a status field, keyword is right.
text, keyword, and multi-fields
A text field passes through an analyzer, which splits it into tokens. It suits match queries that search for words in a sentence. A keyword field indexes the whole value without splitting. It suits exact matching, aggregation, and sorting.
When one field has to serve both purposes, use a multi-field. The same string is indexed as text and simultaneously as a keyword subfield.
The following is a Kibana Dev Tools Console request.
PUT /products
{
"mappings": {
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": { "type": "keyword" }
}
},
"price": { "type": "integer" },
"created_at": { "type": "date" }
}
}
}The name field supports full-text search, while name.keyword supports exact matching and aggregation. Indexing the value twice increases storage use. Apply this configuration only when a field needs both functions.
| Search intent | Field | Query or operation |
|---|---|---|
| Words within a product name | name | match analyzes the query |
| Exact product name | name.keyword | term compares the indexed value |
| Group by product name | name.keyword | terms aggregation |
A term query does not analyze its input, so sending original text to a text field can miss its stored tokens.
The analyzer pipeline
An analyzer turns raw text into searchable tokens. It runs three components in order.
flowchart LR
A[Raw text<br/>original input] --> B[Character filter<br/>character preprocessing]
B --> C[Tokenizer<br/>split into tokens]
C --> D[Token filter<br/>token processing]
D --> E[Inverted index<br/>stored]
- Character filter: cleans up the string before it reaches the tokenizer, doing work such as stripping HTML tags or substituting characters.
- Tokenizer: breaks the string into tokens, the units of meaning. The standard tokenizer follows Unicode word-boundary rules.
- Token filter: processes the resulting tokens. Lowercasing, stopword removal, synonym merging, and stemming happen here.
Tokens from the analyzer pipeline enter the inverted index. This index maps each token to the documents that contain it. A lookup retrieves that document list without scanning every document. This structure supports fast full-text search over large datasets.
Index-time and search-time tokens must be compatible, but the analyzers need not be identical. A separate search_analyzer can support query-time synonyms or autocomplete. Check token output against representative queries, as shown in the search_analyzer documentation.
Korean search and nori
The standard tokenizer does not perform Korean morphological analysis. It can retain a particle in '삼성전자의' and produce a different token from '삼성전자'. Korean search often uses a morphological analyzer.
nori is the official Elasticsearch Korean morphological analysis plugin (analysis-nori). nori_tokenizer splits sentences into morphemes, and the nori_part_of_speech filter removes parts of speech such as particles and endings. Self-managed clusters require the plugin on every node.
PUT /stocks
{
"settings": {
"analysis": {
"analyzer": {
"korean": {
"type": "custom",
"tokenizer": "nori_tokenizer",
"filter": ["lowercase", "nori_part_of_speech"]
}
}
}
},
"mappings": {
"properties": {
"name": { "type": "text", "analyzer": "korean" }
}
}
}Autocomplete and body search need different tokenization rules. Autocomplete must match partial input, so use a separate field and analyzer. A body-text analyzer that also handles autocomplete can fail to serve either function well.
Design criteria in practice
Choose field types from expected search patterns. First identify the values and operations that each field must support.
- User names, status values, tags: keyword
- Body text, descriptions, reviews: text
- Strings that need both search and aggregation: multi-field
- Autocomplete: a dedicated field with a dedicated analyzer
Changing index-time analysis does not rewrite tokens already stored. Rebuild the index when existing documents need the new tokenization. Updating search_analyzer alone can change query processing without reindexing, but still needs relevance checks.
| Change | Existing documents | Operational step |
|---|---|---|
| Index-time tokenizer | Stored tokens remain unchanged | Reindex into the new mapping |
| Search-time analyzer | Stored tokens remain unchanged | Update search_analyzer and test queries |
| Add a multi-field | Old documents lack the new subfield | Reprocess existing documents |
The required work depends on whether the change affects stored tokens or only new queries.
Summary
Mappings define field representation, while analyzers produce tokens for full-text search. Use text for analyzed queries and keyword for exact matching or aggregation, combining them when both are needed.
Korean morphology and autocomplete require tokenization suited to their queries. Keep index-time and search-time tokens compatible, and reindex when existing documents need different stored tokens.