Spring Data Elasticsearch - Quick Reference

SkillSearch

Spring Data Elasticsearch for full-text search and analytics. Covers ElasticsearchOperations, repositories, aggregations, and index management.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Spring Data Elasticsearch - Quick Reference skill

What this skill tells your AI

The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/databases/spring-data-elasticsearch/SKILL.md and read by ahel’s review.

Full Reference: See advanced.md for aggregations, autocomplete/suggestions, bulk operations, index management, and Testcontainers integration.

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: spring-data-elasticsearch for comprehensive documentation.

Dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

Configuration

spring:
  elasticsearch:
    uris: http://localhost:9200
    username: ${ELASTICSEARCH_USERNAME:}
    password: ${ELASTICSEARCH_PASSWORD:}
    connection-timeout: 5s
    socket-timeout: 30s

Document Mapping

@Document(indexName = "products")
public class Product {

    @Id
    private String id;

    @Field(type = FieldType.Text, analyzer = "standard")
    private String name;

    @Field(type = FieldType.Text, analyzer = "standard")
    private String description;

    @Field(type = FieldType.Keyword)
    private String category;

    @Field(type = FieldType.Double)
    private BigDecimal price;

    @Field(type = FieldType.Integer)
    private Integer stock;

    @Field(type = FieldType.Boolean)
    private boolean active;

    @Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second)
    private LocalDateTime createdAt;

    @Field(type = FieldType.Nested)
    private List<ProductAttribute> attributes;

    @Field(type = FieldType.Keyword)
    private List<String> tags;
}

Repository Pattern

public interface ProductRepository extends ElasticsearchRepository<Product, String> {

    List<Product> findByCategory(String category);
    List<Product> findByNameContaining(String name);
    List<Product> findByPriceBetween(BigDecimal min, BigDecimal max);
    List<Product> findByActiveTrue();

    // Pagination
    Page<Product> findByCategory(String category, Pageable pageable);

    // Sorting
    List<Product> findByCategoryOrderByPriceAsc(String category);

    // Count / Exists / Delete
    long countByCategory(String category);
    boolean existsByName(String name);
    void deleteByCategory(String category);
}

Custom Queries

public interface ProductRepository extends ElasticsearchRepository<Product, String> {

    @Query("""
        {
          "multi_match": {
            "query": "?0",
            "fields": ["name^3", "description", "tags"],
            "type": "best_fields",
            "fuzziness": "AUTO"
          }
        }
        """)
    Page<Product> fullTextSearch(String query, Pageable pageable);
}

ElasticsearchOperations

@Service
@RequiredArgsConstructor
public class ProductSearchService {

    private final ElasticsearchOperations elasticsearchOperations;

    public SearchHits<Product> search(ProductSearchCriteria criteria) {
        BoolQuery.Builder boolQuery = new BoolQuery.Builder();

        if (StringUtils.hasText(criteria.getQuery())) {
            boolQuery.must(MultiMatchQuery.of(m -> m
                .query(criteria.getQuery())
                .fields("name^3", "description", "tags")
                .fuzziness("AUTO")
            )._toQuery());
        }

        if (StringUtils.hasText(criteria.getCategory())) {
            boolQuery.filter(TermQuery.of(t -> t
                .field("category")
                .value(criteria.getCategory())
            )._toQuery());
        }

        NativeQuery query = NativeQuery.builder()
            .withQuery(boolQuery.build()._toQuery())
            .withPageable(PageRequest.of(criteria.getPage(), criteria.getSize()))
            .build();

        return elasticsearchOperations.search(query, Product.class);
    }
}

Best Practices

DoDon't
Use appropriate field typesMap everything as text
Define proper analyzersUse default for all
Use filters for exact matchesUse match for keywords
Paginate large result setsFetch all documents at once

When NOT to Use This Skill

  • Raw Elasticsearch API - Use elasticsearch skill for REST API
  • ELK stack setup - Use elasticsearch skill
  • Primary database - Elasticsearch is for search, not ACID transactions

Anti-Patterns

Anti-PatternProblemSolution
Refresh after each writePerformance degradationUse refresh_interval, batch
Deep pagination with from/sizeMemory issuesUse search_after
Mapping all as textPoor search, high diskUse appropriate field types
No index lifecycleDisk exhaustionConfigure ILM policies
Fetching all fieldsWasted bandwidthUse source filtering

Quick Troubleshooting

ProblemDiagnosticFix
Connection failedCheck Elasticsearch runningStart ES, check URI, SSL
Index not foundCheck index nameCreate index, check @Document
Mapping conflictCheck field typesReindex with correct mapping
Search returns nothingCheck analyzerTest with _analyze API
Version conflictCheck @VersionHandle OptimisticLockingFailureException

Production Checklist

  • Cluster configured (3+ nodes)
  • Shards and replicas set
  • Index lifecycle management
  • Proper mapping defined
  • Analyzers configured
  • Bulk operations for indexing
  • Monitoring enabled
  • Security enabled

Reference Documentation

Signals

GitHub stars
33
Forks
8
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
spring-data-elasticsearch
Source
github.com/claude-dev-suite/claude-dev-suite