From 77033d98158bfdfbc8a1db95b69007eeb895f6b5 Mon Sep 17 00:00:00 2001 From: Martijn van Groningen Date: Thu, 13 Nov 2025 16:56:51 +0100 Subject: [PATCH] Address issue with DateFieldMapper#isFieldWithinQuery(...) If a date field has doc values skippers enabled, then it isn't guaranteed that every segment will actually have skippers. The logic was currently assuming that it did. Closes #138024 --- .../index/mapper/DateFieldMapper.java | 7 ++-- .../index/mapper/DateFieldTypeTests.java | 38 ++++++++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java index e3499ec5c8fed..6e97412cafcef 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java @@ -841,9 +841,10 @@ public Relation isFieldWithinQuery( } for (LeafReaderContext ctx : leaves) { DocValuesSkipper skipper = ctx.reader().getDocValuesSkipper(name()); - assert skipper != null : "no skipper for field:" + name() + " and reader:" + reader; - minValue = Long.min(minValue, skipper.minValue()); - maxValue = Long.max(maxValue, skipper.maxValue()); + if (skipper != null) { + minValue = Long.min(minValue, skipper.minValue()); + maxValue = Long.max(maxValue, skipper.maxValue()); + } } return isFieldWithinQuery(minValue, maxValue, from, to, includeLower, includeUpper, timeZone, dateParser, context, name()); } diff --git a/server/src/test/java/org/elasticsearch/index/mapper/DateFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/DateFieldTypeTests.java index a043c815c3a44..b1e9a5c131b61 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/DateFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/DateFieldTypeTests.java @@ -113,8 +113,44 @@ public void testIsFieldWithinQueryDateNanosDocValueSkipper() throws IOException isFieldWithinRangeTestCase(ft); } - public void isFieldWithinRangeTestCase(DateFieldType ft) throws IOException { + public void testIsFieldWithinQueryDocValueSkipperNotInAllSegments() throws IOException { + var ft = new DateFieldType( + "my_date", + IndexType.skippers(), + false, + DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER, + Resolution.NANOSECONDS, + null, + null, + Collections.emptyMap() + ); + try (Directory dir = newDirectory()) { + try (IndexWriter w = new IndexWriter(dir, new IndexWriterConfig(null))) { + // Simulates one segment have no my_date field + LuceneDocument doc = new LuceneDocument(); + doc.add(SortedNumericDocValuesField.indexedField("my_other_date", 123456789000L)); + w.addDocument(doc); + w.flush(); + + doc = new LuceneDocument(); + Field field = SortedNumericDocValuesField.indexedField("my_date", ft.parse("2015-10-12")); + doc.add(field); + w.addDocument(doc); + field.setLongValue(ft.parse("2016-04-03")); + w.addDocument(doc); + try (DirectoryReader reader = DirectoryReader.open(w)) { + DateMathParser alternateFormat = DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.toDateMathParser(); + doTestIsFieldWithinQuery(ft, reader, null, null); + doTestIsFieldWithinQuery(ft, reader, null, alternateFormat); + doTestIsFieldWithinQuery(ft, reader, ZoneOffset.UTC, null); + doTestIsFieldWithinQuery(ft, reader, ZoneOffset.UTC, alternateFormat); + } + } + } + } + + public void isFieldWithinRangeTestCase(DateFieldType ft) throws IOException { Directory dir = newDirectory(); IndexWriter w = new IndexWriter(dir, new IndexWriterConfig(null)); LuceneDocument doc = new LuceneDocument();