Interface FormatReader
- All Superinterfaces:
AutoCloseable,Closeable
- All Known Subinterfaces:
NoConfigFormatReader,RangeAwareFormatReader,SegmentableFormatReader
Simple formats: implement only read(StorageObject, FormatReadContext) (sync) -
async wrapping is automatic.
Async-capable formats: override readAsync(StorageObject, FormatReadContext, Executor, ActionListener)
for native async behavior.
The output is ESQL's native Page format rather than Arrow to avoid mandating Arrow as a dependency for all format implementations.
Implementations should provide metadata discovery via metadata(StorageObject)
which returns a unified SourceMetadata containing schema and source information.
Per-query format configuration (delimiter, encoding, etc.) is set on the reader instance
via withConfig(Map). Per-query optimizer hints (pushed filters for row-group
or stripe skipping) are set via withPushedFilter(Object). Per-read execution
parameters (projection, batch size, limit, error policy, split config) are bundled in
FormatReadContext.
-
Nested Class Summary
Nested ClassesModifier and TypeInterfaceDescriptionstatic enumStrategy for resolving schemas across multiple files in a glob/multi-file query. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final FormatReader.SchemaResolutionCluster-wide default schema resolution strategy when a query does not specify one.static final int -
Method Summary
Modifier and TypeMethodDescriptiondefault AggregatePushdownSupportReturns the aggregate pushdown support for this format.default ErrorPolicyReturns the default error policy for this format.default FormatReader.SchemaResolutionReturns the cluster-wide default schema resolution for this reader.default FilterPushdownSupportReturns the filter pushdown support for this format, or null if not supported.metadata(StorageObject object) default voidmetadataAsync(StorageObject object, Executor executor, ActionListener<SourceMetadata> listener) Asynchronously resolves metadata for the given storage object.default CloseableIterator<Page> read(StorageObject object, List<String> projectedColumns, int batchSize) Convenience overload that delegates toread(StorageObject, FormatReadContext).read(StorageObject object, FormatReadContext context) Reads data from the given storage object using the provided context.default voidreadAsync(StorageObject object, FormatReadContext context, Executor executor, ActionListener<CloseableIterator<Page>> listener) Asynchronously reads data from the given storage object using the provided context.Returns this reader'sRowPositionStrategy— the dispatcher applies it polymorphically to wrap (or pass through) the reader's emitted page iterator so each page has the_rowPositionslot populated.schema(StorageObject object) default FormatReaderStatusReturns a typed snapshot of format-reader I/O counters, ornullwhen the reader tracks none.default booleandefault booleanWhether this format supports being wrapped in a whole-file, stream-only decompressor (e.g.default FormatReaderwithConfig(Map<String, Object> config) Returns a reader configured from the input config map.withConfigTrackingConsumedKeys(Map<String, Object> config) Returns a reader configured from the input config map, paired with the keys consumed from it.default FormatReaderwithDeclaredDateFormats(Map<String, String> physicalNameToPattern) Returns a format reader that parses the given columns' dates with the given patterns instead of the ISO default / file-leveldatetime_format.default FormatReaderwithDeclaredTypeColumns(Set<String> physicalDeclaredColumns) Returns a format reader that treats the given columns as declared-type columns: their target type came from an explicit declaration rather than inference, which licenses a lossy read-time coercion toward it (e.g.default FormatReaderwithPushedFilter(Object pushedFilter) Returns a format reader configured with the given pushed filter from the optimizer.default FormatReaderwithSchema(List<Attribute> schema) Returns a format reader configured with the schema attributes.
-
Field Details
-
NO_LIMIT
static final int NO_LIMIT- See Also:
-
DEFAULT_SCHEMA_RESOLUTION
Cluster-wide default schema resolution strategy when a query does not specify one.This is the single source of truth: it is consulted both by this SPI's
defaultSchemaResolution()and byExternalSourceResolver.parseSchemaResolutionwhen noschema_resolutionkey is present in the per-query config. The format detected at glob-expansion time is not yet known when the resolver decides whether to take the read-all-and-reconcile path versus the FFW fast path, so there is no format dispatch here today; if per-format defaults become desirable in the future the resolver will need to peek at the lex-smallest file's format first, and this constant becomes the fallback only.
-
-
Method Details
-
defaultSchemaResolution
Returns the cluster-wide default schema resolution for this reader. Format implementations may override this to advertise a different preferred default, but the resolver does not consult it today (seeDEFAULT_SCHEMA_RESOLUTIONfor the rationale). Override is effectively informational until that wiring exists. -
defaultErrorPolicy
Returns the default error policy for this format. The base default isErrorPolicy.STRICT(fail_fast) and every format inherits it, so a bad per-value coercion fails the read across all formats unless the user opts intoerror_mode: null_field. Pinned per reader by atestDefaultErrorPolicyIsStrictguard; do not override to a lenient default (that would silently diverge one format from the others). -
metadata
- Throws:
IOException
-
metadataAsync
default void metadataAsync(StorageObject object, Executor executor, ActionListener<SourceMetadata> listener) Asynchronously resolves metadata for the given storage object.The default wraps the synchronous
metadata(StorageObject)in the provided executor, mirroringreadAsync(org.elasticsearch.xpack.esql.datasources.spi.StorageObject, org.elasticsearch.xpack.esql.datasources.spi.FormatReadContext, java.util.concurrent.Executor, org.elasticsearch.action.ActionListener<org.elasticsearch.compute.operator.CloseableIterator<org.elasticsearch.compute.data.Page>>). Formats whose footer/metadata read can be issued without holding an executor thread across the network round-trip (e.g. Parquet viaStorageObject.readBytesAsync(long, long, org.elasticsearch.xpack.esql.datasources.spi.DirectBufferFactory, java.util.concurrent.Executor, org.elasticsearch.action.ActionListener<org.elasticsearch.xpack.esql.datasources.spi.DirectReadBuffer>)) should override this so that a wide discovery fan-out is bounded by an in-flight permit rather than by the number of executor threads it pins. -
schema
- Throws:
IOException
-
read
Reads data from the given storage object using the provided context.This is the primary read method. All implementations must override this method.
- Throws:
IOException
-
read
default CloseableIterator<Page> read(StorageObject object, List<String> projectedColumns, int batchSize) throws IOException Convenience overload that delegates toread(StorageObject, FormatReadContext). Keeps test code and simple call sites working without constructing a context.- Throws:
IOException
-
readAsync
default void readAsync(StorageObject object, FormatReadContext context, Executor executor, ActionListener<CloseableIterator<Page>> listener) Asynchronously reads data from the given storage object using the provided context.The default wraps the synchronous
read(StorageObject, FormatReadContext)in the provided executor. Formats with native async support should override this. -
formatName
String formatName() -
fileExtensions
-
withConfig
Returns a reader configured from the input config map. Default delegates towithConfigTrackingConsumedKeys(Map)and discards the consumed-keys set; use this overload when the caller does not need to validate against the consumed keys.Override target: implementations must override
withConfigTrackingConsumedKeys(Map), NOT this method. The defaultwithConfigdelegates through the tracking variant, so an override here alone would be silently bypassed by every caller. The tracking variant is the single configuration entry point for the SPI. -
withConfigTrackingConsumedKeys
Returns a reader configured from the input config map, paired with the keys consumed from it.Required override. Every reader must explicitly declare which keys it claims, even if the answer is "none" (return
Configured.empty(this)). The previousdefaultsilently dropped any unknown keys; that footgun is the reason this is no longer optional. Implementations that read configuration from the map should override this method (notwithConfig(Map)); the consumed-keys set is required byConfigKeyValidatorfor unknown-key rejection at planning time. -
withPushedFilter
Returns a format reader configured with the given pushed filter from the optimizer.The pushed filter is an opaque object produced by
FilterPushdownSupportduring local physical optimization. Only format readers that support predicate pushdown (e.g., Parquet row-group skipping, ORC stripe-level predicates) need to override this.The filter is per-query: it applies identically to every file/split in the query. Implementations should cast the filter to their expected type and return a new reader instance with the filter stored as an instance field.
- Parameters:
pushedFilter- opaque filter object, or null if no filter was pushed- Returns:
- a new reader with the filter applied, or
thisif the filter is not applicable
-
aggregatePushdownSupport
Returns the aggregate pushdown support for this format. Only format readers with column statistics in their metadata (Parquet, ORC) override this. -
withSchema
Returns a format reader configured with the schema attributes.The schema is determined during the planning phase (via
metadata(StorageObject)) and is constant for all files/splits in a query. Passing it here allows the reader to skip re-reading/inferring the schema from the file header on every read, which is especially important for split-based reads where the split may start mid-file (no header available).Formats with embedded schemas (Parquet, ORC) may ignore this since they always read the schema from the file metadata.
- Parameters:
schema- the planning-phase schema attributes, or null to clear- Returns:
- a new reader with the schema set, or
thisif the schema is not needed
-
withDeclaredDateFormats
Returns a format reader that parses the given columns' dates with the given patterns instead of the ISO default / file-leveldatetime_format. Keyed by physical (file) column name — the caller (FileSourceFactory) has already applied any declaredpathrename. The patterns are ESDateFormatterpatterns (named formats and||chains included), matching the dataset-put validation.Only the text formats (CSV/TSV, NDJSON) parse dates from text and override this. Columnar formats (Parquet, ORC) carry native typed values and keep the no-op default — a declared
formaton a columnar column is rejected upstream at query resolution, so it never reaches here.- Parameters:
physicalNameToPattern- per-column date patterns keyed by physical column name; empty for no declared formats- Returns:
- a new reader applying the per-column formats, or
thiswhen none apply
-
withDeclaredTypeColumns
Returns a format reader that treats the given columns as declared-type columns: their target type came from an explicit declaration rather than inference, which licenses a lossy read-time coercion toward it (e.g. a declaredintegerover anint64file column narrows per value, null on overflow). An inferred target must never narrow — a cross-file clash widens-or-nulls. Keyed by physical (file) column name; the caller (FileSourceFactory) has already applied any declaredpathrename.Only the by-name columnar formats (Parquet, ORC) make a whole-column incompatibility null-fill decision and override this — a declared column keeps the coercion escape, an inferred column null-fills whenever the file type is not widening-compatible. The text formats (CSV/TSV, NDJSON) parse straight into the target and keep the no-op default (their per-field failures are governed by the
ErrorPolicy, not a whole-column type check).- Parameters:
physicalDeclaredColumns- physical names of the declared-type columns; empty when no column type was declared- Returns:
- a new reader honoring the declared-type set, or
thiswhen none apply
-
filterPushdownSupport
Returns the filter pushdown support for this format, or null if not supported.When non-null, the optimizer can translate ESQL filter expressions into format-specific predicates (e.g., Parquet FilterPredicate) that enable row-group skipping via statistics, dictionary, and bloom filter checks.
- Returns:
- FilterPushdownSupport for this format, or null if not supported
-
supportsNativeAsync
default boolean supportsNativeAsync() -
supportsWholeFileCompression
default boolean supportsWholeFileCompression()Whether this format supports being wrapped in a whole-file, stream-only decompressor (e.g..parquet.zstor.orc.gz). Sequential formats (CSV, NDJSON) return the defaulttrue. Tail/footer-based formats (Parquet, ORC) must override tofalsebecause they require random access and a known decompressed length. This flag does NOT affect a format's own internal compression (e.g. Parquet column-chunk zstd). -
statusSnapshot
Returns a typed snapshot of format-reader I/O counters, ornullwhen the reader tracks none. The snapshot is folded into theformat_readerfield of the external-source operator status. -
rowPositionStrategy
RowPositionStrategy rowPositionStrategy()Returns this reader'sRowPositionStrategy— the dispatcher applies it polymorphically to wrap (or pass through) the reader's emitted page iterator so each page has the_rowPositionslot populated. Every reader must explicitly declare a strategy: aPassThroughRowPositionStrategywhen the reader natively fills the slot in its own iterator (parquet-mr, ORC, CSV, NDJSON), aNullSpliceRowPositionStrategywhen the reader has no row-position channel and the slot must surface NULL (parquet-rs), or a future strategy that injects the column from per-page reader state. There is no default — readers that "don't care" still participate, by returningPassThroughRowPositionStrategy.
-