Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Index Management Operations in Easysearch Java SDK 2.0.x

Tech May 12 2

Efficiently managing indices is a core requirement when working with Easysearch. The Java SDK 2.0.x provides a robust API for handling administrative tasks such as index creation, maintenance, and automated lifecycle management. This guide explores the two primary interaction patterns and the essential operations for index administration.

Interaction Patterns: Builder vs. Functional DSL

The SDK offers two distinct ways to construct request objects. While both achieve the same result, the Functional DSL is generally preferred for its readability and conciseness.

Standard Builder Pattern

The traditional approach uses explicit Builder classes. This is familiar to many Java developers but can become verbose as requests grow in complexity.

CreateIndexResponse createResponse = client.indices().create(
    new CreateIndexRequest.Builder()
        .index("inventory-data")
        .aliases("current-inventory",
            new Alias.Builder().isWriteIndex(true).build()
        )
        .build()
);

Functional Lambda Pattern

The recommended approach utilizes Lambda expressions to define the request structure. This eliminates the need to manually instantiate multiple Builder classes and produces a more hierarchical, readable code structure.

CreateIndexResponse createResponse = client.indices()
    .create(idx -> idx
        .index("inventory-data")
        .aliases("current-inventory", alias -> alias
            .isWriteIndex(true)
        )
    );

This style is particularly powerful for complex search queries where nesting is frequent:

SearchResponse<Product> response = client.search(s -> s
    .index("inventory-data")
    .query(q -> q
        .bool(b -> b
            .must(m -> m
                .match(f -> f
                    .field("category")
                    .query("electronics")
                )
            )
            .filter(f -> f
                .range(r -> r
                    .field("stock_count")
                    .gte(JsonData.of(10))
                )
            )
        )
    ),
    Product.class
);

Synchronous Index Management

Synchronous operations block the executing thread until the server returns a response. This is ideal for scripts and administrative tasks where sequential execution is required.

String targetIndex = "log_store";

// Check for existence and remove if necessary
if (client.indices().exists(e -> e.index(targetIndex)).value()) {
    client.indices().delete(d -> d.index(targetIndex));
}

// Create a new index
client.indices().create(c -> c.index(targetIndex));

// Close index (making it read-only and reducing resource usage)
client.indices().close(c -> c.index(targetIndex));

// Open index (restoring it to active status)
client.indices().open(o -> o.index(targetIndex));

// Force immediate visibility of written data
client.indices().refresh(r -> r.index(targetIndex));

// Persist data from memory to disk
client.indices().flush(f -> f.index(targetIndex));

// Optimize index storage by merging segments
client.indices().forcemerge(fm -> fm
    .index(targetIndex)
    .maxNumSegments(1L)
);

Asynchronous Index Management

For applications requiring high throughput or non-blocking behavior, the EasysearchAsyncClient provides a CompletableFuture-based API.

String asyncIndex = "async_logs";
EasysearchAsyncClient asyncClient = AppClient.getAsyncClient();

asyncClient.indices().exists(e -> e.index(asyncIndex))
    .thenCompose(check -> {
        if (check.value()) {
            return asyncClient.indices().delete(d -> d.index(asyncIndex))
                .thenApply(r -> null);
        }
        return CompletableFuture.completedFuture(null);
    })
    .thenCompose(v -> {
        return asyncClient.indices().create(c -> c.index(asyncIndex));
    })
    .whenComplete((res, err) -> {
        if (err != null) {
            System.err.println("Operation failed: " + err.getMessage());
        } else {
            System.out.println("Index lifecycle operation complete.");
        }
    })
    .get(20, TimeUnit.SECONDS);

Index Rollover Implementation

Rollover allows you to automaticallly create a new index when the current write index meets specific criteria, such as age or size. This is crucial for managing time-series data or large-scale logs.

Initial Setup

First, create an index with a numeric suffix and assign a write alias:

String baseIndex = "web-logs-000001";
String aliasName = "web-logs-alias";

client.indices().create(c -> c
    .index(baseIndex)
    .aliases(aliasName, a -> a.isWriteIndex(true))
);

Executing Rollover

You can define rollover conditions programmatically using the Java API:

RolloverResponse rolloverResponse = client.indices().rollover(r -> r
    .alias(aliasName)
    .conditions(cond -> cond
        .maxDocs(50000L)        // Rollover if docs exceed 50,000
        .maxAge(t -> t.time("24h")) // Rollover if older than 24 hours
        .maxSize("10gb")        // Rollover if size exceeds 10GB
    )
);

Alternatively, if you prefer using a raw JSON configuration for conditions, use the withJson method:

String configJson = """
{
  "conditions": {
    "max_docs": 50000,
    "max_age": "1d",
    "max_size": "10gb"
  }
}
""";

RolloverResponse response = client.indices().rollover(r -> r
    .alias(aliasName)
    .withJson(new StringReader(configJson))
);

Operational Recommendations

  • Selection: Use synchronous methods for simple deployment scripts. Use asynchronous methods for application-level index creation to avoid blocking threads.
  • Performance: Operations like forcemerge are resource-intensive. Schedule these during off-peak hours.
  • Consistency: Frequent refresh calls can impact write throughput. Rely on the default refresh interval (typically 1s) unless immediate visibility is strictly required for a specific logic flow.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.