From 4d57882339fe30fbea2c426458dcbb8d7d4aadb1 Mon Sep 17 00:00:00 2001 From: ChrisHegarty Date: Tue, 23 Sep 2025 11:47:48 +0100 Subject: [PATCH 1/5] Optimize dotCount in expanding dot parser --- .../index/mapper/FieldTypeLookup.java | 7 +++--- .../index/mapper/FieldTypeLookupTests.java | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/FieldTypeLookup.java b/server/src/main/java/org/elasticsearch/index/mapper/FieldTypeLookup.java index c2f992eb6f664..b8d28e5b8fdbf 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/FieldTypeLookup.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/FieldTypeLookup.java @@ -153,10 +153,9 @@ final class FieldTypeLookup { public static int dotCount(String path) { int dotCount = 0; - for (int i = 0; i < path.length(); i++) { - if (path.charAt(i) == '.') { - dotCount++; - } + int index = -1; + while ((index = path.indexOf('.', index + 1)) != -1) { + dotCount++; } return dotCount; } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java b/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java index ae793bc3b329e..67576c8d23c6e 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java @@ -522,6 +522,31 @@ public void testNoRootAliasForPassThroughFieldOnConflictingField() { assertEquals(foo.fieldType(), lookup.get("foo")); } + public void testDotCount() { + assertEquals(0, FieldTypeLookup.dotCount("")); + assertEquals(1, FieldTypeLookup.dotCount(".")); + assertEquals(2, FieldTypeLookup.dotCount("..")); + assertEquals(3, FieldTypeLookup.dotCount("...")); + assertEquals(4, FieldTypeLookup.dotCount("....")); + assertEquals(0, FieldTypeLookup.dotCount("foo")); + assertEquals(1, FieldTypeLookup.dotCount("foo.bar")); + assertEquals(2, FieldTypeLookup.dotCount("foo.bar.baz")); + assertEquals(3, FieldTypeLookup.dotCount("foo.bar.baz.bob")); + assertEquals(4, FieldTypeLookup.dotCount("foo.bar.baz.bob.")); + assertEquals(4, FieldTypeLookup.dotCount("foo..bar.baz.bob")); + assertEquals(5, FieldTypeLookup.dotCount("foo..bar..baz.bob")); + assertEquals(6, FieldTypeLookup.dotCount("foo..bar..baz.bob.")); + + int times = atLeast(50); + for (int i = 0; i < times; i++) { + byte[] bytes = new byte[randomInt(1024)]; + random().nextBytes(bytes); + String s = new String(bytes); + int expected = s.chars().map(c -> c == '.' ? 1 : 0).sum(); + assertEquals(expected, FieldTypeLookup.dotCount(s)); + } + } + @SafeVarargs @SuppressWarnings("varargs") static List randomizedList(T... values) { From 3e32da8a3d10793a3ecf0321eb60ed724c678028 Mon Sep 17 00:00:00 2001 From: Chris Hegarty <62058229+ChrisHegarty@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:10:10 +0100 Subject: [PATCH 2/5] Update docs/changelog/135263.yaml --- docs/changelog/135263.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/changelog/135263.yaml diff --git a/docs/changelog/135263.yaml b/docs/changelog/135263.yaml new file mode 100644 index 0000000000000..554f1e258e515 --- /dev/null +++ b/docs/changelog/135263.yaml @@ -0,0 +1,5 @@ +pr: 135263 +summary: Optimize `dotCount` in expanding dot parser +area: "Mapping, Performance" +type: enhancement +issues: [] From 090cccbe90c03032bf9bd7d1af318eeba12beb93 Mon Sep 17 00:00:00 2001 From: Chris Hegarty <62058229+ChrisHegarty@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:31:30 +0100 Subject: [PATCH 3/5] Update 135263.yaml --- docs/changelog/135263.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog/135263.yaml b/docs/changelog/135263.yaml index 554f1e258e515..e67ee86f1a31c 100644 --- a/docs/changelog/135263.yaml +++ b/docs/changelog/135263.yaml @@ -1,5 +1,5 @@ pr: 135263 summary: Optimize `dotCount` in expanding dot parser -area: "Mapping, Performance" +area: "Mapping" type: enhancement issues: [] From 5115cb8acb46a05ddd46eeac45fd1ea3a18739e8 Mon Sep 17 00:00:00 2001 From: Chris Hegarty <62058229+ChrisHegarty@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:32:18 +0100 Subject: [PATCH 4/5] Update FieldTypeLookupTests.java --- .../org/elasticsearch/index/mapper/FieldTypeLookupTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java b/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java index 67576c8d23c6e..5c9f6542ff14c 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java @@ -541,7 +541,7 @@ public void testDotCount() { for (int i = 0; i < times; i++) { byte[] bytes = new byte[randomInt(1024)]; random().nextBytes(bytes); - String s = new String(bytes); + String s = new String(bytes, StandardCharsets.UTF_8); int expected = s.chars().map(c -> c == '.' ? 1 : 0).sum(); assertEquals(expected, FieldTypeLookup.dotCount(s)); } From fade6c1c8f91c9748bf46c0be892e10f0958530a Mon Sep 17 00:00:00 2001 From: Chris Hegarty <62058229+ChrisHegarty@users.noreply.github.com> Date: Tue, 23 Sep 2025 12:49:24 +0100 Subject: [PATCH 5/5] Update FieldTypeLookupTests.java --- .../org/elasticsearch/index/mapper/FieldTypeLookupTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java b/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java index 5c9f6542ff14c..eb1d2ef551f96 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/FieldTypeLookupTests.java @@ -14,6 +14,7 @@ import org.elasticsearch.test.ESTestCase; import org.hamcrest.Matchers; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection;