Skip to content

Conversation

@bsbodden
Copy link
Collaborator

Summary

This PR introduces a comprehensive Dynamic Indexing feature for Redis OM Spring, enabling runtime index configuration through SpEL expressions, multi-tenant support, ephemeral indexes, and index
migration strategies. This provides flexibility for applications requiring dynamic index management based on runtime context.

Key Features

  1. SpEL-Based Dynamic Index Names
  • Support for Spring Expression Language in @IndexingOptions annotation
  • Dynamic index names evaluated at runtime: indexName = "products_#{@tenantService.getCurrentTenant()}_idx"
  • Access to Spring beans, environment properties, and system properties
  • Automatic fallback to default values when expressions fail
  1. Multi-Tenant Index Support
  • RedisIndexContext for thread-local tenant context management
  • TenantService pattern for managing current tenant state
  • Tenant-specific indexes that can be created/destroyed dynamically
  • Custom IndexResolver interface for advanced resolution logic
  1. Ephemeral Indexes (EphemeralIndexService)
  • Create temporary indexes with automatic TTL-based cleanup
  • Extend or reduce TTL for existing ephemeral indexes
  • Useful for testing, analytics, and temporary data processing
  • Background cleanup of expired indexes
  1. Index Migration (IndexMigrationService)
  • Blue-Green: Create new index, reindex data, switch alias atomically
  • Dual-Write: Write to both indexes during migration
  • In-Place: Update existing index (for minor changes)
  • Version tracking and alias management
  • MigrationResult and ReindexResult for operation status
  1. Configurable Index Definitions (ConfigurableIndexDefinitionProvider)
  • Runtime registration and updates of index definitions
  • Bulk operations for managing multiple indexes
  • Export/import index configurations as JSON
  • Validation and statistics for index definitions

New Components

Component Description
@IndexingOptions Enhanced annotation with indexName, keyPrefix, creationMode
RedisIndexContext Thread-local context for tenant/environment information
IndexResolver Interface for custom index name/prefix resolution
DefaultIndexResolver Default implementation using context and annotations
EphemeralIndexService Service for TTL-based temporary indexes
IndexMigrationService Service for zero-downtime index migrations
ConfigurableIndexDefinitionProvider Runtime index configuration management
MigrationStrategy Enum: BLUE_GREEN, DUAL_WRITE, IN_PLACE

Demo Application

New roms-multitenant demo showcasing:

  • Product and Order entities with dynamic index names
  • REST API for tenant switching and product management
  • Admin endpoints for index creation/verification
  • Interactive HTML UI demonstrating tenant isolation
  • Integration tests for dynamic index creation

Documentation

  • ephemeral-indexes.adoc: Guide for temporary indexes with TTL
  • index-migration.adoc: Guide for migration strategies
  • multi-tenant-support.adoc: Comprehensive multi-tenancy guide
  • index-creation.adoc: Updated with dynamic indexing examples
  • Complete Javadoc for all new public APIs

Important Notes

Note on keyPrefix: The keyPrefix attribute in @IndexingOptions affects the index configuration (what key prefix the index searches), not the actual key storage by Spring Data Redis. Documents are
stored using Spring Data Redis's static keyspace. For true data isolation, implement a custom KeyspaceResolver or tenant-aware ID strategy.

Implements Phase 1 of the Dynamic Indexing Feature Design, enabling Spring Expression Language
(SpEL) support in @IndexingOptions for runtime-evaluated index names and key prefixes.

Key features:
- Support for SpEL expressions in indexName and keyPrefix attributes
- Template expression syntax with #{...} markers
- Access to environment properties, beans, and system properties
- Automatic fallback to default naming when SpEL evaluation fails
- Full backward compatibility maintained

Use cases enabled:
- Multi-tenant indexing with tenant-specific names and prefixes
- Version-based index naming for blue-green deployments
- Environment-aware index configuration
- Dynamic index naming based on runtime context

Breaking changes: None - existing code continues to work unchanged

Testing: Comprehensive test suite with 100% coverage including:
- Environment property resolution
- Bean reference resolution
- Method invocations in SpEL
- Fallback behavior on evaluation failure
- Multi-tenant scenarios
- System properties access
- Add RedisIndexContext for thread-local tenant and environment context
- Add IndexResolver interface for custom index name/prefix resolution strategies
- Add DefaultIndexResolver with full SpEL evaluation support for context variables
- Extend RediSearchIndexer with context-aware index operations
- Support dynamic index naming and key prefixes based on runtime context
- Enable multi-tenant Redis deployments with isolated indexes per tenant
…ime configuration

- Add SpEL expression support for dynamic index naming and key prefixes
- Implement RedisIndexContext for thread-local multi-tenant isolation
- Create IndexResolver interface for customizable index resolution strategies
- Add IndexMigrationService supporting Blue-Green, Dual-Write, and In-Place migration strategies
- Implement ConfigurableIndexDefinitionProvider for runtime index configuration
- Support context-aware index creation with tenant-specific indices
- Add comprehensive validation, export/import, and statistics functionality
- Maintain 100% backward compatibility with existing applications

Components added:
- RedisIndexContext: ThreadLocal context storage for tenant/environment data
- DefaultIndexResolver: SpEL-aware resolver with application context integration
- IndexMigrationService: Production-ready index migration with versioning
- ConfigurableIndexDefinitionProvider: Runtime index management and Spring Data Redis bridge
- Supporting classes: MigrationResult, ReindexResult, MigrationStrategy, ValidationResult

Test coverage: 50+ tests including comprehensive integration tests demonstrating
real Redis functionality with multi-tenant data isolation and dynamic configuration.
- Enhance README with dynamic indexing and multi-tenant support highlights
- Add extensive dynamic indexing section to index-creation.adoc covering:
  - SpEL expressions for dynamic index naming
  - Environment-based and bean reference configurations
  - Multi-tenant index context and custom resolvers
  - Error handling, migration services, and best practices
- Create dedicated multi-tenant-support.adoc page with:
  - RedisIndexContext and thread-local isolation
  - Custom index resolvers and tenant management service
  - Request-scoped tenant context and data access patterns
  - Monitoring, observability, and troubleshooting guides
- Update navigation to include multi-tenant support documentation

This documentation covers all aspects of the new dynamic indexing features
including SpEL evaluation, multi-tenant isolation, index migration, and
enterprise-ready patterns for production deployments.
…gement

- Add real Redis alias operations to RediSearchIndexer (createAlias, removeAlias, updateAlias)
  - Integrate with existing SearchOperations interface methods
  - Support FT.ALIASADD, FT.ALIASUPDATE, FT.ALIASDEL Redis commands

- Update IndexMigrationService to use real Redis aliasing for blue-green deployments
  - switchAlias() now creates actual Redis aliases instead of stub implementation
  - Enable zero-downtime index migrations with atomic alias switching

- Add EphemeralIndexService for temporary indexes with TTL support
  - Automatic deletion after specified time-to-live expires
  - Support for extending TTL of existing ephemeral indexes
  - Proper cleanup on service shutdown via DisposableBean
  - Useful for batch processing and temporary data analysis

- Add comprehensive integration tests using TestContainers
  - IndexMigrationServiceIntegrationTest: Validates blue-green migration with real aliasing
  - EphemeralIndexServiceIntegrationTest: Tests TTL expiration and extension
  - CustomIndexResolverIntegrationTest: Validates custom index resolver functionality

All tests passing (1611 tests, 100% success rate)
Add missing Javadoc comments to fix build warnings in the indexing
module. This includes documentation for constructors, builder classes,
and all public methods in ConfigurableIndexDefinitionProvider,
EphemeralIndexService, IndexMigrationService, MigrationResult,
ReindexResult, and RediSearchIndexer.

Also wrap SpEL expressions in {@code} blocks in RediSearchIndexer
to prevent them from being parsed as Javadoc tags.
Add roms-multitenant demo showcasing dynamic index naming with SpEL
expressions for multi-tenant scenarios. The demo includes:

- Product and Order entities with tenant-aware index names
- TenantService for thread-local tenant context management
- REST controllers for tenant switching and product management
- Admin endpoints for index creation and verification
- Interactive HTML UI for demonstrating tenant isolation
- Integration tests verifying dynamic index creation

The demo demonstrates how to use @IndexingOptions with SpEL
expressions like "products_#{@tenantService.getCurrentTenant()}_idx"
to create tenant-specific search indexes at runtime.
Add new documentation pages for dynamic indexing features:

- ephemeral-indexes.adoc: Covers EphemeralIndexService for creating
  temporary indexes with TTL, including use cases for testing,
  analytics, and temporary data processing

- index-migration.adoc: Covers IndexMigrationService with Blue-Green,
  Dual-Write, and In-Place migration strategies for zero-downtime
  index updates

Also update multi-tenant-support.adoc to clarify that keyPrefix in
@IndexingOptions affects only index configuration, not actual key
storage by Spring Data Redis. Add navigation entries and update
outline.md.
Add new test entity fixtures:
- ComplexSpelEntity: Entity with complex SpEL expressions for testing
- SystemPropertyEntity: Entity using system property SpEL expressions

Add BulkIndexOperationsIntegrationTest for testing batch index
operations and update DynamicIndexingSpelTest and
MultiTenantIndexIsolationIntegrationTest with improved test cases
for dynamic index resolution.
… isolation

The keyPrefix attribute in @IndexingOptions now controls both the index
configuration AND the actual key storage location for documents. This
provides complete multi-tenant data isolation where each tenant's data
is stored with different key prefixes.

Changes:
- Add resolveDynamicKeyspace() to RedisJSONKeyValueAdapter for @document entities
- Add resolveDynamicKeyspace() to RedisEnhancedKeyValueAdapter for @RedisHash entities
- Update put(), get(), delete() methods to use dynamic keyspace resolution
- Update Product entity to use dynamic keyPrefix with SpEL expressions
- Add comprehensive testTenantSearchIsolation() test for end-to-end verification
- Update multi-tenant documentation to reflect complete isolation support

Example usage:
@IndexingOptions(
    indexName = "products_#{@tenantService.getCurrentTenant()}_idx",
    keyPrefix = "#{@tenantService.getCurrentTenant()}:products:"
)

For tenant "acme":
- Index: products_acme_idx
- Keys stored as: acme:products:<id>
@bsbodden bsbodden self-assigned this Nov 27, 2025
@bsbodden bsbodden requested a review from Copilot November 27, 2025 15:28
Copilot finished reviewing on behalf of bsbodden November 27, 2025 15:29
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a comprehensive Dynamic Indexing feature for Redis OM Spring, enabling runtime index configuration through SpEL expressions, multi-tenant support, ephemeral indexes, and index migration strategies. The implementation spans across:

  • SpEL-Based Dynamic Index Names: Support for Spring Expression Language in @IndexingOptions annotation for runtime evaluation
  • Multi-Tenant Index Support: RedisIndexContext for thread-local tenant context management with custom IndexResolver interface
  • Ephemeral Indexes: EphemeralIndexService for creating temporary indexes with automatic TTL-based cleanup
  • Index Migration: IndexMigrationService supporting Blue-Green, Dual-Write, and In-Place migration strategies
  • Configurable Index Definitions: ConfigurableIndexDefinitionProvider for runtime index configuration management

Reviewed changes

Copilot reviewed 65 out of 65 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
redis-om-spring/src/main/java/com/redis/om/spring/indexing/RediSearchIndexer.java Adds SpEL expression evaluation for dynamic index names and key prefixes, context-aware indexing methods, and bulk operations
redis-om-spring/src/main/java/com/redis/om/spring/indexing/RedisIndexContext.java Thread-local context for tenant/environment information with builder pattern and execution utilities
redis-om-spring/src/main/java/com/redis/om/spring/indexing/IndexResolver.java Strategy interface for custom index name/prefix resolution
redis-om-spring/src/main/java/com/redis/om/spring/indexing/DefaultIndexResolver.java Default implementation supporting SpEL and context-based resolution
redis-om-spring/src/main/java/com/redis/om/spring/indexing/IndexMigrationService.java Service for zero-downtime index migrations with multiple strategies
redis-om-spring/src/main/java/com/redis/om/spring/indexing/EphemeralIndexService.java Service for TTL-based temporary indexes with automatic cleanup
redis-om-spring/src/main/java/com/redis/om/spring/indexing/ConfigurableIndexDefinitionProvider.java Runtime index configuration management with validation and export/import
redis-om-spring/src/main/java/com/redis/om/spring/annotations/IndexingOptions.java Enhanced annotation with keyPrefix and comprehensive SpEL documentation
redis-om-spring/src/main/java/com/redis/om/spring/RedisJSONKeyValueAdapter.java Dynamic keyspace resolution integration
redis-om-spring/src/main/java/com/redis/om/spring/RedisEnhancedKeyValueAdapter.java Dynamic keyspace resolution integration
tests/src/test/java/com/redis/om/spring/indexing/* Comprehensive test suite covering all dynamic indexing features
tests/src/test/java/com/redis/om/spring/fixtures/document/model/* Test entities demonstrating SpEL usage patterns
docs/content/modules/ROOT/pages/index-migration.adoc Complete documentation for index migration strategies
demos/roms-multitenant/* Demo application showcasing multi-tenant support

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

* @return the next version string
*/
public String getNextVersion(String incrementType) {
int major = Integer.parseInt(getMajorVersion());
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential uncaught 'java.lang.NumberFormatException'.

Copilot uses AI. Check for mistakes.
Add try-catch blocks to handle potential NumberFormatException when
parsing version numbers from index names and version strings.

- IndexMigrationService.getCurrentIndexVersion(): wrap Integer.parseInt
  with try-catch and log warning on failure, returning 0 as default
- VersionService.getNextVersion(): wrap all three Integer.parseInt calls
  with try-catch blocks, using sensible defaults (1.0.0)
@bsbodden bsbodden merged commit 70b7fa3 into main Nov 27, 2025
5 checks passed
@bsbodden bsbodden deleted the bsb/indexing-ng branch November 27, 2025 16:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants