IndexOrDocValuesQuery chooses between the index side and the doc-values side using a cost heuristic that predates doc-values skippers. The decision is driven by the index side's cost (with a fixed penalty applied to doc values); it has no awareness that the doc-values side may carry a DocValuesSkipper.
When a skipper is present and effective (values well-correlated with doc order, e.g. a primary/secondary index sort or naturally monotonic data), the doc-values side can skip whole blocks and be dramatically cheaper than the index side. But because the skipper never enters the cost model, IndexOrDocValuesQuery keeps choosing the index side — particularly for a standalone range, where it always does — and the skipper's benefit is left on the table.
The core gap is that the doc-values range scorer doesn't expose a meaningful, skipper-aware cost for the planner to use (see #15981, where SkipBlockRangeIterator.cost() currently returns NO_MORE_DOCS).
Related issues
IndexOrDocValuesQuerychooses between the index side and the doc-values side using a cost heuristic that predates doc-values skippers. The decision is driven by the index side's cost (with a fixed penalty applied to doc values); it has no awareness that the doc-values side may carry a DocValuesSkipper.When a skipper is present and effective (values well-correlated with doc order, e.g. a primary/secondary index sort or naturally monotonic data), the doc-values side can skip whole blocks and be dramatically cheaper than the index side. But because the skipper never enters the cost model, IndexOrDocValuesQuery keeps choosing the index side — particularly for a standalone range, where it always does — and the skipper's benefit is left on the table.
The core gap is that the doc-values range scorer doesn't expose a meaningful, skipper-aware cost for the planner to use (see #15981, where SkipBlockRangeIterator.cost() currently returns NO_MORE_DOCS).
Related issues