From 1f069ce1540078eab20e4528b15488f64c7b5354 Mon Sep 17 00:00:00 2001 From: Chris Parrinello Date: Fri, 24 Oct 2025 12:25:25 -0500 Subject: [PATCH 1/4] Checkpoint --- .../query/SearchExecutionContextTests.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java index 94282a4e570d5..ce6d5e6e22923 100644 --- a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java @@ -8,10 +8,12 @@ */ package org.elasticsearch.index.query; +import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.KeywordField; import org.apache.lucene.document.StringField; import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.memory.MemoryIndex; @@ -231,6 +233,8 @@ public void testFielddataLookupSometimesLoop() throws IOException { runtimeField("4", (leafLookup, docId) -> { if (docId == 0) { return "escape!"; + } else if (docId == 1) { + return "escape2!"; } return leafLookup.doc().get("4").get(0).toString(); }) @@ -776,10 +780,24 @@ private static List collect(String field, SearchExecutionContext searchE private static List collect(String field, SearchExecutionContext searchExecutionContext, Query query) throws IOException { List result = new ArrayList<>(); try (Directory directory = newDirectory(); RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory)) { - indexWriter.addDocument(List.of(new StringField("indexed_field", "first", Field.Store.NO))); - indexWriter.addDocument(List.of(new StringField("indexed_field", "second", Field.Store.NO))); + indexWriter.addDocument(List.of(new StringField("indexed_field", "first", Field.Store.YES))); + indexWriter.addDocument(List.of(new StringField("indexed_field", "second", Field.Store.YES))); try (DirectoryReader reader = indexWriter.getReader()) { IndexSearcher searcher = newSearcher(reader); + var indexReader = searcher.getIndexReader(); + var leaves = indexReader.leaves(); + for (var leaf : leaves) { + int max; + try (LeafReader leafReader = leaf.reader()) { + max = leafReader.maxDoc(); + Map documents = new HashMap<>(); + for (int i = 0; i < max; i++) { + documents.put(i, leafReader.storedFields().document(i, Set.of("indexed_field"))); + } + System.out.println(documents); + } + } + MappedFieldType fieldType = searchExecutionContext.getFieldType(field); IndexFieldData indexFieldData; if (randomBoolean()) { From 002714fb7618ca4a1dd3499cc408a856e5e6311c Mon Sep 17 00:00:00 2001 From: Chris Parrinello Date: Mon, 27 Oct 2025 08:50:32 -0500 Subject: [PATCH 2/4] investigation --- .../index/query/SearchExecutionContextTests.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java index ce6d5e6e22923..add0ddfb0babc 100644 --- a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java @@ -8,12 +8,10 @@ */ package org.elasticsearch.index.query; -import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.KeywordField; import org.apache.lucene.document.StringField; import org.apache.lucene.index.DirectoryReader; -import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; import org.apache.lucene.index.memory.MemoryIndex; @@ -784,20 +782,6 @@ private static List collect(String field, SearchExecutionContext searchE indexWriter.addDocument(List.of(new StringField("indexed_field", "second", Field.Store.YES))); try (DirectoryReader reader = indexWriter.getReader()) { IndexSearcher searcher = newSearcher(reader); - var indexReader = searcher.getIndexReader(); - var leaves = indexReader.leaves(); - for (var leaf : leaves) { - int max; - try (LeafReader leafReader = leaf.reader()) { - max = leafReader.maxDoc(); - Map documents = new HashMap<>(); - for (int i = 0; i < max; i++) { - documents.put(i, leafReader.storedFields().document(i, Set.of("indexed_field"))); - } - System.out.println(documents); - } - } - MappedFieldType fieldType = searchExecutionContext.getFieldType(field); IndexFieldData indexFieldData; if (randomBoolean()) { From a0de1048d7dcb59607568138ce33d5fca28abf59 Mon Sep 17 00:00:00 2001 From: Chris Parrinello Date: Tue, 4 Nov 2025 14:07:46 -0600 Subject: [PATCH 3/4] break the cycle on the first document --- .../query/SearchExecutionContextTests.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java index add0ddfb0babc..812b67d5d0c51 100644 --- a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java @@ -10,7 +10,6 @@ import org.apache.lucene.document.Field; import org.apache.lucene.document.KeywordField; -import org.apache.lucene.document.StringField; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.Term; @@ -223,20 +222,27 @@ public void testFielddataLookupTerminatesInLoop() { } public void testFielddataLookupSometimesLoop() throws IOException { - SearchExecutionContext searchExecutionContext = createSearchExecutionContext( - // simulate a runtime field cycle in the second doc: 1: doc['2'] 2: doc['3'] 3: doc['4'] 4: doc['4'] + // create this field so we can use it to make sure we're escaping the loop on only the "first" document + var concreteField = new KeywordFieldMapper.KeywordFieldType("indexed_field", true, true, Collections.emptyMap()); + + // simulate a runtime field cycle in the second doc: 1: doc['2'] 2: doc['3'] 3: doc['4'] 4: doc['4'] + var runtimeFields = List.of( runtimeField("1", leafLookup -> leafLookup.doc().get("2").get(0).toString()), runtimeField("2", leafLookup -> leafLookup.doc().get("3").get(0).toString()), runtimeField("3", leafLookup -> leafLookup.doc().get("4").get(0).toString()), runtimeField("4", (leafLookup, docId) -> { - if (docId == 0) { + if (leafLookup.doc().get("indexed_field").get(0).equals("first")) { return "escape!"; - } else if (docId == 1) { - return "escape2!"; } return leafLookup.doc().get("4").get(0).toString(); }) ); + SearchExecutionContext searchExecutionContext = createSearchExecutionContext( + "uuid", + null, + createMappingLookup(List.of(concreteField), runtimeFields), + Collections.emptyMap() + ); List values = collect("1", searchExecutionContext, new TermQuery(new Term("indexed_field", "first"))); assertEquals(List.of("escape!"), values); IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> collect("1", searchExecutionContext)); @@ -778,8 +784,8 @@ private static List collect(String field, SearchExecutionContext searchE private static List collect(String field, SearchExecutionContext searchExecutionContext, Query query) throws IOException { List result = new ArrayList<>(); try (Directory directory = newDirectory(); RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory)) { - indexWriter.addDocument(List.of(new StringField("indexed_field", "first", Field.Store.YES))); - indexWriter.addDocument(List.of(new StringField("indexed_field", "second", Field.Store.YES))); + indexWriter.addDocument(List.of(new KeywordField("indexed_field", "first", Field.Store.YES))); + indexWriter.addDocument(List.of(new KeywordField("indexed_field", "second", Field.Store.YES))); try (DirectoryReader reader = indexWriter.getReader()) { IndexSearcher searcher = newSearcher(reader); MappedFieldType fieldType = searchExecutionContext.getFieldType(field); From 8efb5f413c8805849789ad08082e58e259f9978a Mon Sep 17 00:00:00 2001 From: Chris Parrinello Date: Wed, 5 Nov 2025 16:10:48 -0600 Subject: [PATCH 4/4] fixes from comments --- .../index/query/SearchExecutionContextTests.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java index 812b67d5d0c51..5c027e8c9994f 100644 --- a/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/SearchExecutionContextTests.java @@ -230,11 +230,11 @@ public void testFielddataLookupSometimesLoop() throws IOException { runtimeField("1", leafLookup -> leafLookup.doc().get("2").get(0).toString()), runtimeField("2", leafLookup -> leafLookup.doc().get("3").get(0).toString()), runtimeField("3", leafLookup -> leafLookup.doc().get("4").get(0).toString()), - runtimeField("4", (leafLookup, docId) -> { - if (leafLookup.doc().get("indexed_field").get(0).equals("first")) { + runtimeField("4", leafLookup -> { + if (leafLookup.doc().get("indexed_field").getFirst().equals("first")) { return "escape!"; } - return leafLookup.doc().get("4").get(0).toString(); + return leafLookup.doc().get("4").getFirst().toString(); }) ); SearchExecutionContext searchExecutionContext = createSearchExecutionContext(