Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ private void projectPlusOverriding(
List<String> originalFieldNames = context.relBuilder.peek().getRowType().getFieldNames();
List<RexNode> toOverrideList =
originalFieldNames.stream()
.filter(newNames::contains)
.filter(originalName -> shouldOverrideField(originalName, newNames))
.map(a -> (RexNode) context.relBuilder.field(a))
.toList();
// 1. add the new fields, For example "age0, country0"
Expand All @@ -870,6 +870,17 @@ private void projectPlusOverriding(
context.relBuilder.rename(expectedRenameFields);
}

private boolean shouldOverrideField(String originalName, List<String> newNames) {
return newNames.stream()
.anyMatch(
newName ->
// Match exact field names (e.g., "age" == "age") for flat fields
newName.equals(originalName)
// OR match nested paths (e.g., "resource.attributes..." starts with
// "resource.")
|| newName.startsWith(originalName + "."));
Copy link
Collaborator

Choose a reason for hiding this comment

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

is there any other place using this pattern of detection? Or if there is a better way to detect if it is a nested field or not?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In CalciteRelNodeVisitor.java, the visitFlatten() method uses the same startsWith() pattern:

  public RelNode visitFlatten(Flatten node, CalcitePlanContext context) {
    visitChildren(node, context);
    RelBuilder relBuilder = context.relBuilder;
    String fieldName = node.getField().getField().toString();
    // Match the sub-field names with "field.*"
    List<RelDataTypeField> fieldsToExpand =
        relBuilder.peek().getRowType().getFieldList().stream()
            .filter(f -> f.getName().startsWith(fieldName + "."))  // ← Same pattern!
            .toList();
    // ... rest of method
  }

}

private List<List<RexInputRef>> extractInputRefList(List<RelBuilder.AggCall> aggCalls) {
return aggCalls.stream()
.map(RelBuilder.AggCall::over)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public void init() throws Exception {
loadIndex(Index.BANK);
loadIndex(Index.EVENTS_NULL);
loadIndex(Index.TIME_TEST_DATA);
loadIndex(Index.TELEMETRY);
}

@Test
Expand Down Expand Up @@ -984,4 +985,85 @@ public void testStatsWithBinsOnTimeAndTermField_Avg() throws IOException {
rows(50, "us-east", "2024-07-01 00:05:00"),
rows(40.25, "us-west", "2024-07-01 00:01:00"));
}

@Test
public void testBinWithNestedFieldWithoutExplicitProjection() throws IOException {
// Test bin command on nested field without explicit fields projection
// This reproduces the bug from https://github.com/opensearch-project/sql/issues/4482
// The telemetry index has: resource.attributes.telemetry.sdk.version (values: 10, 11, 12, 13,
// 14)
JSONObject result =
executeQuery(
String.format(
"source=%s | bin `resource.attributes.telemetry.sdk.version` span=2 | sort"
+ " `resource.attributes.telemetry.sdk.version`",
TEST_INDEX_TELEMETRY));

// When binning a nested field, all sibling fields in the struct are also returned
verifySchema(
result,
schema("resource.attributes.telemetry.sdk.enabled", null, "boolean"),
schema("resource.attributes.telemetry.sdk.language", null, "string"),
schema("resource.attributes.telemetry.sdk.name", null, "string"),
schema("severityNumber", null, "int"),
schema("resource.attributes.telemetry.sdk.version", null, "string"));

// With span=2 on values [10, 11, 12, 13, 14], we expect binned ranges:
// 10 -> 10-12, 11 -> 10-12, 12 -> 12-14, 13 -> 12-14, 14 -> 14-16
// The binned field is the last column
verifyDataRows(
result,
rows(true, "java", "opentelemetry", 9, "10-12"),
rows(false, "python", "opentelemetry", 12, "10-12"),
rows(true, "javascript", "opentelemetry", 9, "12-14"),
rows(false, "go", "opentelemetry", 16, "12-14"),
rows(true, "rust", "opentelemetry", 12, "14-16"));
}

@Test
public void testBinWithNestedFieldWithExplicitProjection() throws IOException {
// Test bin command on nested field WITH explicit fields projection (workaround)
// This is the workaround mentioned in https://github.com/opensearch-project/sql/issues/4482
JSONObject result =
executeQuery(
String.format(
"source=%s | bin `resource.attributes.telemetry.sdk.version` span=2 | fields"
+ " `resource.attributes.telemetry.sdk.version` | sort"
+ " `resource.attributes.telemetry.sdk.version`",
TEST_INDEX_TELEMETRY));
verifySchema(result, schema("resource.attributes.telemetry.sdk.version", null, "string"));

// With span=2 on values [10, 11, 12, 13, 14], we expect binned ranges
verifyDataRows(
result, rows("10-12"), rows("10-12"), rows("12-14"), rows("12-14"), rows("14-16"));
}

@Test
public void testBinWithEvalCreatedDottedFieldName() throws IOException {
JSONObject result =
executeQuery(
String.format(
"source=%s | eval `resource.temp` = 1 | bin"
+ " `resource.attributes.telemetry.sdk.version` span=2 | sort"
+ " `resource.attributes.telemetry.sdk.version`",
TEST_INDEX_TELEMETRY));

verifySchema(
result,
schema("resource.attributes.telemetry.sdk.enabled", null, "boolean"),
schema("resource.attributes.telemetry.sdk.language", null, "string"),
schema("resource.attributes.telemetry.sdk.name", null, "string"),
schema("resource.temp", null, "int"),
schema("severityNumber", null, "int"),
schema("resource.attributes.telemetry.sdk.version", null, "string"));

// Data column order: enabled, language, name, severityNumber, resource.temp, version
verifyDataRows(
result,
rows(true, "java", "opentelemetry", 9, 1, "10-12"),
rows(false, "python", "opentelemetry", 12, 1, "10-12"),
rows(true, "javascript", "opentelemetry", 9, 1, "12-14"),
rows(false, "go", "opentelemetry", 16, 1, "12-14"),
rows(true, "rust", "opentelemetry", 12, 1, "14-16"));
}
}
Loading