feat: implement OpenSearchIndex with full-text and wildcard search
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
package com.cameleer3.server.app.search;
|
||||
|
||||
import com.cameleer3.server.app.AbstractPostgresIT;
|
||||
import com.cameleer3.server.core.search.ExecutionSummary;
|
||||
import com.cameleer3.server.core.search.SearchRequest;
|
||||
import com.cameleer3.server.core.search.SearchResult;
|
||||
import com.cameleer3.server.core.storage.SearchIndex;
|
||||
import com.cameleer3.server.core.storage.model.ExecutionDocument;
|
||||
import com.cameleer3.server.core.storage.model.ExecutionDocument.ProcessorDoc;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.opensearch.testcontainers.OpensearchContainer;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||
import org.springframework.test.context.DynamicPropertySource;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
// Extends AbstractPostgresIT for PostgreSQL datasource needed by Spring context
|
||||
class OpenSearchIndexIT extends AbstractPostgresIT {
|
||||
|
||||
@Container
|
||||
static final OpensearchContainer<?> opensearch =
|
||||
new OpensearchContainer<>("opensearchproject/opensearch:2.19.0")
|
||||
.withSecurityEnabled(false);
|
||||
|
||||
@DynamicPropertySource
|
||||
static void configureOpenSearch(DynamicPropertyRegistry registry) {
|
||||
registry.add("opensearch.url", opensearch::getHttpHostAddress);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
SearchIndex searchIndex;
|
||||
|
||||
@Test
|
||||
void indexAndSearchByText() throws Exception {
|
||||
Instant now = Instant.now();
|
||||
ExecutionDocument doc = new ExecutionDocument(
|
||||
"search-1", "route-a", "agent-1", "app-1",
|
||||
"FAILED", "corr-1", "exch-1",
|
||||
now, now.plusMillis(100), 100L,
|
||||
"OrderNotFoundException: order-12345 not found", null,
|
||||
List.of(new ProcessorDoc("proc-1", "log", "COMPLETED",
|
||||
null, null, "request body with customer-99", null, null, null)));
|
||||
|
||||
searchIndex.index(doc);
|
||||
Thread.sleep(1500); // Allow OpenSearch refresh
|
||||
|
||||
SearchRequest request = new SearchRequest(
|
||||
null, now.minusSeconds(60), now.plusSeconds(60),
|
||||
null, null, null,
|
||||
"OrderNotFoundException", null, null, null,
|
||||
null, null, null, null, null,
|
||||
0, 50, "startTime", "desc");
|
||||
|
||||
SearchResult<ExecutionSummary> result = searchIndex.search(request);
|
||||
assertTrue(result.total() > 0);
|
||||
assertEquals("search-1", result.items().get(0).executionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void wildcardSearchFindsSubstring() throws Exception {
|
||||
Instant now = Instant.now();
|
||||
ExecutionDocument doc = new ExecutionDocument(
|
||||
"wild-1", "route-b", "agent-1", "app-1",
|
||||
"COMPLETED", null, null,
|
||||
now, now.plusMillis(50), 50L, null, null,
|
||||
List.of(new ProcessorDoc("proc-1", "bean", "COMPLETED",
|
||||
null, null, "UniquePayloadIdentifier12345", null, null, null)));
|
||||
|
||||
searchIndex.index(doc);
|
||||
Thread.sleep(1500);
|
||||
|
||||
SearchRequest request = new SearchRequest(
|
||||
null, now.minusSeconds(60), now.plusSeconds(60),
|
||||
null, null, null,
|
||||
"PayloadIdentifier", null, null, null,
|
||||
null, null, null, null, null,
|
||||
0, 50, "startTime", "desc");
|
||||
|
||||
SearchResult<ExecutionSummary> result = searchIndex.search(request);
|
||||
assertTrue(result.total() > 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user