Skip to content

Conversation

yuancu
Copy link
Collaborator

@yuancu yuancu commented Sep 4, 2025

Description

Support time modifier in search command.

Changes are cherry-picked from a branch based on #4152. Waiting for #4152 to be completed.

Examples:

source=any earliest='2020-12-10'
source=any earliest='2020-12-10' latest='2025-09-10 13:00:12'
source=any latest=now
source=logs earliest=-7d
source=logs earliest='-1d@d'

Queries with earliest and latest time modifiers will be converted to a query string query with comparison conditions on the implicit timestamp field @timestamp. For example, query source=time_test earliest=-1year latest='-50d@w3' is converted to the following DSL:

{
  "query": {
    "query_string": {
      "query": "(@timestamp:>=now-1y) AND (@timestamp:<=now-50d/w-5d)",
    }
  }
}

Work items

  • support absolute time like 2012-10-10
  • support relative time range like now, -30m, -2h@h, @w0
  • support chained time range offsets like -mon@mon+7d
  • Unix epoch time like 1 (UTC January 1, 1970 at 12:00:01 AM)

Related Issues

Resolves #4135

Implementation Walk-through

Implementation Details

  1. Time Modifier Processing

The core functionality is implemented in the visitTimeModifierValue and visitTimeModifierExpression methods in AstExpressionBuilder.java:

  • visitTimeModifierValue: Converts time values to OpenSearch date math expressions
  • visitTimeModifierExpression: Creates comparison conditions for @timestamp field in query string
  1. Time Format Conversion

The PR extends DateTimeUtils.java with the parseRelativeTime method, which transforms PPL time expressions to OpenSearch date math expressions.

  1. Query String Query Creation

Time modifiers are converted to search comparisons with a query string on the implicit @timestamp field, which is now defined as a constant in OpenSearchConstants.java. For example, search earliest=-10days@month latest=now() is converted to a query string query like the following:

{
  "query": {
    "query_string": {
      "query": "(@timestamp:>=-10d/M) AND (@timestamp:<=now)"
    }
  }
}

PPL Time Modifiers to OpenSearch Date Math Examples

  • Absolute Times

    PPL Time Modifier OpenSearch Date Math Explanation
    '2023-01-01' 2023-01-01 Simple date
    '2023-01-01 13:45:30' 2023-01-01T13:45:30Z Date with time
  • Relative Times

    PPL Time Modifier OpenSearch Date Math Explanation
    now now Current time
    -30s now-30s 30 seconds ago
    -1h now-1h 1 hour ago
    +1d now+1d 1 day in future
  • Snapping to Time Units (Using @)

    PPL Time Modifier OpenSearch Date Math Explanation
    -1d@d now-1d/d 1 day ago, rounded to day
    @h now/h Round to current hour
    @m now/M Round to current month
  • Week Days

    PPL Time Modifier OpenSearch Date Math Explanation
    @w0 /w-1d or /w+6d Previous Sunday (depending on current day)
    @w1 /w Start of week (Monday)
    @w4 /w+3d Thursday of current week
  • Special Cases

PPL Time Modifier OpenSearch Date Math Explanation
@q /M or /M-1M or /M-2M Start of current quarter
-2q -6M 2 quarters ago (6 months)
1234.567 1234567 Unix timestamp (seconds → milliseconds)
  • Complex Expressions
PPL Time Modifier OpenSearch Date Math Explanation
-1d+1y@mon now-1d+1y/M 1 day ago + 1 year, rounded to month
-3d@d-2h+10m now-3d/d-2h+10m 3 days ago, day start, minus 2 hours, plus 10 minutes

Check List

  • New functionality includes testing.
  • New functionality has been documented.
  • New functionality has javadoc added.
  • New functionality has a user manual doc added.
  • New PPL command checklist all confirmed.
  • API changes companion pull request created.
  • Commits are signed per the DCO using --signoff or -s.
  • Public documentation issue/PR created.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

@yuancu yuancu added the enhancement New feature or request label Sep 4, 2025
@vamsimanohar
Copy link
Member

can you review this: #4152
I am changing the grammar for search expression and its functionality.
We might need to reevaluate the implementation.

@yuancu
Copy link
Collaborator Author

yuancu commented Sep 7, 2025

Hi @vamsimanohar, thank you for reminding! I think the functionality does not overlap, I'll re-implement this based on your grammar.

@vamsimanohar
Copy link
Member

@yuancu Few things to keep in mind.

We fundamentally want search command to be always push down and translate toquery_stringfunction in DSL which follows Lucene query syntax. Anything we add to search command should get translated to lucene query.

I think it should be possible with your changes.

@yuancu yuancu changed the title Support absolute time range in search command Support time modifiers in search command Sep 12, 2025
Signed-off-by: Yuanchun Shen <[email protected]>

Unit test search with absolute time range

Signed-off-by: Yuanchun Shen <[email protected]>

Rephrase timeRange and timeModifier

Signed-off-by: Yuanchun Shen <[email protected]>

Switch to earliest and latest udf

Signed-off-by: Yuanchun Shen <[email protected]>

Add a convert util

Signed-off-by: Yuanchun Shen <[email protected]>

Verify time correctness during coversion

Signed-off-by: Yuanchun Shen <[email protected]>

Fix quarter parsing bugs

Signed-off-by: Yuanchun Shen <[email protected]>

Fix week snap parsing

Signed-off-by: Yuanchun Shen <[email protected]>

Remove old implementation that translates time modifier to time filter

Signed-off-by: Yuanchun Shen <[email protected]>
getRelativeZonedDateTime(
expression, ZonedDateTime.ofInstant(clock.instant(), clock.getZone()));
return earliest.isBefore(candidateDatetime);
return !earliest.isAfter(candidateDatetime);
Copy link
Collaborator Author

@yuancu yuancu Sep 16, 2025

Choose a reason for hiding this comment

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

Modified because earliest should be greater or equal.

;

timeSnap
: AT timeModifierUnit;
Copy link
Collaborator Author

@yuancu yuancu Sep 17, 2025

Choose a reason for hiding this comment

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

Asking for help: currently, AT timeModifierUnit can not be matched. Since antlr is parsed bottom-up, plus that a shorter rule matching longer text will be prioritized, AT timeModifierUnit will always be matched as an identifier by the following rule:

// OpenSearchPPLLexer.g4
ID:                                 ID_LITERAL;
fragment ID_LITERAL:                ([@*A-Z_])+?[*A-Z_\-0-9]*;
// OpenSearchPPLParser.g4
ident
   : (DOT)? ID

As a result, I can not write something like source=t earliest=-10h@day, but have to write it as source=t earliest='-10h@day' because -10h@day will be matched to the shorter rule ident.

I tried to make the grammar context aware, but had no luck with multiple solutions. Is there any suggestion for a workaround?

Copy link
Member

Choose a reason for hiding this comment

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

@yuancu have you figured out anything on this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, I haven't :/

testImplementation group: 'org.hamcrest', name: 'hamcrest-library', version: "${hamcrest_version}"
testImplementation group: 'org.mockito', name: 'mockito-core', version: "${mockito_version}"
testImplementation group: 'org.mockito', name: 'mockito-junit-jupiter', version: "${mockito_version}"
testImplementation group: 'org.opensearch', name: 'opensearch', version: "${opensearch_version}"
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This dependency is added for the access of org.opensearch.common.time.DateMathParser -- I want to make sure that the parsed OpenSearch date math like now-1d/M-2M returns the intended instant for -1d@q

Copy link
Collaborator

Choose a reason for hiding this comment

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

parseRelativeTime() is called by PPL module only, right? if move parseRelativeTime to PPL module, does opensearch depedency still needed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, it is only called by PPL module. If I still want to assure the correctness of the parsed instant, I'll have to move this dependency to the PPL module.

Is there any concern over this dependency? If it's for the performance, as the dependency is only test time, I assume there would be no harm to the runtime performance.

@vamsimanohar
Copy link
Member

@yuancu hey can you update the description with latest implementation where you are translating to Lucene query.

HRS: 'HRS';
HOURS: 'HOURS';
DAYS: 'DAYS';
WEEKS: 'WEEKS';
Copy link
Member

Choose a reason for hiding this comment

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

can you add these new terms to searchKeyWords or keywordCanbeId

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Added timeModifierUnit to searchableKeyWord. I wonder how does this change the parsing behavior


searchExpression
: LT_PRTHS searchExpression RT_PRTHS # groupedExpression
: timeModifier # timeModifierExpression
Copy link
Member

Choose a reason for hiding this comment

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

For my understanding: This implies we can write only timeModifier in searchExpression.
Can you update search.rst with these changes.

Copy link
Collaborator

Choose a reason for hiding this comment

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

+1, please update doc.

JSONObject result1 =
executeQuery(
String.format(
"search source=%s earliest='2025-08-01 03:47:41' latest=now | fields @timestamp",
Copy link
Collaborator

Choose a reason for hiding this comment

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

What if earliest is a field name? Should add backtick?


searchExpression
: LT_PRTHS searchExpression RT_PRTHS # groupedExpression
: timeModifier # timeModifierExpression
Copy link
Collaborator

Choose a reason for hiding this comment

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

+1, please update doc.

: LT_PRTHS searchExpression RT_PRTHS # groupedExpression
: timeModifier # timeModifierExpression
| LT_PRTHS searchExpression RT_PRTHS # groupedExpression
| NOT searchExpression # notExpression
Copy link
Collaborator

Choose a reason for hiding this comment

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

do timemodifier support NOT? e.g. search source=index NOT latest=now

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes. Time modifiers are converted conditions with SearchComparison. Any further operation that is applicable to search comparison, such as NOT, OR, AND, are applicable to time modifiers.

testImplementation group: 'org.hamcrest', name: 'hamcrest-library', version: "${hamcrest_version}"
testImplementation group: 'org.mockito', name: 'mockito-core', version: "${mockito_version}"
testImplementation group: 'org.mockito', name: 'mockito-junit-jupiter', version: "${mockito_version}"
testImplementation group: 'org.opensearch', name: 'opensearch', version: "${opensearch_version}"
Copy link
Collaborator

Choose a reason for hiding this comment

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

parseRelativeTime() is called by PPL module only, right? if move parseRelativeTime to PPL module, does opensearch depedency still needed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[FEATURE] Support earliest and latest in search command
3 participants