The range query skips that rewrite step: its createWeight hands the caller's source straight to getValues. A source that needs the searcher then either throws or computes its values without it.
- A
DoubleValuesSourcegives one number per document: a field's value, an expression, or a query's score (DoubleValuesSource.fromQuery). - Some sources need the searcher before they can produce values. Core's protocol is: call
source.rewrite(searcher), thengetValueson the result. A query-score source throws if you skip the first step. - Core's javadoc says Queries that use a
DoubleValuesSourceshould callrewrite()increateWeight, where they get the searcher.FunctionMatchQuerydoes. DoubleRange#getQuery(fastMatch, source), and itsLongRangetwin, return the query a range facet uses to filter or drill down.
createWeight skips it, the silent QueryValueSource variant, and a fix sketch. Select the still to open it at full size. Generated with AI, checked against the code.- Index one document whose text field
fis "a". Buildscore = DoubleValuesSource.fromQuery(new TermQuery(f:a)), a source whose value for each document is its score for that query (here 0.1308, BM25), and the range(0, +inf]. - Count
range.getQuery(null, score). You expect 1: the document scores above 0, andFunctionMatchQueryover the same source counts 1. - Instead the search throws
UnsupportedOperationException: This DoubleValuesSource must be rewritten, with assertions on or off. - Why: a query-score source works only after
rewrite(searcher). Core's javadoc says Queries should call it increateWeight, andFunctionMatchQuerydoes; the range query callsgetValueson the source exactly as it was passed in. - The
LongRangetwin (overscore.toLongValuesSource()) andIndexReaderFunctionssources fail the same way. A legacyQueryValueSourceview does not throw but ignores the searcher: on a ClassicSimilarity searcher the document scores 1.0, the view computes 0.1308, and the range[1.0, 1.0]matches 0 documents instead of 1.
Applications that filter or drill down with DoubleRange/LongRange#getQuery over a source that needs rewriting: query scores (fromQuery), IndexReaderFunctions statistics, or legacy ValueSource views. Field and expression-of-fields sources, the documented use, are unaffected. Public API, default settings; it fails on the first search. Workaround: pass source.rewrite(searcher). Rare.
Mechanism, terms and numbers668 words
DoubleRange#getQuery(Query, DoubleValuesSource) and LongRange#getQuery(Query, LongValuesSource) return a private ValueSourceQuery whose rewrite rewrites only the fast-match query and whose createWeight calls valueSource.getValues(context, null) and valueSource.isCacheable(ctx) on the source exactly as given (DoubleRange.java:156-164, :190, :210; LongRange.java:143-150, :177, :197 on main 645d4fe14a20). Nothing in either class calls valueSource.rewrite(searcher), although DoubleValuesSource says "Queries that use DoubleValuesSource objects should call rewrite() during Query#createWeight" (DoubleValuesSource.java:97-99) and FunctionMatchQuery does (FunctionMatchQuery.java:88). So DoubleValuesSource.fromQuery (and its toLongValuesSource() view) and IndexReaderFunctions sources throw "must be rewritten" on every search that reaches a segment's values, and a legacy QueryValueSource view silently scores with its own default-Similarity searcher. Introduced in 7.2.0 by LUCENE-7736, which added the rewrite rule and updated FunctionMatchQuery and FunctionScoreQuery but not these queries; it was executed on 10 releases from 7.2.0 to 10.6.0 and on main, the other release tags read the same, and 8.8.2-8.11.3 (not tagged in the history clone) are inferred. Field and expression-of-fields sources, the documented use, are unaffected, and source.rewrite(searcher) works around it. Intent is contested: the facet module documents that its Multi* wrappers never call rewrite, and the wrapped overload builds this same query, so the doc offers a javadoc fix as well as a code fix. A fix that rewrites once in createWeight passes the repro and the facet module's checks; it must land with the fix for LFV-770, or sortable-long sources regress.
- The query never rewrites its source.
getQuery(Query, DoubleValuesSource)returnsnew ValueSourceQuery(this, fastMatchQuery, valueSource)(DoubleRange.java:335-337). Itsrewriterewrites onlyfastMatchQuery(:156-164). ItscreateWeight(:166-213):
final DoubleValues values = valueSource.getValues(context, null); // :190, the source as given
...
public boolean isCacheable(LeafReaderContext ctx) {
return valueSource.isCacheable(ctx); // :210
}LongRange.java is the same (getQuery :322, rewrite :143-150, getValues :177, isCacheable :197).
- Core's rule. The class javadoc: "clients should call
rewrite(IndexSearcher)against the top-level searcher, and then callgetValueson the resulting DoubleValuesSource" (DoubleValuesSource.java:34-36;LongValuesSource.java:30-32). And onrewrite: "Queries that use DoubleValuesSource objects should call rewrite() duringQuery#createWeight(IndexSearcher, ScoreMode, float)rather than duringQuery#rewrite(IndexSearcher)to avoid IndexReader reference leakage" (:97-99).FunctionMatchQuery.java:88doesDoubleValuesSource vs = source.rewrite(searcher);increateWeight; so doFunctionScoreQuery.java:121and the sandboxCoveringQuery.java:172(for itsLongValuesSource), whileRescoreTopNQuery.java:68-69rewrites inQuery#rewrite, the place the rule says to avoid. The one other Query that holds a values source and skips the step, spatial-extras' privatePointVectorStrategy.DistanceRangeQuery(PointVectorStrategy.java:277), only ever gets the strategy's ownDistanceValueSource, whoserewritereturnsthis. The Query sentence is onDoubleValuesSource#rewriteonly:LongValuesSource#rewrite(LongValuesSource.java:64-70) lacks it, so theLongRangehalf rests on the class protocol and the parallel design. - Sources that throw.
fromQueryreturns a source whosegetValuesisthrow new UnsupportedOperationException("This DoubleValuesSource must be rewritten")(DoubleValuesSource.java:741,:768); itsrewritebuilds a searcher-bound source (:777-779). ItstoLongValuesSource()view delegates to it. The index-statistic sources ofIndexReaderFunctions, such asmaxDoc()andsumTotalTermFreq, throw "IndexReaderFunction must be rewritten before use" (IndexReaderFunctions.java:320,:99); its per-documenttermFreqdoes not. - The silent legacy path.
ValueSource#asDoubleValuesSource()returnsnew WrappedDoubleValuesSource(this, null)(ValueSource.java:184-186), so its values context holds a null searcher untilrewrite(searcher)makes a copy that holds one (:199-200,:244-246).QueryValueSourcewith a null searcher buildsnew IndexSearcher(...)over the top-level reader (QueryValueSource.java:114-125), with the default Similarity.
range.getQuery(null, DoubleValuesSource.fromQuery(f:a)), range(0, +inf]: throws "must be rewritten" atDoubleRange.java:190;FunctionMatchQueryandgetQuery(null, score.rewrite(searcher))count 1. The document's BM25 score is 0.1308.LongRange.getQuery(null, score.toLongValuesSource()): throws atLongRange.java:177.getQuery(null, IndexReaderFunctions.maxDoc()): "IndexReaderFunction must be rewritten before use".- ClassicSimilarity searcher,
new QueryValueSource(f:a, 0f).asDoubleValuesSource(), range[1.0, 1.0](the top Classic score): the unrewritten view computes 0.1308 (BM25), so the range query counts 0;FunctionMatchQueryand the rewritten view count 1. (The hunt's 5-document test: 0 instead of 3.) - Control:
DoubleValuesSource.fromLongField("n")counts 1; itsrewritereturns itself.
Exposure and likelihood315 words
- Who can hit it. Applications that build a range filter or drill-down with
DoubleRange#getQuery(Query, DoubleValuesSource)orLongRange#getQuery(Query, LongValuesSource)(both classes@lucene.experimental) over a source that needs rewriting:DoubleValuesSource.fromQueryor itstoLongValuesSource()view, anIndexReaderFunctionsstatistic, or a searcher-dependent legacyValueSourceexposed withasDoubleValuesSource(). - Not hit. Field sources and expressions over fields: the facet demo drills down with
range.getQuery(boundingBox, vs)over a haversine expression of two fields (DistanceFacetsExample.java:239-243). - What it takes. Public API, default codec,
IndexWriterConfigand searcher, one document. The silent variant also needs a non-default Similarity on the searcher. - Effect. Mostly a deterministic
UnsupportedOperationException, whose message names the missing step, on every search that reaches the values (DoubleRange.java:190): any segment, or with a fast-match query any segment where that query matches a document. The silent variant gives a wrong filter result. No corruption or hang was seen in the cases run. - How likely. Rare. An application that also counts such ranges must already pre-rewrite the source for the range counters, which throw on it too, and would often reuse that source in the drill-down. The recorded searches found no public report since 7.2.0 (2017); their gaps are under Prior reports.
- For searcher-bound sources the workaround binds the query to one searcher.
getQuery(fastMatch, source.rewrite(searcher))works. The result is "specialised for the given IndexSearcher" (DoubleValuesSource.java:92); for a source whose rewrite captures the searcher, such asfromQuery(its rewrite builds aWeight,:777-779), the query has to be rebuilt after a reopen; core's rule exists "to avoid IndexReader reference leakage". Field sources, whoserewritereturnsthis, have no such cost. - Out of scope: score-dependent sources. The query passes
nullscores togetValuestoday and with the fix (DoubleRange.java:190), soDoubleValuesSource.SCORESand similar sources ("callers must not pass null",DoubleValuesSource.java:350-354) are unsupported either way; neither the bug nor the fixes are about them.
One JUnit test method in lucene/facet, public API: index one document with f = "a", then count DoubleRange#getQuery(null, DoubleValuesSource.fromQuery(f:a)) for the range (0, +inf] with a plain IndexSearcher. Deterministic and single-threaded; the same with assertions on and off.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.lucene.facet.range;
import java.util.List;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.DoubleValuesSource;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.ByteBuffersDirectory;
import org.apache.lucene.store.Directory;
import org.apache.lucene.tests.util.LuceneTestCase;
public class TestDoubleRangeGetQueryRewritesSource extends LuceneTestCase {
public void testGetQueryOverQueryScoreSource() throws Exception {
try (Directory dir = new ByteBuffersDirectory()) {
try (IndexWriter w = new IndexWriter(dir, new IndexWriterConfig())) {
w.addDocument(List.of(new TextField("f", "a", Field.Store.NO)));
}
try (DirectoryReader reader = DirectoryReader.open(dir)) {
DoubleValuesSource score = DoubleValuesSource.fromQuery(new TermQuery(new Term("f", "a")));
DoubleRange range = new DoubleRange("score > 0", 0, false, Double.POSITIVE_INFINITY, true);
int count;
try {
count = new IndexSearcher(reader).count(range.getQuery(null, score));
} catch (UnsupportedOperationException e) {
// Expected count 1 (the doc scores > 0); actual: the unrewritten source throws
throw new AssertionError("expected count 1, got " + e, e);
}
assertEquals(1, count);
}
}
}
}
cp $REPRO/TestDoubleRangeGetQueryRewritesSource.java $LUCENE/lucene/facet/src/test/org/apache/lucene/facet/range/
cd $LUCENE && ./gradlew :lucene:facet:test --tests TestDoubleRangeGetQueryRewritesSource -Ptests.seed=DEADBEEF -Ptests.asserts=true
# also with -Ptests.asserts=false
- Expected
- Count 1: the one document scores above 0, so the range
(0, +inf]matches it (FunctionMatchQueryover the same source counts 1). - Observed
UnsupportedOperationException: This DoubleValuesSource must be rewritten, thrown fromDoubleRange.java:190on the first search.
More files, environment, full output255 words
The test catches the UnsupportedOperationException only to turn it into an assertion that states expected versus actual, with the exception as the cause. The body has one document, no threads and no random calls (ByteBuffersDirectory, default IndexWriterConfig, new IndexSearcher(reader)). The seed still drives the test framework's per-run settings; the result was the same in every recorded run (seeds DEADBEEF and 5EED1234, gradle and the standalone runner). The file carries the Apache license header; with the fix applied, :lucene:facet:check passes with it included unchanged, so it can go into a PR as is.
Left out on purpose: the LongRange view, IndexReaderFunctions, the silent QueryValueSource variant and the FunctionMatchQuery comparison; they are in the explanation above.
| lucene | main 645d4fe14a20 (11.0.0-SNAPSHOT); also the 10.6.0 release jars |
|---|---|
| jdk | OpenJDK 25.0.3 (build 25.0.3+9-LTS) |
| os | Linux, aarch64 (the only platform run; the code path is pure Java) |
cp $REPRO/TestDoubleRangeGetQueryRewritesSource.java $LUCENE/lucene/facet/src/test/org/apache/lucene/facet/range/
cd $LUCENE && ./gradlew :lucene:facet:test --tests TestDoubleRangeGetQueryRewritesSource -Ptests.seed=DEADBEEF -Ptests.asserts=true
# also with -Ptests.asserts=false
TestDoubleRangeGetQueryRewritesSource > testGetQueryOverQueryScoreSource FAILED
java.lang.AssertionError: expected count 1, got java.lang.UnsupportedOperationException: This DoubleValuesSource must be rewritten
at __randomizedtesting.SeedInfo.seed([DEADBEEF:31099228EEA9893F]:0)
at org.apache.lucene.facet.range.TestDoubleRangeGetQueryRewritesSource.testGetQueryOverQueryScoreSource(TestDoubleRangeGetQueryRewritesSource.java:48)
Caused by:
java.lang.UnsupportedOperationException: This DoubleValuesSource must be rewritten
at org.apache.lucene.search.DoubleValuesSource$QueryDoubleValuesSource.getValues(DoubleValuesSource.java:768)
at org.apache.lucene.facet.range.DoubleRange$ValueSourceQuery$1.scorerSupplier(DoubleRange.java:190)
...
at org.apache.lucene.search.IndexSearcher.count(IndexSearcher.java:528)
:lucene:facet:test (FAILURE): 1 test, 1 failure
# the same with -Ptests.asserts=false; the same on the 10.6.0 release jars (assertions on and off)
# with the fix: :lucene:facet:test (SUCCESS): 1 test (assertions on and off)
# abridged: gradle prints the core frames with an org.apache.lucene.core@11.0.0-SNAPSHOT/ module prefix, and some frames are left out (...)- Core says Queries using a
DoubleValuesSource"should call rewrite() during Query#createWeight" (DoubleValuesSource.java:97-99); this query has the searcher there and does not. - The
getQueryjavadoc limits no source; the other Queries taking a caller's source rewrite it (FunctionMatchQuery,FunctionScoreQuery,CoveringQuery,RescoreTopNQuery). - Contested: the
Multi*wrappers document that rewrite is never called, and build this same query. Adjudication: a defect, medium confidence.
The full argument341 words
This is a conflict between two written contracts: core's rule for Queries and the facet module's documented no-rewrite design for its Multi* wrappers, which the wrapped getQuery overload shares at run time. The adjudication rated it a defect (medium confidence), the devil's-advocate verifier called intent "uncertain", and a cross-model fact check of this doc rated the case for "intended" strong, though not decisive.
- Contract.
DoubleValuesSource.java:97-99(above); the client protocol at:34-36andLongValuesSource.java:30-32.ValueSourceQueryis an ordinary Query that receives theIndexSearcherincreateWeight. The Query sentence is onDoubleValuesSource#rewriteonly; theLongRangehalf rests on theLongValuesSourceclass protocol and the parallel design (the sandboxCoveringQueryrewrites itsLongValuesSourceincreateWeight,CoveringQuery.java:172). - The
getQueryjavadoc (DoubleRange.java:323-334,LongRange.java:310-321): "Create a Query that matches documents in this range ... If the value source is static, eg an indexed numeric field, it may be faster to usePointRangeQuery". No restriction on the source; non-static sources are implied. - History. The
getValues(context, null)line is from LUCENE-7610 (master713b65d1dcc, branch_6xa238610bab1, both committed 2017-01-07; first release 6.4.0, from the branch_6x commit), before any rewrite step existed. LUCENE-7736 (#8787;03afeb7766aon branch_7x,2a4dd499bbdon master, committed 2017-11-15) addedrewrite()and the rule, added the call toFunctionMatchQueryandFunctionScoreQuery, and in the facet module changed only a test source (rewrite() { return this; }). In its review Adrien Grand wrote "I think you forgot to update FunctionMatchQuery to make it rewrite the values source?", and Alan Woodward answered "I did, thanks for picking it up";CoveringQuerywas fixed in a follow-up commit (3f0b240853d). The facet range queries are not mentioned. - Other Queries. Every other class in Lucene that extends
Queryand takes a caller-suppliedDoubleValuesSourceorLongValuesSourcerewrites it:FunctionMatchQuery.java:88,FunctionScoreQuery.java:121andCoveringQuery.java:172increateWeight,RescoreTopNQuery.java:68-69inQuery#rewrite. The only other one that skips the step, spatial-extras' privatePointVectorStrategy.DistanceRangeQuery, only ever gets its ownDistanceValueSource, whoserewritereturnsthis(PointVectorStrategy.java:197-198,:277;DistanceValueSource.java:96-99).
The devil's-advocate check322 words
The strongest case for "intended" (built by the devil's-advocate verifier and strengthened by the cross-model fact check): the facet module documents a no-rewrite design. MultiDoubleValuesSource.java:41-47 says "DoubleValuesSource#rewrite(IndexSearcher) will also never be called. The user should be aware of this if using a DoubleValuesSource that relies on rewriting or scores. The faceting use-cases don't call rewrite or provide scores, which is why this simplification was made." (MultiLongValuesSource.java:43-49 likewise.) In PR #543 (LUCENE-10245) Alan Woodward wrote "I don't think we need needsScores() or rewrite() for facets", and Greg Miller kept only isCacheable "for the query implementations in LongRange and DoubleRange", so that discussion had the range queries in view. The LUCENE-10245 CHANGES entry says "DoubleRange and LongRange also support creating queries from these multi-valued sources" (lucene/CHANGES.txt:4438-4442). The direct overload builds a query equal to the documented fromSingleValued path's, so the two cannot be told apart at run time, and the code fix changes behaviour on that documented route too. The range counters do not rewrite either, the upstream test picks either overload at random (TestRangeFacetCounts.java:1703-1709), and a caller-side rewrite works.
Why the adjudication and the devil's-advocate verifier still read the direct overloads as a defect: the caveat sits on the fromSingleValued wrappers, not on getQuery(Query, DoubleValuesSource), whose javadoc states no restriction; the PR #543 exchange decided which methods the new Multi* classes have (they have no rewrite()), not that this Query may skip DoubleValuesSource#rewrite; the counters have no searcher, while this Query does, and core's rule is written for Queries; and in LUCENE-7736 Alan Woodward wrote "the only callers of rewrite are internal lucene classes" (while discussing equals() across readers), which suggests users were not expected to pre-rewrite. Verdict: a defect (adjudication, medium confidence), with intent contested: the devil's-advocate verifier called the case "not decisive", and the cross-model fact check rated it strong and would file this as a neutral design or documentation question.
Recommended Rewrite once in createWeight, as FunctionMatchQuery does
If the maintainers want a behaviour change: rewrite the source once at the start of ValueSourceQuery.createWeight, use the result for getValues and isCacheable in both classes, as FunctionMatchQuery does, and update the Multi*ValuesSource note. The repro and :lucene:facet:check pass. Land it with LFV-770's fix. Otherwise, document that the source must be pre-rewritten.
public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost)
throws IOException {
+ final DoubleValuesSource rewrittenSource = valueSource.rewrite(searcher);
...
- final DoubleValues values = valueSource.getValues(context, null);
+ final DoubleValues values = rewrittenSource.getValues(context, null);
...
public boolean isCacheable(LeafReaderContext ctx) {
- return valueSource.isCacheable(ctx);
+ return rewrittenSource.isCacheable(ctx);
}All options and trade-offs2 options · 635 words
One option was built and run in a scratch worktree of 645d4fe14a20; the other is not built. Which one fits depends on which contract the maintainers want the direct overloads to follow (see Why it is a bug); a maintainer could reasonably choose either, and the code fix is not the only reasonable answer.
The finder's code fix plus a javadoc update (4 files, +19/-10). Its two-line code comment was corrected on 2026-10-30: it now credits the Query sentence to DoubleValuesSource#rewrite only, and in LongRange cites the LongValuesSource class protocol. In DoubleRange.ValueSourceQuery.createWeight (and the same in LongRange with LongValuesSource), rewrite first and use the rewritten source for getValues and isCacheable. In MultiDoubleValuesSource / MultiLongValuesSource, "will also never be called" becomes "will also never be called when counting facets (the range queries from DoubleRange#getQuery do rewrite an unwrapped single-valued source)".
public Weight createWeight(IndexSearcher searcher, ScoreMode scoreMode, float boost)
throws IOException {
+ final DoubleValuesSource rewrittenSource = valueSource.rewrite(searcher);
...
- final DoubleValues values = valueSource.getValues(context, null);
+ final DoubleValues values = rewrittenSource.getValues(context, null);
...
public boolean isCacheable(LeafReaderContext ctx) {
- return valueSource.isCacheable(ctx);
+ return rewrittenSource.isCacheable(ctx);
}Trade-offs
- Must land with LFV-770.
toSortableLongDoubleValuesSource().rewrite()returns the plain cast adapter (DoubleValuesSource.java:193-195), which today never matters here. Probe: one document with value 2.5,LongRangeover the sortable longs of 2.0 and 3.0, sourcefromDoubleField("v").toSortableLongDoubleValuesSource(): count 1 on main, 0 with this fix alone, 1 with LFV-770's one-line fix added (return inner.rewrite(searcher).toSortableLongDoubleValuesSource();). getQuery(Query, Multi*ValuesSource)unwrapsfromSingleValuedinto the same query, so the fix also changes behaviour on that documented route: it starts rewriting there, against theMulti*note as written today; hence the javadoc update (or keep the two paths apart).- One
rewritepercreateWeight, the same costFunctionMatchQuerypays. A source the caller already rewrote is rewritten again: forfromQuery's rewritten form that returns the same object (WeightDoubleValuesSource.rewritereturnsthis), a legacyWrappedDoubleValuesSourcemakes a new wrapper (ValueSource.java:244-246), and core says implementations "should assume that this will only be called once" (DoubleValuesSource.java:94), so other pre-rewritten sources are not covered;FunctionMatchQuerybehaves the same. No benchmark was run. - Touches the
isCacheableline that LFV-320 (the fast-match query's cacheability is ignored) also changes; coordinate the two. - Score-dependent sources stay unsupported: the fixed query still calls
getValues(context, null).
What the checks validated
- Scratch worktree of
645d4fe14a20, gradle, JDK 25: stock + test fails with assertions on and off; + fix: the test passes with assertions on and off. - + fix:
:lucene:facet:test --tests 'org.apache.lucene.facet.range.*'passes, 37 tests (TestRangeFacetCounts22,TestDynamicRangeUtil14, the repro 1); + fix and the test::lucene:facet:checkBUILD SUCCESSFUL (license, format, ecj lint and forbidden-API checks;:lucene:facet:test307 tests, 7 skipped);:lucene:facet:renderJavadocpasses with no warnings. - Earlier, code part shadowed onto the main jars: the finder's 3 tests and the independent reproduction's 7 pass; upstream
TestRangeFacetCounts22 of 22. - With LFV-770's fix added (shadowed): the coupling probe and the minimal test pass.
- After the comment fix (2026-10-30), the new diff in a fresh scratch worktree:
:lucene:facet:checkpasses again (307 tests, 7 skipped; format, ecj and forbidden-API checks) and the repro passes with assertions off; diff stats unchanged. - Not run: the full Lucene suite, nightly tests, the sandbox module, benchmarks.
Add to both getQuery(Query, DoubleValuesSource / LongValuesSource) javadocs that a source which needs rewriting must be passed as source.rewrite(searcher).
Trade-offs
No behaviour change, it matches the Multi* note as written, and it has no dependency on LFV-770; but these stay the only Queries that take a caller-supplied values source and skip core's rule, the query is tied to one searcher for searcher-bound sources, and users must know about the silent QueryValueSource case themselves.
Downstream relevance is limited to products that build these range queries over score or index-statistic sources: they get a clear per-query exception, or, with a legacy QueryValueSource view and a custom Similarity, a wrong filter result over their own index.
An independent reviewer from another model family (OpenAI GPT-5.6), asked what the hunt unit's facet test harnesses could not see, named this defect: the range query never rewrites its source (DoubleRange.java:190 and the LongRange twin), with a one-document input that should count 1. The finder confirmed it by execution and found the silent QueryValueSource variant.
The method in full172 words
Method: a read-only cross-model critique, confirmed by execution (non-formal), a hunt unit (facet residual algorithms). The unit's bounded-exhaustive harnesses checked range drill-downs against counting, but only through the Multi* overloads with from*Field sources. Asked to find a concrete defect that those harnesses could not see, a reviewer from another model family (OpenAI GPT-5.6, reading only, running nothing) reported one finding at high confidence: the DoubleRange drill-down query never rewrites a rewrite-dependent DoubleValuesSource (DoubleRange.java:156-163, :190), with a one-document input (DoubleValuesSource.fromQuery(new MatchAllDocsQuery()), range [0, 2]), expected count 1 and a derived actual of "This DoubleValuesSource must be rewritten", plus the LongRange twin (LongRange.java:143-150, :177). The harness gap was its explanation of why the harnesses missed it. The finder read ValueSourceQuery, confirmed the defect with a public-API JUnit on the stock main jars (2026-10-27), and added the silent QueryValueSource variant through ValueSource#asDoubleValuesSource() and QueryValueSource. The independent reproduction added IndexReaderFunctions and the fast-match case; this doc's test is a one-method form of the finder's first test.
The recorded searches (2026-10-27) found no prior report: over 200 queries over GitHub issues, PRs and commits, downstream projects, four mailing lists, the JIRA archive and the web, plus scans of all 408 open PRs and the full history. Related: #8787 (LUCENE-7736) added the rule; #543 (LUCENE-10245) the Multi* no-rewrite note.
Searches3 searches
Related, not reports of this bug: #8787 / LUCENE-7736 (added rewrite() and the Query rule; facets not mentioned; FunctionMatchQuery caught in review, CoveringQuery in a follow-up commit); #9046 / LUCENE-7998 (added DoubleValuesSource.fromQuery); #543 / LUCENE-10245 (the Multi* no-rewrite design); #8661 / LUCENE-7610 (introduced the direct overloads); #13375 / #13383 and open PR #16847 (the same classes, unrelated changes).
Coverage gaps: StackOverflow pages could not be fetched (their titles are generic facet questions); private security@ reports are not visible.
| Where | When | How | Found |
|---|---|---|---|
| GitHub (apache/lucene issues, PRs, commits; lucene-solr, Solr, Elasticsearch, OpenSearch) | 2026-10-27 | scripted prior-report search 1 (77 queries incl. lists, JIRA and downstream; 3,403 distinct hits, 0 high, 27 medium, all triaged), 62 own GitHub searches, the finder's 51 queries and 13 direct searches | no report; #8787, #9046, #543, #8661, #13375, #13383 are related |
| Mailing lists and JIRA archive | 2026-10-27 | scripted prior-report search 2 (64 queries over dev@, java-user@, issues@, commits@ and JIRA; 0 high, 12 medium) | no report |
| Open and past PRs, commits, history | 2026-10-27 | changed files of all 408 open PRs and up to 265 facet and values-source PRs; commits by path on main, branch_10x, branch_10_5, branch_9x; the full git history; CHANGES.txt; 9 web queries | only #16847 touches the files (mechanical change); no commit ever added a values-source rewrite to ValueSourceQuery |
Introduced in 7.2.0 by LUCENE-7736 (03afeb7766a, 2017-11-15), which added rewrite() and the rule for Queries but did not update these queries. 6.5.0 to 7.1.0 behave consistently; every executed release from 7.2.0 to 10.6.0, and main, fails.
Versions tested5 rows
LUCENE-7736 "Expose some IndexReader stats via DoubleValuesSources" (Alan Woodward, reviewed by Adrien Grand; JIRA patch, no GitHub PR; issue #8787): 03afeb7766a on branch_7x (first release 7.2.0) and 2a4dd499bbd on master (first release 8.0.0), committed 2017-11-15. DoubleValuesSource.fromQuery came the next day with LUCENE-7998 (c6171019d5f), also in 7.2.0. The getValues(context, null) line is from LUCENE-7610 (master 713b65d1dcc, the line's origin in git blame, first in 7.0.0; branch_6x backport a238610bab1, first in 6.4.0; both committed 2017-01-07). Bisection is at release granularity plus the commit diff; no build at the commit's parent. Releases between the executed ones were scanned statically (no release ever rewrites the source in these classes); 8.8.2-8.11.3 are inferred. All runs used JDK 25, not each release's own JDK. On 7.2.0-7.7.1 and 8.0.0 a QueryValueSource view rewritten earlier by another consumer can hide the silent variant (fixed by LUCENE-8726); the throwing triggers are not affected.
| Version or commit | Verdict | Result |
|---|---|---|
main 645d4fe14a20 | affected | the minimal test fails through gradle, assertions on and off |
| 10.6.0 (release jars) | affected | the minimal test fails, assertions on and off |
7.2.0, 7.2.1, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2, main a9779ef3c193 | affected | 5-check probe: all 5 triggers fail, both controls pass (assertions on and off on 7.2.0, 10.5.2 and main) |
| 6.5.0, 6.6.6, 7.0.0, 7.1.0 | before the rewrite API | the facet query and FunctionMatchQuery agree; neither sees the searcher, and no rewrite API exists |
with the fix (main 645d4fe14a20) | not affected | the minimal test passes; the facet.range tests (37) and :lucene:facet:check (307 tests) pass |
The independent reproduction (real), the adjudication (confirmed, medium) and the root-cause and intended-lens cross-model reviews (real, reading only) agree; the devil's advocate called intent "uncertain"; a cross-model fact check of this doc rated the case for "intended" strong, not decisive; the refute-lens review gave a procedural "not real".
Checks and verdicts469 words
The reviewers from another model family (OpenAI GPT-5.6) could not execute code; the executed evidence comes from the other checks, each of which re-ran a repro.
| Check | Verdict | What it found |
|---|---|---|
| lead critique (cross-model, reading only) | one finding, high confidence | Named the defect (DoubleRange.java:156-163, :190, the LongRange twin) with a one-document fromQuery input and a derived "must be rewritten"; it ran nothing. |
| finder (a hunt unit) | candidate | JUnit with 3 tests fails 3 of 3 on main -ea and -da, 10.5.2 and 9.12.3; passes with the fix; 22 of 22 TestRangeFacetCounts pass with the fix. |
| cross-model review, intended lens | real, medium (reading only) | Intended argument "moderate": the facet note covers the Multi* wrappers, not the direct overloads; a separate run re-ran the JUnit (3 of 3 fail). |
| cross-model review, refute lens | not real, low, procedural | Could not run code; agreed on the root cause and that the inputs are in contract; a separate run re-ran the JUnit (3 of 3 fail). |
| Independent reproducer | real | Own JUnit (7 tests, 2 controls): 5 of 7 fail on main -ea/-da, 10.5.2 and 9.12.3; added IndexReaderFunctions.maxDoc(); 7 of 7 pass with the fix. |
| Cross-model review, root-cause lens | real, medium (reading only) | Root cause agreed; separate runs: 3 of 3 fail on main -ea/-da, 3 of 3 pass with the fix. |
| Devil's advocate | uncertain, medium | Built the Multi* design case and judged it not decisive; design probe: the two overloads build equal queries, the counters also throw, the workaround agrees everywhere. |
| adjudication | confirmed, medium | Re-ran the independent reproduction's test (seed 5EED1A2B, 5 of 7 fail, -ea/-da), the finder's (3 of 3) and the independent reproduction's with the fix (7 of 7 pass); class crash, low priority. |
| Follow-up, audit, repro minimization | keep | History over 17 releases and main, prior-report search, security screen; re-runs with new seeds; the one-method test verified on 645d4fe14a20. |
| fact check of this doc (2026-10-30) | real as described; 4 wording errors, fixed | Re-ran the gradle command (assertions on and off), the standalone runner on main and 10.6.0, fix A with :lucene:facet:check, and its own probe confirming every executed number; the errors (commit/release pairing, unchanged-files claim, "every other Query consumer", how it was found) are fixed. |
| cross-model fact check of this doc (2026-10-30) | behaviour real; intended case strong (reading only) | 2 errors, 6 overclaims and 4 missing caveats, all addressed; it judged the bug noise under the hunt's no-noise rule and suggests a neutral design or documentation question, which is how this version frames it. |
| diagram check (2026-10-30) | pass | Re-ran the diagram probe and the minimal test; every on-screen value, line and quote matches the code at 645d4fe14a20. |
The diagram as a still image, generated with AI and checked against the code. It is under 10 MB, the limit for a GitHub attachment.
- PNG 532 KB
Finding record, Lucene and upstream sources, repro files and diagram notes1,642 words
- Registry title
- DoubleRange#getQuery(Query, DoubleValuesSource) and LongRange#getQuery(Query, LongValuesSource) never call rewrite(searcher) on the values source, so a source that needs rewriting (DoubleValuesSource.fromQuery, IndexReaderFunctions) throws 'must be rewritten', and a legacy QueryValueSource view silently ignores the searcher's Similarity
- Area
- facet / range drill-down and filter queries (DoubleRange/LongRange.ValueSourceQuery)
- Priority
- Low, rank 624: The experimental DoubleRange/LongRange#getQuery fails loudly only for values sources that need rewriting (not the documented field or expression sources), and passing source.rewrite(searcher) works around it.
- Impact class
- crash
- Impact note
- Applications that filter or drill down with the experimental DoubleRange#getQuery(Query, DoubleValuesSource) or LongRange#getQuery(Query, LongValuesSource) over a values source that needs rewriting (DoubleValuesSource.fromQuery or its toLongValuesSource() view, an IndexReaderFunctions statistic, or a searcher-dependent legacy ValueSource exposed with asDoubleValuesSource()) and do not call rewrite(searcher) themselves get a deterministic UnsupportedOperationException ('This DoubleValuesSource must be rewritten' or 'IndexReaderFunction must be rewritten before use') from every search with the query, with default index and searcher settings and at any index size; in the narrower case of a legacy QueryValueSource view on a searcher with a non-default Similarity the range is checked against default-Similarity scores and silently matches the wrong documents (0 instead of 3 in the repro); field and expression-of-fields sources, the documented use, are unaffected, passing source.rewrite(searcher) works around it, and every release from 7.2.0 to 10.6.0 has it (10.6.0 executed on the release jars).
- Summary
- You build a range filter with DoubleRange#getQuery(null, DoubleValuesSource.fromQuery(new TermQuery(...))) (or LongRange#getQuery with the source's toLongValuesSource() view) and run it on an IndexSearcher, and expect it to match the documents whose query score falls in the range, as FunctionMatchQuery does with the same source, because core says Queries that use a DoubleValuesSource call rewrite() in createWeight. Instead the search throws UnsupportedOperationException 'This DoubleValuesSource must be rewritten': the range query hands the source to getValues without ever rewriting it against the searcher. With a legacy QueryValueSource view on a searcher that uses ClassicSimilarity the same omission is silent: the source scores with a fresh default-Similarity searcher, and the range [top score, top score] matches 0 documents where FunctionMatchQuery matches 3.
- Introduced
- 03afeb7766a39996de3c85e8a6ab24d2a352dd1c on branch_7x (first released in 7.2.0); master equivalent 2a4dd499bbd2f5ed1f481e17eeaee4f32b927185 (first released in 8.0.0). LUCENE-7736 'Expose some IndexReader stats via DoubleValuesSources' (apache/lucene#8787; JIRA patch, no GitHub PR; author romseygeek, reviewed by jpountz) added DoubleValuesSource/LongValuesSource#rewrite(IndexSearcher) with the rule that Queries call rewrite() in createWeight, updated FunctionMatchQuery and FunctionScoreQuery, and left the facet DoubleRange/LongRange ValueSourceQuery unchanged [read; bisected at release granularity by execution, no build at the commit's parent]. The no-rewrite line valueSource.getValues(context, null) comes from LUCENE-7610 (713b65d1dcc on master, a238610bab1 on branch_6x, first in 6.4.0), written before any rewrite step existed; DoubleValuesSource.fromQuery, the main throwing trigger, came the next day with LUCENE-7998 (c6171019d5f on branch_7x, 423677f20e6 on master), in the same 7.2.0 release. (2017-11-15 (LUCENE-7736 committed on branch_7x and master; author date 2017-03-28); LUCENE-7998 committed 2017-11-16; the getValues line from LUCENE-7610, committed 2017-01-07)
- First affected version
- 7.2.0 [exec, -ea and -da]: the 5-check probe fails 5 of 5 with its controls passing, and the no-rewrite probe gives [] where FunctionMatchQuery gives [0, 1, 4]; 7.1.0 is the last unaffected release (no rewrite API: the 5-check probe does not compile, and the no-rewrite probe passes on 6.5.0, 6.6.6, 7.0.0 and 7.1.0 [exec], where the facet query and FunctionMatchQuery both ignore the searcher); the direct overloads exist since 6.4.0.
- Affected versions
- every release from 7.2.0 to 10.5.2 (71 releases: 7.2.0-7.7.3, 8.0.0-8.11.4, 9.0.0-9.12.3, 10.0.0-10.5.2), 10.6.0 [exec: the doc's repro on the release jars, -ea and -da] and main a9779ef3c193 (unreleased 11.0); branch_10_6 and branch_10x [read]; upstream main f7bcc0abd816 (2026-10-27) has the same code; never fixed upstream. [exec] the follow-up's 5-check probe fails on 7.2.0, 7.2.1, 7.7.3, 8.0.0, 8.11.4, 9.0.0, 9.12.3, 10.0.0, 10.5.2 and main (-ea and -da on 7.2.0, 10.5.2 and main), the finder's JUnit 3 of 3 and the independent reproduction's JUnit 5 of 7 on 9.12.3, 10.5.2 and main; [read] a static scan of every other 6.x-10.x release tag in the history clone (no release ever calls valueSource.rewrite in these classes); 8.8.2-8.11.3 are not tagged in the clone and are inferred from 8.8.1 (scan) and 8.11.4 (exec). On 7.2.0-7.7.1 and 8.0.0 (before LUCENE-8726) a QueryValueSource view already rewritten by another consumer carries the searcher into the facet query and masks the silent variant; fresh instances show it there too, and the throwing triggers are not affected.
- Status
- documented (brief, checks and a per-finding doc exist)
- Verification
- Confirmed by AI-run checks: an independent repro, a cross-model review that could only read the code (its low-confidence “not real” is procedural), an intended-behaviour check, a prior-report search and a skeptical audit; not yet triaged by a person.
- Found by
- non-formal: code reading
- Upstream and prior reports
- none found (2026-10-27, the prior-report record, read-only): scripted prior-report search 1 (77 planned queries: 32 GitHub issue/PR, 5 commit, 4 downstream-repository, 24 mailing-list, 6 JIRA; 3403 distinct hits, 0 high, 27 medium, all triaged), run 2 (64 queries over dev@, java-user@, issues@, commits@ and JIRA; 0 high, 12 medium), 62 own GitHub searches over apache/lucene, apache/lucene-solr and the Elasticsearch, OpenSearch and Solr repositories (25 non-empty, all triaged), the changed files of all 408 open PRs (only #16847 touches DoubleRange.java/LongRange.java, mechanically: maxDoc to context.maxLeafDoc()), the files of up to 265 facet and values-source PRs, commits by path on main, branch_10x, branch_10_5 and branch_9x, the full local history (no commit ever added valueSource.rewrite to ValueSourceQuery), 9 web queries and main CHANGES.txt; the finder's earlier run (51 scripted prior-report search queries, 13 gh queries) found nothing either. Design context, not reports: #543 (LUCENE-10245, merged: the facet Multi*ValuesSource wrappers need no rewrite(), now the documented fromSingleValued caveat, a path this row excludes), #8787 (LUCENE-7736: added rewrite; FunctionMatchQuery was fixed during review and CoveringQuery in follow-up commit 3f0b240, facets not mentioned), #9046 (LUCENE-7998: fromQuery and the Query rewrite javadoc), #8661 (LUCENE-7610: the direct overloads); #13375/#13383 touch the same classes for an unrelated FieldExistsQuery shortcut. Gap: StackOverflow pages could not be fetched; their titles are generic facet questions.
- Lucene commit tested
- main
645d4fe14a20(commit of 2026-10-28): the repro test through gradle in a scratch worktree, assertions on and off, stock and with the fix, plus thefacet.rangetests and:lucene:facet:checkwith the fix; the 10.6.0 release jars through the standalone runner, assertions on and off; a coupling probe stock, with the fix, and with the fix plus LFV-770's fix. After the 2026-10-30 checks the fix's code comment was corrected and the new diff re-run::lucene:facet:checkand the repro with assertions off pass. Upstream main716d6f216f52(2026-10-29) and branch_11x have the code-path files unchanged. The hunt, the verifiers, the adjudication and the follow-up used maina9779ef3c193, where every file on the bug's code path is identical;RescoreTopNQuery.java, cited only as an example of a rewriting Query, changed in #16926 but not at the cited lines.
- Finding record
lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java:156-164 (at a9779ef3c193) (ValueSourceQuery.rewrite rewrites only fastMatchQuery), :166-213 (createWeight; valueSource.getValues(context, null) at :190, valueSource.isCacheable(ctx) at :209-210), :323-336 (getQuery(Query, DoubleValuesSource) javadoc and overload: no restriction on the source; 'If the value source is static ... PointRangeQuery'), :339-358 (getQuery(Query, MultiDoubleValuesSource) unwraps fromSingleValued into the same ValueSourceQuery)lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java:143-150 (at a9779ef3c193) (rewrite: fast match only), :153-200 (createWeight; getValues at :177, isCacheable at :196-197), :322 (getQuery(Query, LongValuesSource)), :338 (getQuery(Query, MultiLongValuesSource)); DoubleRange.java and LongRange.java are byte-identical at a Lucene main checkout ea57360912edlucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java:33-35 (at a9779ef3c193) (client protocol: rewrite against the top-level searcher, then getValues), :97-99 ('Queries that use DoubleValuesSource objects should call rewrite() during Query#createWeight'), :768 (QueryDoubleValuesSource.getValues throws 'This DoubleValuesSource must be rewritten'); LongValuesSource.java:30-32 (client protocol)lucene/queries/src/java/org/apache/lucene/queries/function/FunctionMatchQuery.java:88 (at a9779ef3c193) (DoubleValuesSource vs = source.rewrite(searcher) in createWeight: the same pattern done right)lucene/queries/src/java/org/apache/lucene/queries/function/ValueSource.java:184-205 (at a9779ef3c193) (asDoubleValuesSource() -> WrappedDoubleValuesSource(this, null), newContext(searcher)) and valuesource/QueryValueSource.java:114-125 (null context searcher -> new IndexSearcher over the top-level reader, default Similarity)lucene/facet/src/java/org/apache/lucene/facet/MultiDoubleValuesSource.java:41-47 (at a9779ef3c193) and MultiLongValuesSource.java:43-49 (documented: rewrite 'will also never be called' for fromSingleValued wrappers; 'The faceting use-cases don't call rewrite or provide scores')lucene/demo/src/java/org/apache/lucene/demo/facet/DistanceFacetsExample.java:243 (at a9779ef3c193) (documented use: range.getQuery over an expression-of-fields source, which needs no rewrite); DoubleRange.java:42 and LongRange.java:41 (@lucene.experimental)
- The finding in 30 seconds
a Lucene main checkout (645d4fe14a20) lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java:156-164, :166-213 (:190, :209-210), :323-337a Lucene main checkout (645d4fe14a20) lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java:143-150, :153-200 (:177, :196-197), :322a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java:34-36, :97-99, :741, :768, :777-779a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/search/LongValuesSource.java:30-32, :64-70a Lucene main checkout (645d4fe14a20) lucene/queries/src/java/org/apache/lucene/queries/function/FunctionMatchQuery.java:88; FunctionScoreQuery.java:121; ValueSource.java:184-186, :199-200, :244-246; valuesource/QueryValueSource.java:114-125; IndexReaderFunctions.java:99, :320a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/search/RescoreTopNQuery.java:68-69; lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CoveringQuery.java:172a Lucene main checkout (645d4fe14a20) lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java:197-198, :244-293 (:277); DistanceValueSource.java:96-99a Lucene main checkout (645d4fe14a20) grep: the classes under lucene/*/src/java that extend Query and hold a DoubleValuesSource or LongValuesSource (RescoreTopNQuery, DoubleRange, LongRange, FunctionMatchQuery, FunctionScoreQuery, CoveringQuery, PointVectorStrategy; SerializedDVStrategy holds a ShapeValuesSource)
- Who is affected
a Lucene main checkout (645d4fe14a20) lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java:42; lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java:41 (@lucene.experimental)a Lucene main checkout (645d4fe14a20) lucene/demo/src/java/org/apache/lucene/demo/facet/DistanceFacetsExample.java:125-139, :239-243a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java:92, :97-99, :350-354, :777-779; lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java:183-185, :190
- Why it looks unintended
a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java:34-36, :97-99a Lucene main checkout (645d4fe14a20) lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRange.java:323-334; lucene/facet/src/java/org/apache/lucene/facet/range/LongRange.java:310-321a Lucene main checkout (645d4fe14a20) lucene/facet/src/java/org/apache/lucene/facet/MultiDoubleValuesSource.java:41-47; a Lucene main checkout (645d4fe14a20) lucene/facet/src/java/org/apache/lucene/facet/MultiLongValuesSource.java:43-49a Lucene main checkout (645d4fe14a20) lucene/facet/src/test/org/apache/lucene/facet/range/TestRangeFacetCounts.java:1703-1709a Lucene main checkout (645d4fe14a20) lucene/CHANGES.txt:4438-4442 (LUCENE-10245 entry)a Lucene main checkout (645d4fe14a20) lucene/queries/src/java/org/apache/lucene/queries/function/FunctionMatchQuery.java:88; FunctionScoreQuery.java:121; lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CoveringQuery.java:172; lucene/core/src/java/org/apache/lucene/search/RescoreTopNQuery.java:68-69; lucene/spatial-extras/src/java/org/apache/lucene/spatial/vector/PointVectorStrategy.java:197-198, :277; DistanceValueSource.java:96-99
- Suggested fix
a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java:193-195, :848-850a Lucene main checkout (645d4fe14a20) lucene/core/src/java/org/apache/lucene/search/DoubleValuesSource.java:94; lucene/queries/src/java/org/apache/lucene/queries/function/ValueSource.java:244-246
- TestDoubleRangeGetQueryRewritesSource.java (lucene/facet, one test):
repro/LFV-776/src/org/apache/lucene/facet/range/TestDoubleRangeGetQueryRewritesSource.java(54 lines)
Made in parallel with this doc from the diagram's executed public-API probe on main 645d4fe14a20 (the one-document example, the LongRange view, IndexReaderFunctions.maxDoc(), the QueryValueSource view on a ClassicSimilarity searcher and a field-source control; stock and with the fix, assertions on and off); every code row is checked against the source at that commit.
assets/LFV-776/bug.png(532 KB)
