Interface ColumnExtractor
- All Superinterfaces:
AutoCloseable,Closeable,Releasable
Deferred extraction keeps the forward scan narrow (sort keys, predicates, and the synthetic routing column) and materializes wide projection-only columns only after a per-driver TopN has chosen surviving rows.
Addressing space (physical row identity)
Thepositions accepted by extract(java.lang.String[], org.elasticsearch.xpack.esql.core.type.DataType[], long[], org.elasticsearch.compute.data.BlockFactory) are row identities: stable, opaque
longs the iterator that emits ROW_POSITION_COLUMN attached to each row. The
extractor and the iterator must agree on the encoding — for the Parquet implementation, it is
the file-global row index in footer iteration order, which is filter-, late-materialization-,
and page-skip-invariant. This makes the handshake robust to whatever survives between scan and
extract: the same row coming back later carries the same identity that pointed at it during the
forward scan, no matter how many predicate / page-skipping transforms ran in between.
The handshake between an iterator and its matching extractor is expressed by
ColumnExtractorProducer: an iterator that emits ROW_POSITION_COLUMN implements
that interface and produces an extractor whose addressing space matches its own.
Composition across multiple sources opened in the same driver — assigning extractor ids,
encoding references, and dispatching extractions — is handled by SourceExtractors
(org.elasticsearch.xpack.esql.datasources.SourceExtractors), not by this SPI.
Threading: a single driver thread owns an instance; implementations need not be thread-safe.
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intBit position of the extractor id within an encoded_rowPositionvalue.static final StringReserved name of the synthetic row-reference column emitted by source readers that support deferred materialization. -
Method Summary
Modifier and TypeMethodDescriptionBlock[]extract(String[] columnNames, DataType[] targetTypes, long[] positions, BlockFactory blockFactory) Materializes one or more columns at the given row identities in a single I/O batch.default Blockextract(String columnName, long[] positions, BlockFactory blockFactory) Convenience overload for the common single-column case.longrowCount()Number of distinct row identities addressable by this extractor.Methods inherited from interface org.elasticsearch.core.Releasable
close
-
Field Details
-
LOCAL_POSITION_BITS
static final int LOCAL_POSITION_BITSBit position of the extractor id within an encoded_rowPositionvalue. The lowLOCAL_POSITION_BITShold the per-extractor physical row identity; the high bits hold the registry-assigned extractor id. This is the wire-format the iterator implementingColumnExtractorProducermust respect when it pre-encodes its emitted values.The framework's
SourceExtractorsowns the canonical encoding/decoding helpers and pins this same value; the constant is mirrored here so format readers depend only on the SPI when implementing the encoding handshake.- See Also:
-
ROW_POSITION_COLUMN
Reserved name of the synthetic row-reference column emitted by source readers that support deferred materialization. Values are opaque encoded references combining an extractor id with a physical row identity — seeorg.elasticsearch.xpack.esql.datasources.SourceExtractorsfor the bit layout.Encoding lives at the iterator boundary: the source factory wires an extractor id into the iterator via
ColumnExtractorProducer.setExtractorId(int), and from then on every_rowPositionvalue the iterator emits is already encoded as(id << 48) | physicalRowOffset. Downstream operators decode without a separate encoding pass. The extract operator removes this channel from its output.Historically the encoding ran in a wrapper iterator that rebuilt the
_rowPositionblock per page. That wrapper was removed once iterators began materialising the values themselves; if a future format reader cannot pre-encode in-line, re-introducing a similar wrapper is a viable (if slower) fallback — the contract surfaces here so the option remains discoverable.- See Also:
-
-
Method Details
-
rowCount
long rowCount()Number of distinct row identities addressable by this extractor.The valid range for
extract(java.lang.String[], org.elasticsearch.xpack.esql.core.type.DataType[], long[], org.elasticsearch.compute.data.BlockFactory)'spositionsentries is[0, rowCount()). For Parquet this is the file's total row count.Implementations should return a pure in-memory value without triggering I/O.
- Returns:
- number of rows addressable by this extractor
-
extract
Block[] extract(String[] columnNames, @Nullable DataType[] targetTypes, long[] positions, BlockFactory blockFactory) throws IOException Materializes one or more columns at the given row identities in a single I/O batch.Callers invoke this after TopN with only the identities that survived pruning. Identities may be unsorted and may repeat; the returned blocks must align row
iwithpositions[i]so operators can zip deferred values with encoded references without an extra reordering pass. Each entry must lie in[0, rowCount()).Implementations should fetch every requested column's bytes in one coalesced batch so that latency and per-request overhead are amortised across the projection. For object-store backends like S3 the win is significant: the cost dominator is the per-request RTT/TTFB, so issuing one fan-out batch covering all columns instead of N sequential batches turns a
O(N)round-trip wait intoO(1). For physical layouts where columns within a row group are contiguous (e.g. Parquet column chunks), the bytes for multiple columns also coalesce naturally during merging.Returned blocks are owned by the caller; on partial failure, the implementation must release any blocks it already built before propagating the exception.
targetTypescarries the planner/declared type per column so extraction honors the same declared-type coercion the eager decode paths run (DeclaredTypeCoercions): a column whose file type differs from its target coerces value-by-value (per-value failures null the cell and emit a response Warning header, bulk-API style).null— the whole array or an entry — means "emit the file's own type" (no coercion).- Parameters:
columnNames- logical columns to load, in output order; must not containROW_POSITION_COLUMNtargetTypes- planner/declared type per column, aligned withcolumnNames;null(array or entry) disables coercion for that columnpositions- row identities; every element is readblockFactory- factory for breaker-aware allocation- Returns:
- one block per requested column, each with exactly
positions.lengthvalues in caller order - Throws:
IOException- if the format reader fails while satisfying the request
-
extract
default Block extract(String columnName, long[] positions, BlockFactory blockFactory) throws IOException Convenience overload for the common single-column case. Delegates toextract(String[], DataType[], long[], BlockFactory)so implementations only need to provide one code path.- Throws:
IOException
-