eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – Spring Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 30% off until 31st March, 2026

>> EXPLORE ACCESS NOW

Partner – Diagrid – NPI EA (cat= Testing)
announcement - icon

In distributed systems, managing multi-step processes (e.g., validating a driver, calculating fares, notifying users) can be difficult. We need to manage state, scattered retry logic, and maintain context when services fail.

Dapr Workflows solves this via Durable Execution which includes automatic state persistence, replaying workflows after failures and built-in resilience through retries, timeouts and error handling.

In this tutorial, we'll see how to orchestrate a multi-step flow for a ride-hailing application by integrating Dapr Workflows and Spring Boot:

>> Dapr Workflows With PubSub

Course – Spring Sale 2026 – NPI (cat=Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 30% off until 31st March, 2026

>> EXPLORE ACCESS NOW

1. Overview

One of the most common challenges when working with Elasticsearch is selecting the appropriate field type for the data to be stored. In particular, string fields require special attention. Elasticsearch offers two primary options: keyword and text. Selecting the correct one is essential. Otherwise, we risk unexpected search results, broken aggregations, or even performance issues.

In this article, we’ll explore how keyword and text fields differ. Then, we’ll explain when to use each type so we can design more reliable and efficient Elasticsearch mappings.

2. text Field Type

In Elasticsearch, the text field type is used for full-text search. Before indexing, Elasticsearch analyzes the content by tokenizing it, converting it to lowercase, and, depending on the analyzer, applying steps like synonym handling and stop-word removal.

Let’s take the next document as an example for our search cases:

{
  "type": "article",
  "title": "Using Elasticsearch with Spring Boot",
  "status": "IN_PROGRESS"
}

We will map the title column as a text field type and the other two columns as a keyword type. After the analysis process, the index result for this column will look as follows:

["using", "elasticsearch", "with", "spring", "boot"]

And we can use the match operator for full-text search behavior:

{
  "query": {
    "match": {
      "title": "spring elasticsearch"
    }
  }
}

To perform a full-text search using the Elasticsearch Java API Client, we can start by defining a model that represents the document to index. With Java, a record is a great fit for this case:

public record Article(String type, String title, String status) {
}

Next, we’ll define the search query using the client.

SearchResponse<Article> response = client.search(s -> s
  .index("index")
  .query(q -> q
    .match(m -> m
      .field("title")
      .query("spring elasticsearch")
      .operator(Operator.And) // require both terms
    )
  ),
  Article.class
);

This query searches on the title field using full-text analysis and requires both terms spring and elasticsearch to be present.

The text field type has some limitations for string values. For example, it does not support sorting or aggregations. This is because text fields are optimized for search and don’t store the necessary data structures that enable efficient sorting and aggregation. In addition, text fields are not suitable for exact matching, since Elasticsearch stores analyzed tokens rather than the original values.

3. keyword Field Type

When we define a field as keyword, Elasticsearch stores the value exactly as provided, without applying any analysis such as tokenization or lowercasing. This makes keyword fields ideal for exact matching, filtering, sorting, and aggregations.

For instance, let’s define the status field as a keyword type. Using our example document, Elasticsearch will index the value as follows:

["IN_PROGRESS"]

To search for documents with a specific status, we use the term query, which performs exact matching:

{
  "query": {
    "term": {
      "status": "IN_PROGRESS"
    }
  }
}

Now, let’s define the query using the Java client:

SearchResponse<Article> response = client.search(s -> s
  .index("index")
  .query(q -> q
    .term(t -> t
      .field("status")
      .value("IN_PROGRESS")
    )
  ), 
  Article.class
);

An important thing to note is that since keyword fields are case-sensitive and require exact matches, searching for “in_progress” (lowercase) would return no results, even though the actual value is “IN_PROGRESS”. This behavior is crucial to understand when working with keyword fields.

Using the keyword type allows us to perform aggregations over the field and get accurate information about the documents. For example, if we want to get the count of documents by status, we can define the next query:

{
  "size": 0,
  "aggs": {
    "by_status": {
      "terms": {
        "field": "status"
      }
    }
  }
}

And using the Java client:

SearchResponse<Void> response = elasticsearchClient.search(s -> s.index("index")
  .size(0)
  .aggregations("by_status", a -> a.terms(t -> t.field("status"))), Void.class);
        
response.aggregations()
  .get("by_status")
  .sterms()
  .buckets()
  .array()
  .forEach(b -> System.out.println(b.key()
    .stringValue() + " -> " + b.docCount()));

This query groups documents by their exact status values and returns the count for each group, making it easy to generate reports or dashboards based on categorical data

4. Choosing Between text and keyword

Now that we have explored the differences between the two types, we can infer which one will suit us better for our particular cases. For instance, if we need to perform a full-text search, text type will be the best option. If we need to search by exact matching or perform aggregations based on the data, the keyword type will be a better fit.

Sorting is another reason to use the keyword type. Elasticsearch can only sort on fields that have a single comparable value per document. Since keyword fields are stored as-is (not tokenized), they work naturally for sorting. Let’s see the query:

{
  "sort": [
    {
      "status": "asc"
    }
  ]
}

And using the Java client:

SearchResponse<Article> response = elasticsearchClient.search(s -> s.index("index")
  .sort(so -> so.field(f -> f.field("status")
    .order(SortOrder.Asc))), Article.class);

Similarly, while the text type is not intended for aggregations, the keyword type is not suitable for long, free-form text. Using it in this way only increases the index size and provides no relevance scoring.

Understanding these differences helps us build more reliable Elasticsearch indices, achieve better performance, and produce accurate search results and aggregations.

5. Multi-Fields Typing

A common and recommended pattern is to index the same field as both text and keyword using multi-fields. This approach allows full-text search while still supporting exact matches, sorting, and aggregations on the same logical field.

The next is an example mapping:

{
  "title": {
    "type": "text",
    "fields": {
      "keyword": {
        "type": "keyword"
      }
    }
  }
}

With this mapping, Elasticsearch creates two indexed versions of the title field and gives us the flexibility to use the same field in different ways. For example, we can perform a full-text search on the analyzed version:

{
  "query": {
    "match": {
      "title": "spring elasticsearch"
    }
  }
}

And sort the results using the keyword version:

{
  "query": {
    "match": {
      "title": "spring elasticsearch"
    }
  },
  "sort": [
    {
      "title.keyword": "asc"
    }
  ]
}

Using the Java client, we can also combine both capabilities:

SearchResponse<Article> response = client.search(s -> s
  .index("index")
  .query(q -> q
    .match(m -> m
      .field("title")
      .query("spring elasticsearch")
    )
  )
  .sort(so -> so
    .field(f -> f
      .field("title.keyword")
      .order(SortOrder.Asc)
    )
  ),
  Article.class
);

Similarly, we can aggregate on the keyword version to get exact value counts:

SearchResponse<Article> response = client.search(s -> s
  .index("index")
  .size(0)
  .aggregations("popular_titles", a -> a
    .terms(t -> t
      .field("title.keyword")
      .size(10)
    )
  ),
  Article.class
);

response.aggregations()
  .get("popular_titles")
  .sterms()
  .buckets()
  .array()
  .forEach(b -> System.out.println(
    b.key().stringValue() + " -> " + b.docCount()
  ));

This pattern is especially useful for fields like product names, article titles, or user-generated content, where we need both search and analytical capabilities. However, we need to keep in mind that multi-fields increase storage requirements since Elasticsearch indexes the data twice.

6. Conclusion

In this article, we explored the key differences between text and keyword field types in Elasticsearch. We reviewed how searches work for each type, discussed their appropriate use cases, and explained how choosing the correct field type leads to more accurate results and faster queries.

We also examined the multi-fields pattern, which allows us to index the same field as both text and keyword. This approach provides the flexibility to perform full-text searches while still supporting exact matching, sorting, and aggregations on the same logical field.

As always, the complete code for this tutorial is available over on GitHub.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – Spring Sale 2026 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 30% off until 31st March, 2026

>> EXPLORE ACCESS NOW

Course – Spring Sale 2026 – NPI (All)
announcement - icon

Yes, we're now running our Spring Sale. All Courses are 30% off until 31st March, 2026

>> EXPLORE ACCESS NOW

eBook Jackson – NPI EA – 3 (cat = Jackson)