This article explores Elasticsearch field types and how to choose between text and keyword for effective search and indexing.
1. Introduction to Elasticsearch
Elasticsearch is a distributed, RESTful search and analytics engine that can store, search, and analyze large volumes of data quickly in near real-time. It is widely used for full-text search, log and event data analysis, and as a backend for search features in applications.
1.1 Renaming Fields in Elasticsearch
Elasticsearch mappings define how documents and their fields are stored, indexed, and searched. Each field has a specific data type that determines how the data will be analyzed and queried. For example, a text field is used for full-text search, while a keyword field is better suited for exact matches and aggregations. One common challenge developers face is renaming an existing field in Elasticsearch. Unlike relational databases, where columns can be renamed with an ALTER TABLE statement, Elasticsearch does not allow direct renaming of fields inside an existing mapping. Once a field is created and indexed, its name and type are fixed because the underlying Lucene index relies on these definitions for storage and search optimization.
Attempting to rename a field directly can result in errors or inconsistent search behavior. Therefore, renaming requires a careful, multi-step process. The recommended approach involves:
- Create a new index: Define the new index with the updated mapping, specifying the new field name and its data type.
- Reindex the data: Copy documents from the old index to the new index, transforming the old field name to the new one during the process. This ensures all existing data remains accessible under the new schema.
- Update references: Modify application queries and any scripts to use the new field name, ensuring consistency across your system.
It is also important to understand Elasticsearch field types when renaming fields. For instance:
text– Optimized for full-text search. Content is analyzed, tokenized, and searchable by keywords.keyword– Optimized for exact matches and aggregations. Content is stored as-is without analysis.
Choosing the correct type for your new field during renaming ensures that searches, filters, and aggregations continue to work correctly after migration. Additionally, for complex documents, you may need to handle multi-fields or nested fields carefully to avoid data loss or search inconsistencies during the reindexing process. By following this approach, developers can effectively rename fields in Elasticsearch while maintaining data integrity and search performance.
1.2 Setting Up Elasticsearch with Docker
Using Docker makes it easy to run Elasticsearch locally without installing it directly on your system. Here, we will use Docker Compose to spin up a single-node Elasticsearch instance for testing and development.
version: "3.8"
services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.12.1
container_name: elasticsearch
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- ES_JAVA_OPTS=-Xms1g -Xmx1g
ports:
- "9200:9200"
volumes:
- esdata:/usr/share/elasticsearch/data
volumes:
esdata:
To start Elasticsearch, run the following command in the directory containing your docker-compose.yml:
docker compose up -d
This command pulls the Elasticsearch image (if not already present), creates a container, and runs it in detached mode. The container will listen on port 9200 for HTTP requests. Verify that Elasticsearch is running by sending a simple HTTP request:
curl http://localhost:9200
You should receive a JSON response showing cluster information, version details, and a tagline.
{
"name" : "elasticsearch",
"cluster_name" : "docker-cluster",
"cluster_uuid" : "abc123xyz",
"version" : {
"number" : "8.12.1",
"build_flavor" : "default",
"build_type" : "docker",
"build_hash" : "xyz123abc",
"build_date" : "2026-01-01T00:00:00.000Z",
"build_snapshot" : false,
"lucene_version" : "9.7.0",
"minimum_wire_compatibility_version" : "7.17.0",
"minimum_index_compatibility_version" : "7.0.0"
},
"tagline" : "You Know, for Search"
}
Once confirmed, your Docker-based Elasticsearch environment is ready for testing mappings, indexing data, and running queries. This setup is ideal for exploring advanced tasks like renaming existing fields in Elasticsearch mappings.
2. Elasticsearch String Field Types
Elasticsearch provides two primary field types for storing string data: text and keyword. Each serves a different purpose depending on how you want to search, sort, or aggregate your data. The table below summarizes the key differences, use cases, and examples.
| Field Type | Behavior | Use Cases | Example | Pros and Cons |
|---|---|---|---|---|
text |
|
|
|
|
keyword |
|
|
|
|
Understanding these differences is critical when renaming fields or designing new indices. Choosing the right type ensures that searches remain accurate, aggregations are efficient, and your application’s performance stays optimal.
3. Choosing Between text and keyword
Choosing the correct field type in Elasticsearch depends on how the data will be queried, searched, and aggregated. Selecting the wrong type can lead to inefficient queries, inaccurate search results, or difficulty performing aggregations and sorting.
| Feature | text | keyword |
|---|---|---|
| Full-text search | Yes – analyzed into tokens to support flexible search queries such as match, phrase, and fuzzy searches. | No – stored as-is, cannot be tokenized or searched by partial matches. |
| Exact matching | No – tokenization prevents exact string comparison. | Yes – ideal for filtering, exact match queries, and keyword lookups. |
| Sorting | No – cannot reliably sort analyzed text fields. | Yes – supports efficient sorting and ordering of documents. |
| Aggregations | No – analyzed tokens make aggregations unreliable. | Yes – can be aggregated for counts, grouping, and faceted search. |
4. Multi-Fields and Java Example
Multi-fields allow a single field to be indexed in multiple ways. For example, a field can be indexed as text for full-text search and as keyword for sorting and aggregations.
{
"mappings": {
"properties": {
"title": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword"
}
}
}
}
}
}
4.1 Java Code Example: Renaming a Field
// ElasticsearchRenameFieldExample.java
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.bulk.BulkByScrollResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.reindex.ReindexRequest;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import java.io.IOException;
import java.util.Collections;
public class ElasticsearchRenameFieldExample {
public static void main(String[] args) {
// 1. connect to elasticsearch
try (RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("localhost", 9200, "http")))) {
// 2. create old index and add sample document
String oldIndex = "users_old";
if (!client.indices().exists(new GetIndexRequest(oldIndex), RequestOptions.DEFAULT)) {
CreateIndexRequest createOld = new CreateIndexRequest(oldIndex);
String oldMapping = """
{
"properties": {
"username": { "type": "text" },
"age": { "type": "integer" }
}
}
""";
createOld.mapping(oldMapping, XContentType.JSON);
client.indices().create(createOld, RequestOptions.DEFAULT);
// add sample document
IndexRequest indexRequest = new IndexRequest(oldIndex)
.id("1")
.source("""
{
"username": "john_doe",
"age": 30
}
""", XContentType.JSON);
IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);
System.out.println("Added sample document: " + indexResponse.getId());
}
// 3. create new index with updated mapping
String newIndex = "users_new";
if (!client.indices().exists(new GetIndexRequest(newIndex), RequestOptions.DEFAULT)) {
CreateIndexRequest createNew = new CreateIndexRequest(newIndex);
String newMapping = """
{
"properties": {
"user_name": {
"type": "text",
"fields": {
"keyword": { "type": "keyword" }
}
},
"age": { "type": "integer" }
}
}
""";
createNew.mapping(newMapping, XContentType.JSON);
client.indices().create(createNew, RequestOptions.DEFAULT);
System.out.println("Created new index: " + newIndex);
}
// 4. reindex data and rename field using painless script
ReindexRequest reindexRequest = new ReindexRequest();
reindexRequest.setSourceIndices(oldIndex);
reindexRequest.setDestIndex(newIndex);
Script script = new Script(
ScriptType.INLINE,
"painless",
"ctx._source.user_name = ctx._source.remove('username')",
Collections.emptyMap()
);
reindexRequest.setScript(script);
BulkByScrollResponse response = client.reindex(reindexRequest, RequestOptions.DEFAULT);
System.out.println("Reindex completed successfully");
System.out.println("Documents processed: " + response.getCreated());
System.out.println("Renamed field: username → user_name");
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.1.1 Code Explanation
This Java program demonstrates how to rename a field in Elasticsearch by creating a new index with the updated mapping and reindexing data from an old index; it starts by connecting to Elasticsearch using a RestHighLevelClient on localhost:9200, then checks if the old index “users_old” exists and if not, creates it with fields “username” (text) and “age” (integer) and inserts a sample document; next, it creates a new index “users_new” with the renamed field “user_name” (text with keyword subfield) and the same “age” field if it does not exist; then it performs a reindex operation from “users_old” to “users_new” using a painless script that removes the old “username” field from each document and assigns its value to “user_name”; finally, it prints out confirmation messages including the number of documents processed and the field rename operation, while handling any IOExceptions during the process.
4.1.2 Code Output
Added sample document: 1 Created new index: users_new Reindex completed successfully Documents processed: 1 Renamed field: username → user_name
The output shows the step-by-step results of the Java program that renames a field in Elasticsearch: Added sample document: 1 confirms that a sample document with the field username and age was successfully inserted into the old index users_old; Created new index: users_new indicates that the new index with the updated mapping, including the renamed field user_name, was created; Reindex completed successfully shows that the reindex operation finished without errors; Documents processed: 1 confirms that one document was migrated from the old index to the new index; and Renamed field: username → user_name indicates that the field renaming was performed correctly using the painless script during reindexing. overall, this output verifies that the data from the old index is now available in the new index with the updated field name, ensuring consistency and successful migration.
5. Conclusion
Renaming a field in Elasticsearch cannot be done directly because mappings are immutable once data has been indexed. The standard solution is to create a new index with the updated mapping and reindex the data while transforming the field name. Understanding field types like text and keyword is crucial when designing Elasticsearch mappings. Using the correct type improves search performance and ensures efficient query execution. Multi-fields provide a flexible way to support both full-text search and exact matching within the same field, making them a powerful tool for building scalable Elasticsearch applications.
























