Spring Boot Elasticsearch Vector Search

Spring Boot Elasticsearch Vector Search thumbnail

In this tutorial, we will implement Spring Boot Elasticsearch Vector Search using:

  • Full-text search (BM25)
  • Fuzzy search
  • kNN vector search
  • Semantic search (kNN + BM25 + Fuzzy)

We assume that embeddings are already stored in Elasticsearch during document ingestion using the embeddings field and model id all-MiniLM-L6-v2.

You can refer this elsticsearch doc for storing embeddings in Elasticsearch.

You can also generate embeddings using:


Maven Dependencies

<dependency>
    <groupId>co.elastic.clients</groupId>
    <artifactId>elasticsearch-java</artifactId>
    <version>9.2.5</version>
</dependency>

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
    <version>9.2.5</version>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

We use:

  • elasticsearch-java -> Official high-level Java client
  • rest-client -> Low-level HTTP transport
  • Lombok -> Boilerplate reduction

application.yml Configuration

spring:
  application:
    name: elastic-knn

devglan:
  elastic:
    url: http://127.0.0.1:9200
    apiKey: YOUR_BASE64_ENCODED_API_KEY
    similarityThreshold: "60%"
    minScore: 0.91
    modelId: all-MiniLM-L6-v2
    indices:
      - my-documents

Configuration Explanation

  • modelId -> Embedding model deployed in Elasticsearch
  • minScore -> Filters low-quality vector matches
  • similarityThreshold -> Minimum match percentage for filters
  • indices -> Target index list

ElasticsearchClient Configuration

@Configuration
@RequiredArgsConstructor
public class ElasticSearchConfig {

    private final ElasticProperties elasticProperties;

    @Bean
    public ElasticsearchClient elasticsearchClient() {

        Header[] defaultHeaders = new Header[]{
                new BasicHeader(HttpHeaders.AUTHORIZATION, 
                "ApiKey " + elasticProperties.getApiKey())
        };

        RestClient restClient = RestClient.builder(
                        HttpHost.create(elasticProperties.getUrl())
                )
                .setDefaultHeaders(defaultHeaders)
                .build();

        ElasticsearchTransport transport =
                new RestClientTransport(restClient, new JacksonJsonpMapper());

        return new ElasticsearchClient(transport);
    }
}

This creates a reusable, thread-safe Elasticsearch client.


Full Text Search (BM25)

private Function<Query.Builder, ObjectBuilder<Query>> fullTextQuery(String text) {
    return q -> q.multiMatch(m -> m
            .query(text)
            .fields("title^3", "body^2", "text^2")
            .type(TextQueryType.MostFields)
    );
}

How It Works

  • Uses multi_match
  • BM25 scoring algorithm
  • Boosting applied: title > body > text
  • MostFields combines scores across fields

Best for: Keyword-based search.


Fuzzy Search

private Function<Query.Builder, ObjectBuilder<Query>> fuzzyTextQuery(String text) {
    return q -> q.multiMatch(m -> m
            .query(text)
            .fields("title", "body", "text")
            .fuzziness("1")
            .prefixLength(3)
            .analyzer("standard")
            .type(TextQueryType.MostFields)
    );
}

How It Works

  • fuzziness("1") -> Allows one edit distance
  • prefixLength(3) -> First 3 characters must match
  • Handles typos and spelling mistakes

Best for: User-generated search queries.


Spring Boot Elasticsearch kNN Vector Search (Pure Semantic Search)

This is NOT hybrid search.

It is: kNN semantic ranking + filter(bool(must: BM25 + fuzzy))

public List<SearchResult> similaritySearch(String query) {

    SearchRequest.Builder builder = new SearchRequest.Builder()
            .index(elasticProperties.getIndices())
            .size(20)
            .minScore(elasticProperties.getMinScore())
            .knn(knn -> knn
                    .field("embeddings")
                    .k(20)
                    .numCandidates(100)
                    .queryVectorBuilder(qvb -> qvb
                            .textEmbedding(te -> te
                                    .modelId(elasticProperties.getModelId())
                                    .modelText(query)
                            )
                    )
                    .filter(f -> f
                            .bool(b -> b
                                    .must(fullTextQuery(query))
                                    .must(fuzzyTextQuery(query))
                                    .minimumShouldMatch(
                                        elasticProperties.getSimilarityThreshold())
                            )
                    )
            );

    SearchRequest searchRequest = builder.build();
    SearchResponse<SearchResult> response =
            elasticsearchClient.search(searchRequest, SearchResult.class);

    ...
}

How This Works

  • kNN performs semantic similarity ranking
  • Elasticsearch generates embedding using modelId
  • Results are ranked by vector similarity
  • Full-text + fuzzy act as filters (must match)
  • minScore removes weak semantic matches

Why This Is Better Than Hybrid Scoring?

  • Cleaner ranking logic
  • No unpredictable score blending
  • Semantic intent drives results
  • Lexical filters ensure relevance

Full Text vs Fuzzy vs Semantic

Search Type Ranking Based On Best For
Full Text BM25 Keyword match
Fuzzy Edit distance Typo handling
kNN Semantic Vector similarity Intent understanding

Conclusion

We implemented a production-ready Spring Boot Elasticsearch vector search using:

  • Official Java Client 9.2.5
  • Semantic kNN search
  • BM25 filtering
  • Fuzzy filtering

This architecture provides:

  • High relevance
  • Better semantic understanding
  • Strong control over search quality
  • Production scalability

Support This Free Tool!

Buying me a coffee helps keep the project running and supports new features.

cards
Powered by paypal

Thank you for helping this blog thrive!

About The Author

author-image
I write about cryptography, web security, and secure software development. Creator of practical crypto validation tools at Devglan.

Further Reading on Spring Boot