Skip to content
Closed
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
5 changes: 5 additions & 0 deletions docs/changelog/125566.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 125566
summary: Bracket syntax for accessing dotted field names in ingest processors
area: Ingest Node
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,30 @@ teardown:
index: test
id: "1"
- match: { _source.event.original: "overridden original message" }

---
"Test Rename dotted field access":
- do:
ingest.put_pipeline:
id: "1"
body:
processors:
- rename:
field: "attributes['foo.bar']"
target_field: "attributes['bar.foo']"
- match: { acknowledged: true }

- do:
index:
index: test
id: "1"
pipeline: "1"
body:
attributes:
"foo.bar": "test"

- do:
get:
index: test
id: "1"
- match: { _source.attributes.bar\.foo: "test" }
55 changes: 53 additions & 2 deletions server/src/main/java/org/elasticsearch/ingest/IngestDocument.java
Original file line number Diff line number Diff line change
Expand Up @@ -1041,12 +1041,63 @@ private FieldPath(String path) {
newPath = path;
}
}
this.pathElements = newPath.split("\\.");
if (pathElements.length == 1 && pathElements[0].isEmpty()) {
this.pathElements = parsePath(newPath);
if (pathElements.length == 0 || (pathElements.length == 1 && pathElements[0].isEmpty())) {
throw new IllegalArgumentException("path [" + path + "] is not valid");
}
}

private String[] parsePath(String path) {
List<String> elements = new ArrayList<>();
StringBuilder current = new StringBuilder();
boolean inBrackets = false;
boolean doubleQuote = false;
for (int i = 0; i < path.length(); i++) {
char c = path.charAt(i);
char next = 0;
if (i < path.length() - 1) {
next = path.charAt(i + 1);
}

if (inBrackets == false && c == '[' && (next == '\'' || next == '"')) {
if (current.isEmpty() == false) {
elements.add(current.toString());
current.setLength(0);
}
inBrackets = true;
doubleQuote = next == '"';
i++;
} else if (inBrackets && (c == '\'' || c == '"') && next == ']') {
char expected = doubleQuote ? '"' : '\'';
if (expected != c) {
throw new IllegalArgumentException("path [" + path + "] is not valid");
}
String element = current.toString();
elements.add(element);
current.setLength(0);
inBrackets = false;
i++;
} else if (inBrackets == false && c == '.') {
if (current.isEmpty() == false) {
elements.add(current.toString());
current.setLength(0);
}
} else {
current.append(c);
}
}

if (inBrackets) {
throw new IllegalArgumentException("path [" + path + "] is not valid");
}

if (current.isEmpty() == false) {
elements.add(current.toString());
}

return elements.toArray(new String[0]);
}

public Object initialContext(IngestDocument document) {
return useIngestContext ? document.getIngestMetadata() : document.getCtxMap();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1227,4 +1227,49 @@ public void testSourceHashMapIsNotCopied() {
assertThat(document2.getCtxMap().getMetadata(), not(sameInstance(document1.getCtxMap().getMetadata())));
}
}

public void testPathWithBracketNotation() {
// Test basic bracket notation
IngestDocument document = RandomDocumentPicks.randomIngestDocument(random());

// Test bracket notation with single quotes
document.setFieldValue("foo", Map.of("dotted.field", "value1"));
assertThat(document.getFieldValue("foo['dotted.field']", String.class), equalTo("value1"));
assertThat(document.getFieldValue("foo.['dotted.field']", String.class), equalTo("value1"));

// Test bracket notation with double quotes
assertThat(document.getFieldValue("foo[\"dotted.field\"]", String.class), equalTo("value1"));

// Test multiple bracket notations mixed with dots
document.setFieldValue("foo", Map.of("nested.field", Map.of("bar", Map.of("another.field", "value2"))));
assertThat(document.getFieldValue("foo['nested.field'].bar[\"another.field\"]", String.class), equalTo("value2"));
}

public void testInvalidBracketNotation() {
IngestDocument document = RandomDocumentPicks.randomIngestDocument(random());
document.setFieldValue("foo", Map.of("dotted.field", "value"));

// Missing closing bracket
IllegalArgumentException e1 = expectThrows(
IllegalArgumentException.class,
() -> document.getFieldValue("foo['dotted.field", String.class)
);
assertThat(e1.getMessage(), containsString("path [foo['dotted.field] is not valid"));

// Missing quotes
document.setFieldValue("foo[dotted", Map.of("field]", "value"));

assertThat(document.getFieldValue("foo[dotted.field]", String.class), equalTo("value"));

// Mixed quotes
IllegalArgumentException e3 = expectThrows(
IllegalArgumentException.class,
() -> document.getFieldValue("foo['dotted.field\"]", String.class)
);
assertThat(e3.getMessage(), containsString("path [foo['dotted.field\"]] is not valid"));

// Empty brackets
IllegalArgumentException e4 = expectThrows(IllegalArgumentException.class, () -> document.getFieldValue("['']", String.class));
assertThat(e4.getMessage(), containsString("path [['']] is not valid"));
}
}
Loading