Query Information
PPL Command/Query:
source=jaeger-span-2024-05-08 | eval example_time = STR_TO_DATE('1987-02-03 12:34:56', '%Y-%m-%d %H:%i:%S') | where startTimeMillis > example_time
Expected Result:
The query should return all documents where startTimeMillis (epoch milliseconds) is greater than the timestamp.
Actual Result:
{
"error": {
"reason": "Error occurred in OpenSearch engine: all shards failed",
"details": "Shard[0]: OpenSearchParseException[failed to parse date field [1987-02-03T12:34:56.000Z] with format [epoch_millis]: [failed to parse date field [1987-02-03T12:34:56.000Z] with format [epoch_millis]]]; nested: IllegalArgumentException[failed to parse date field [1987-02-03T12:34:56.000Z] with format [epoch_millis]]; nested: DateTimeParseException[Failed to parse with all enclosed parsers]",
"type": "SearchPhaseExecutionException"
},
"status": 400
}
Full Stack Trace:
Caused by: org.opensearch.OpenSearchParseException: failed to parse date field [1987-02-03T12:34:56.000Z] with format [epoch_millis]
at org.opensearch.common.time.JavaDateMathParser.parseDateTime(JavaDateMathParser.java:247)
at org.opensearch.common.time.JavaDateMathParser.parse(JavaDateMathParser.java:89)
at org.opensearch.index.mapper.DateFieldMapper$DateFieldType.parseToLong(DateFieldMapper.java:621)
at org.opensearch.index.mapper.DateFieldMapper$DateFieldType.isFieldWithinQuery(DateFieldMapper.java:677)
at org.opensearch.index.query.RangeQueryBuilder.getRelation(RangeQueryBuilder.java:462)
at org.opensearch.index.query.RangeQueryBuilder.doRewrite(RangeQueryBuilder.java:487)
at org.opensearch.index.query.AbstractQueryBuilder.rewrite(AbstractQueryBuilder.java:306)
at org.opensearch.search.builder.SearchSourceBuilder.rewrite(SearchSourceBuilder.java:1187)
Workaround:
Adding head command before the filter prevents query pushdown and executes the comparison in-memory:
source=jaeger-span-2024-05-08 | head 999999 | eval example_time = STR_TO_DATE('1987-02-03 12:34:56', '%Y-%m-%d %H:%i:%S') | where startTimeMillis > example_time
Dataset Information
Dataset/Schema Type
Index Mapping
{
"mappings": {
"properties": {
"startTimeMillis": {
"type": "date",
"format": "epoch_millis"
},
"startTime": {
"type": "long"
},
"operationName": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
Sample Data
{
"startTimeMillis": 1715126504378,
"startTime": 1715126504378733,
"operationName": "oteldemo.ProductCatalogService/GetProduct"
}
Bug Description
Issue Summary:
PPL queries that compare date fields with epoch_millis format against STR_TO_DATE() results fail when the filter is pushed down to OpenSearch. The query optimizer incorrectly converts the timestamp comparison value to an ISO 8601 string format ("1987-02-03T12:34:56.000Z") instead of epoch milliseconds, causing OpenSearch to reject the query since the field expects numeric epoch_millis values.
Steps to Reproduce:
- Create an index with a date field using
epoch_millis format:
PUT /test-date-comparison
{
"mappings": {
"properties": {
"timestamp_field": {
"type": "date",
"format": "epoch_millis"
}
}
}
}
- Insert sample data:
POST /test-date-comparison/_doc
{
"timestamp_field": 1715126504378
}
- Execute PPL query with date comparison:
POST /_plugins/_ppl
{
"query": "source=test-date-comparison | eval example_time = STR_TO_DATE('1987-02-03 12:34:56', '%Y-%m-%d %H:%i:%S') | where timestamp_field > example_time"
}
- Observe the error about failing to parse ISO 8601 date string with epoch_millis format
Impact:
- Users cannot perform date comparisons on fields with
epoch_millis, epoch_second, or epoch_micros formats when using STR_TO_DATE() or other date functions in PPL
- Workaround requires adding
head command which forces in-memory execution, negating query optimization benefits and potentially causing performance issues with large datasets
Environment Information
OpenSearch Version:
OpenSearch 3.3.0-SNAPSHOT (also affects earlier versions)
Additional Details:
Root Cause Analysis
This is a preliminary analysis and requires further investigation.
The stack trace and code analysis reveal the exact failure point:
Failure Flow:
- SQL plugin's
LuceneQuery.value() method formats the timestamp as ISO 8601 string: "1987-02-03T12:34:56.000Z"
- This string is passed to
RangeQueryBuilder as the comparison value
- During query rewrite, OpenSearch's
DateFieldMapper.parseToLong() attempts to parse this string
JavaDateMathParser tries to parse the ISO 8601 string using the field's format (epoch_millis)
- Parsing fails because
epoch_millis expects a numeric string (e.g., "539179496000"), not an ISO 8601 formatted string
Affected Code:
- File:
opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/LuceneQuery.java
- Method:
value(ExprValue literal, ExprType fieldType)
Current Logic (Incorrect):
protected Object value(ExprValue literal, ExprType fieldType) {
if (fieldType instanceof OpenSearchDateType) {
OpenSearchDateType openSearchDateType = (OpenSearchDateType) fieldType;
if (literal.type().equals(ExprCoreType.TIMESTAMP)) {
return openSearchDateType.hasNoFormatter()
? literal.timestampValue().toEpochMilli()
: openSearchDateType.getFormattedDate(literal.timestampValue()); // ← Returns ISO 8601 string
}
}
return literal.value();
}
Problem:
When a field has format epoch_millis, hasNoFormatter() returns false (because formats list is not empty), so the code calls getFormattedDate() which returns an ISO 8601 string. However, OpenSearch expects a numeric value for epoch_millis format.
Explain Plan Evidence:
"query":{"range":{"startTimeMillis":{"from":"1987-02-03T12:34:56.000Z",...}}}
Proposed Solution
This is a preliminary analysis and requires further investigation.
The possible fix could be modify the LuceneQuery.value() method to detect numeric date formats and return numeric values instead of formatted strings.
Proposed Code Change:
protected Object value(ExprValue literal, ExprType fieldType) {
if (fieldType instanceof OpenSearchDateType) {
OpenSearchDateType openSearchDateType = (OpenSearchDateType) fieldType;
if (literal.type().equals(ExprCoreType.TIMESTAMP)) {
// Return numeric value if field has no formatter OR uses numeric format
if (openSearchDateType.hasNoFormatter()
|| openSearchDateType.getNumericNamedFormatters().size() > 0) {
return literal.timestampValue().toEpochMilli();
} else {
return openSearchDateType.getFormattedDate(literal.timestampValue());
}
}
// Similar changes for DATE and TIME types
}
return literal.value();
}
Key Changes:
- Check if the field uses numeric formats via
getNumericNamedFormatters().size() > 0
- Return numeric epoch milliseconds for numeric formats
- Only use
getFormattedDate() for non-numeric date formats
Additional Considerations:
- For
epoch_second format, may need to convert: literal.timestampValue().toEpochMilli() / 1000
- For
epoch_micros format, may need to convert: literal.timestampValue().toEpochMilli() * 1000
- Need to handle mixed format strings (e.g., "epoch_millis||strict_date_optional_time")
Related Issues
Screenshots
N/A - Error message and stack trace are text-based and included above.
Query Information
PPL Command/Query:
Expected Result:
The query should return all documents where
startTimeMillis(epoch milliseconds) is greater than the timestamp.Actual Result:
{ "error": { "reason": "Error occurred in OpenSearch engine: all shards failed", "details": "Shard[0]: OpenSearchParseException[failed to parse date field [1987-02-03T12:34:56.000Z] with format [epoch_millis]: [failed to parse date field [1987-02-03T12:34:56.000Z] with format [epoch_millis]]]; nested: IllegalArgumentException[failed to parse date field [1987-02-03T12:34:56.000Z] with format [epoch_millis]]; nested: DateTimeParseException[Failed to parse with all enclosed parsers]", "type": "SearchPhaseExecutionException" }, "status": 400 }Full Stack Trace:
Workaround:
Adding
headcommand before the filter prevents query pushdown and executes the comparison in-memory:Dataset Information
Dataset/Schema Type
Index Mapping
{ "mappings": { "properties": { "startTimeMillis": { "type": "date", "format": "epoch_millis" }, "startTime": { "type": "long" }, "operationName": { "type": "keyword", "ignore_above": 256 } } } }Sample Data
{ "startTimeMillis": 1715126504378, "startTime": 1715126504378733, "operationName": "oteldemo.ProductCatalogService/GetProduct" }Bug Description
Issue Summary:
PPL queries that compare date fields with
epoch_millisformat againstSTR_TO_DATE()results fail when the filter is pushed down to OpenSearch. The query optimizer incorrectly converts the timestamp comparison value to an ISO 8601 string format ("1987-02-03T12:34:56.000Z") instead of epoch milliseconds, causing OpenSearch to reject the query since the field expects numeric epoch_millis values.Steps to Reproduce:
epoch_millisformat:PUT /test-date-comparison { "mappings": { "properties": { "timestamp_field": { "type": "date", "format": "epoch_millis" } } } }POST /test-date-comparison/_doc { "timestamp_field": 1715126504378 }POST /_plugins/_ppl { "query": "source=test-date-comparison | eval example_time = STR_TO_DATE('1987-02-03 12:34:56', '%Y-%m-%d %H:%i:%S') | where timestamp_field > example_time" }Impact:
epoch_millis,epoch_second, orepoch_microsformats when usingSTR_TO_DATE()or other date functions in PPLheadcommand which forces in-memory execution, negating query optimization benefits and potentially causing performance issues with large datasetsEnvironment Information
OpenSearch Version:
OpenSearch 3.3.0-SNAPSHOT (also affects earlier versions)
Additional Details:
epoch_millis#1847Root Cause Analysis
This is a preliminary analysis and requires further investigation.
The stack trace and code analysis reveal the exact failure point:
Failure Flow:
LuceneQuery.value()method formats the timestamp as ISO 8601 string: "1987-02-03T12:34:56.000Z"RangeQueryBuilderas the comparison valueDateFieldMapper.parseToLong()attempts to parse this stringJavaDateMathParsertries to parse the ISO 8601 string using the field's format (epoch_millis)epoch_millisexpects a numeric string (e.g., "539179496000"), not an ISO 8601 formatted stringAffected Code:
opensearch/src/main/java/org/opensearch/sql/opensearch/storage/script/filter/lucene/LuceneQuery.javavalue(ExprValue literal, ExprType fieldType)Current Logic (Incorrect):
Problem:
When a field has format
epoch_millis,hasNoFormatter()returnsfalse(because formats list is not empty), so the code callsgetFormattedDate()which returns an ISO 8601 string. However, OpenSearch expects a numeric value forepoch_millisformat.Explain Plan Evidence:
Proposed Solution
This is a preliminary analysis and requires further investigation.
The possible fix could be modify the
LuceneQuery.value()method to detect numeric date formats and return numeric values instead of formatted strings.Proposed Code Change:
Key Changes:
getNumericNamedFormatters().size() > 0getFormattedDate()for non-numeric date formatsAdditional Considerations:
epoch_secondformat, may need to convert:literal.timestampValue().toEpochMilli() / 1000epoch_microsformat, may need to convert:literal.timestampValue().toEpochMilli() * 1000Related Issues
epoch_millis#1847 - Similar issue with SQL queries where timestamp literals fail on fields without epoch_millis formatScreenshots
N/A - Error message and stack trace are text-based and included above.