Skip to content

Commit 396e3de

Browse files
committed
added validation test for DateRangeIncludingNowQuery approximation
1 parent f1ff627 commit 396e3de

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

server/src/test/java/org/opensearch/search/approximate/ApproximatePointRangeQueryTests.java

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@
2424
import org.apache.lucene.search.TotalHits.Relation;
2525
import org.apache.lucene.store.Directory;
2626
import org.apache.lucene.tests.index.RandomIndexWriter;
27+
import org.opensearch.common.time.DateFormatter;
28+
import org.opensearch.common.time.DateMathParser;
29+
import org.opensearch.index.mapper.DateFieldMapper;
30+
import org.opensearch.index.mapper.DateFieldMapper.DateFieldType;
31+
import org.opensearch.index.mapper.DateFieldMapper.Resolution;
32+
import org.opensearch.index.query.DateRangeIncludingNowQuery;
2733
import org.opensearch.search.internal.SearchContext;
2834
import org.opensearch.search.sort.SortOrder;
2935
import org.opensearch.test.OpenSearchTestCase;
@@ -730,6 +736,85 @@ public void testNycTaxiDataDistribution() throws IOException {
730736
}
731737
}
732738

739+
public void testDateRangeIncludingNowQueryApproximation() throws IOException {
740+
try (Directory directory = newDirectory()) {
741+
try (RandomIndexWriter iw = new RandomIndexWriter(random(), directory, new WhitespaceAnalyzer())) {
742+
int dims = 1;
743+
744+
DateFieldType dateFieldType = new DateFieldType("@timestamp");
745+
long minute = 60 * 1000L;
746+
747+
long currentTime = System.currentTimeMillis();
748+
long startTimestamp = currentTime - (48 * 60 * minute); // Start 48 hours ago
749+
750+
// Create 10000 documents with 1 minute intervals
751+
for (int i = 0; i < 10000; i++) {
752+
long timestamp = startTimestamp + (i * minute);
753+
754+
iw.addDocument(asList(new LongPoint("@timestamp", timestamp), new NumericDocValuesField("@timestamp", timestamp)));
755+
}
756+
757+
iw.flush();
758+
iw.forceMerge(1);
759+
try (IndexReader reader = iw.getReader()) {
760+
IndexSearcher searcher = new IndexSearcher(reader);
761+
762+
testApproximateVsExactDateQuery(searcher, "@timestamp", "now-1h", "now", 50, dims);
763+
764+
testApproximateVsExactDateQuery(searcher, "@timestamp", "now-1d", "now", 50, dims);
765+
766+
testApproximateVsExactDateQuery(searcher, "@timestamp", "now-30m", "now+30m", 50, dims);
767+
768+
}
769+
}
770+
}
771+
}
772+
773+
private void testApproximateVsExactDateQuery(
774+
IndexSearcher searcher,
775+
String field,
776+
String lowerBound,
777+
String upperBound,
778+
int size,
779+
int dims
780+
) throws IOException {
781+
// Parse date expressions to milliseconds
782+
DateFormatter formatter = DateFieldMapper.getDefaultDateTimeFormatter();
783+
DateMathParser parser = formatter.toDateMathParser();
784+
long nowInMillis = System.currentTimeMillis();
785+
786+
long lower = Resolution.MILLISECONDS.convert(parser.parse(lowerBound, () -> nowInMillis));
787+
long upper = Resolution.MILLISECONDS.convert(parser.parse(upperBound, () -> nowInMillis));
788+
789+
Query exactQuery = LongPoint.newRangeQuery(field, lower, upper);
790+
791+
// Wrap with DateRangeIncludingNowQuery if using "now"
792+
if (lowerBound.contains("now") || upperBound.contains("now")) {
793+
exactQuery = new DateRangeIncludingNowQuery(exactQuery);
794+
795+
assertTrue(
796+
"Query should be wrapped in DateRangeIncludingNowQuery when using 'now'",
797+
exactQuery instanceof DateRangeIncludingNowQuery
798+
);
799+
800+
exactQuery = ((DateRangeIncludingNowQuery) exactQuery).getQuery();
801+
}
802+
803+
ApproximatePointRangeQuery approximateQuery = new ApproximatePointRangeQuery(
804+
field,
805+
pack(new long[] { lower }).bytes,
806+
pack(new long[] { upper }).bytes,
807+
1,
808+
ApproximatePointRangeQuery.LONG_FORMAT
809+
);
810+
approximateQuery.setSize(size);
811+
812+
TopDocs exactDocs = searcher.search(exactQuery, size);
813+
TopDocs approxDocs = searcher.search(approximateQuery, size);
814+
815+
verifyRangeQueries(searcher, exactQuery, approxDocs, exactDocs, field, lower, upper, size, dims);
816+
}
817+
733818
private void testApproximateVsExactQuery(IndexSearcher searcher, String field, long lower, long upper, int size, int dims)
734819
throws IOException {
735820
// Test with approximate query
@@ -746,6 +831,21 @@ private void testApproximateVsExactQuery(IndexSearcher searcher, String field, l
746831
Query exactQuery = LongPoint.newRangeQuery(field, lower, upper);
747832
TopDocs approxDocs = searcher.search(approxQuery, size);
748833
TopDocs exactDocs = searcher.search(exactQuery, size);
834+
835+
verifyRangeQueries(searcher, exactQuery, approxDocs, exactDocs, field, lower, upper, size, dims);
836+
}
837+
838+
private void verifyRangeQueries(
839+
IndexSearcher searcher,
840+
Query exactQuery,
841+
TopDocs approxDocs,
842+
TopDocs exactDocs,
843+
String field,
844+
long lower,
845+
long upper,
846+
int size,
847+
int dims
848+
) throws IOException {
749849
// Verify approximate query returns correct number of results
750850
assertTrue("Approximate query should return at most " + size + " docs", approxDocs.scoreDocs.length <= size);
751851
// If exact query returns fewer docs than size, approximate should match

0 commit comments

Comments
 (0)