@loaders.gl/parquet 5.0.0-alpha.2 → 5.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/dist/bundled.d.ts +1 -1
- package/dist/bundled.d.ts.map +1 -1
- package/dist/bundled.js.map +1 -1
- package/dist/delta-format.d.ts +9 -0
- package/dist/delta-format.d.ts.map +1 -0
- package/dist/delta-format.js +12 -0
- package/dist/delta-format.js.map +1 -0
- package/dist/delta-source-loader-types.d.ts +27 -0
- package/dist/delta-source-loader-types.d.ts.map +1 -0
- package/dist/delta-source-loader-types.js +28 -0
- package/dist/delta-source-loader-types.js.map +1 -0
- package/dist/delta-source.d.ts +48 -0
- package/dist/delta-source.d.ts.map +1 -0
- package/dist/delta-source.js +222 -0
- package/dist/delta-source.js.map +1 -0
- package/dist/delta-types.d.ts +38 -0
- package/dist/delta-types.d.ts.map +1 -0
- package/dist/delta-types.js +5 -0
- package/dist/delta-types.js.map +1 -0
- package/dist/geoparquet-loader.js +1 -1
- package/dist/iceberg-rest-catalog.d.ts +49 -0
- package/dist/iceberg-rest-catalog.d.ts.map +1 -0
- package/dist/iceberg-rest-catalog.js +78 -0
- package/dist/iceberg-rest-catalog.js.map +1 -0
- package/dist/iceberg-table-source.d.ts +63 -0
- package/dist/iceberg-table-source.d.ts.map +1 -0
- package/dist/iceberg-table-source.js +797 -0
- package/dist/iceberg-table-source.js.map +1 -0
- package/dist/iceberg-types.d.ts +150 -0
- package/dist/iceberg-types.d.ts.map +1 -0
- package/dist/iceberg-types.js +5 -0
- package/dist/iceberg-types.js.map +1 -0
- package/dist/index.cjs +15005 -3143
- package/dist/index.cjs.map +3 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/arrow/convert-schema-from-parquet.d.ts +3 -1
- package/dist/lib/arrow/convert-schema-from-parquet.d.ts.map +1 -1
- package/dist/lib/arrow/convert-schema-from-parquet.js +94 -19
- package/dist/lib/arrow/convert-schema-from-parquet.js.map +1 -1
- package/dist/lib/arrow/create-nested-arrow-vector.js +89 -0
- package/dist/lib/arrow/create-nested-arrow-vector.js.map +1 -1
- package/dist/lib/constants.js +1 -1
- package/dist/lib/encoders/encode-table-to-parquet-js.d.ts.map +1 -1
- package/dist/lib/encoders/encode-table-to-parquet-js.js +202 -7
- package/dist/lib/encoders/encode-table-to-parquet-js.js.map +1 -1
- package/dist/lib/geo/geoparquet-covering.d.ts +19 -0
- package/dist/lib/geo/geoparquet-covering.d.ts.map +1 -0
- package/dist/lib/geo/geoparquet-covering.js +137 -0
- package/dist/lib/geo/geoparquet-covering.js.map +1 -0
- package/dist/lib/geo/geospatial-metadata.d.ts.map +1 -1
- package/dist/lib/geo/geospatial-metadata.js +39 -13
- package/dist/lib/geo/geospatial-metadata.js.map +1 -1
- package/dist/lib/parquet-bloom-filter-planner.d.ts +16 -0
- package/dist/lib/parquet-bloom-filter-planner.d.ts.map +1 -0
- package/dist/lib/parquet-bloom-filter-planner.js +57 -0
- package/dist/lib/parquet-bloom-filter-planner.js.map +1 -0
- package/dist/lib/parquet-bloom-filter.d.ts +30 -0
- package/dist/lib/parquet-bloom-filter.d.ts.map +1 -0
- package/dist/lib/parquet-bloom-filter.js +289 -0
- package/dist/lib/parquet-bloom-filter.js.map +1 -0
- package/dist/lib/parquet-encryption.d.ts +80 -0
- package/dist/lib/parquet-encryption.d.ts.map +1 -0
- package/dist/lib/parquet-encryption.js +190 -0
- package/dist/lib/parquet-encryption.js.map +1 -0
- package/dist/lib/parquet-page-index.d.ts +34 -5
- package/dist/lib/parquet-page-index.d.ts.map +1 -1
- package/dist/lib/parquet-page-index.js +114 -28
- package/dist/lib/parquet-page-index.js.map +1 -1
- package/dist/lib/parquet-predicate.d.ts +5 -1
- package/dist/lib/parquet-predicate.d.ts.map +1 -1
- package/dist/lib/parquet-predicate.js +42 -14
- package/dist/lib/parquet-predicate.js.map +1 -1
- package/dist/lib/parquet-source-worker-decoder.d.ts +4 -1
- package/dist/lib/parquet-source-worker-decoder.d.ts.map +1 -1
- package/dist/lib/parquet-source-worker-decoder.js +83 -17
- package/dist/lib/parquet-source-worker-decoder.js.map +1 -1
- package/dist/lib/parquet-source-worker-types.d.ts +24 -0
- package/dist/lib/parquet-source-worker-types.d.ts.map +1 -1
- package/dist/lib/parsers/get-parquet-schema.d.ts.map +1 -1
- package/dist/lib/parsers/get-parquet-schema.js +3 -1
- package/dist/lib/parsers/get-parquet-schema.js.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-arrow-js.d.ts.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-arrow-js.js +327 -18
- package/dist/lib/parsers/parse-parquet-to-arrow-js.js.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-arrow.d.ts.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-arrow.js +5 -5
- package/dist/lib/parsers/parse-parquet-to-arrow.js.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-columns.d.ts.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-columns.js +3 -1
- package/dist/lib/parsers/parse-parquet-to-columns.js.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-json.d.ts.map +1 -1
- package/dist/lib/parsers/parse-parquet-to-json.js +18 -2
- package/dist/lib/parsers/parse-parquet-to-json.js.map +1 -1
- package/dist/lib/slice-parquet-batch.d.ts +9 -0
- package/dist/lib/slice-parquet-batch.d.ts.map +1 -0
- package/dist/lib/slice-parquet-batch.js +28 -0
- package/dist/lib/slice-parquet-batch.js.map +1 -0
- package/dist/lib/sources/parquet-range-file.d.ts +1 -1
- package/dist/lib/sources/parquet-range-file.d.ts.map +1 -1
- package/dist/lib/sources/parquet-range-file.js +28 -22
- package/dist/lib/sources/parquet-range-file.js.map +1 -1
- package/dist/lib/utils/normalize-parquet-options.d.ts.map +1 -1
- package/dist/lib/utils/normalize-parquet-options.js +15 -1
- package/dist/lib/utils/normalize-parquet-options.js.map +1 -1
- package/dist/parquet-dataset-source.cjs +15766 -4896
- package/dist/parquet-dataset-source.cjs.map +3 -3
- package/dist/parquet-dataset-source.d.ts +31 -4
- package/dist/parquet-dataset-source.d.ts.map +1 -1
- package/dist/parquet-dataset-source.js +296 -74
- package/dist/parquet-dataset-source.js.map +1 -1
- package/dist/parquet-js-loader-types.d.ts +2 -0
- package/dist/parquet-js-loader-types.d.ts.map +1 -1
- package/dist/parquet-js-loader-types.js +2 -1
- package/dist/parquet-js-loader-types.js.map +1 -1
- package/dist/parquet-js-loader.d.ts +1 -0
- package/dist/parquet-js-loader.d.ts.map +1 -1
- package/dist/parquet-js-loader.js +2 -1
- package/dist/parquet-js-loader.js.map +1 -1
- package/dist/parquet-js-writer.d.ts +23 -2
- package/dist/parquet-js-writer.d.ts.map +1 -1
- package/dist/parquet-js-writer.js +1 -1
- package/dist/parquet-js-writer.js.map +1 -1
- package/dist/parquet-loader-base.js +1 -1
- package/dist/parquet-loader-options.d.ts +11 -0
- package/dist/parquet-loader-options.d.ts.map +1 -1
- package/dist/parquet-loader-options.js.map +1 -1
- package/dist/parquet-source-capabilities.d.ts +8 -1
- package/dist/parquet-source-capabilities.d.ts.map +1 -1
- package/dist/parquet-source-capabilities.js +10 -0
- package/dist/parquet-source-capabilities.js.map +1 -1
- package/dist/parquet-source-loader-types.d.ts +10 -0
- package/dist/parquet-source-loader-types.d.ts.map +1 -1
- package/dist/parquet-source-loader-types.js +11 -1
- package/dist/parquet-source-loader-types.js.map +1 -1
- package/dist/parquet-source-loader.cjs +14911 -4316
- package/dist/parquet-source-loader.cjs.map +3 -3
- package/dist/parquet-source-loader.d.ts +42 -4
- package/dist/parquet-source-loader.d.ts.map +1 -1
- package/dist/parquet-source-loader.js +585 -38
- package/dist/parquet-source-loader.js.map +1 -1
- package/dist/parquet-source-types.d.ts +180 -30
- package/dist/parquet-source-types.d.ts.map +1 -1
- package/dist/parquet-source-worker.js +7055 -6989
- package/dist/parquet-source-worker.js.map +4 -4
- package/dist/parquet-worker-node.cjs +8505 -1041
- package/dist/parquet-worker-node.cjs.map +4 -4
- package/dist/parquet-worker-url.js +5 -1
- package/dist/parquet-worker-url.js.map +1 -1
- package/dist/parquet-worker.js +289 -218
- package/dist/parquet-worker.js.map +4 -4
- package/dist/parquetjs/codecs/declare.d.ts +15 -0
- package/dist/parquetjs/codecs/declare.d.ts.map +1 -1
- package/dist/parquetjs/codecs/declare.js +10 -0
- package/dist/parquetjs/codecs/declare.js.map +1 -1
- package/dist/parquetjs/codecs/delta.d.ts.map +1 -1
- package/dist/parquetjs/codecs/delta.js +356 -7
- package/dist/parquetjs/codecs/delta.js.map +1 -1
- package/dist/parquetjs/codecs/index.d.ts.map +1 -1
- package/dist/parquetjs/codecs/index.js +4 -0
- package/dist/parquetjs/codecs/index.js.map +1 -1
- package/dist/parquetjs/codecs/plain.d.ts +1 -1
- package/dist/parquetjs/codecs/plain.d.ts.map +1 -1
- package/dist/parquetjs/codecs/plain.js +153 -12
- package/dist/parquetjs/codecs/plain.js.map +1 -1
- package/dist/parquetjs/codecs/rle.d.ts +4 -0
- package/dist/parquetjs/codecs/rle.d.ts.map +1 -1
- package/dist/parquetjs/codecs/rle.js +406 -3
- package/dist/parquetjs/codecs/rle.js.map +1 -1
- package/dist/parquetjs/compression.d.ts +9 -0
- package/dist/parquetjs/compression.d.ts.map +1 -1
- package/dist/parquetjs/compression.js +86 -67
- package/dist/parquetjs/compression.js.map +1 -1
- package/dist/parquetjs/encoder/dictionary-planner.d.ts.map +1 -1
- package/dist/parquetjs/encoder/dictionary-planner.js +5 -2
- package/dist/parquetjs/encoder/dictionary-planner.js.map +1 -1
- package/dist/parquetjs/encoder/parquet-encoder.d.ts +43 -1
- package/dist/parquetjs/encoder/parquet-encoder.d.ts.map +1 -1
- package/dist/parquetjs/encoder/parquet-encoder.js +691 -34
- package/dist/parquetjs/encoder/parquet-encoder.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/BoundingBox.d.ts +29 -0
- package/dist/parquetjs/parquet-thrift/BoundingBox.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/BoundingBox.js +85 -0
- package/dist/parquetjs/parquet-thrift/BoundingBox.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/ColumnChunk.d.ts +5 -0
- package/dist/parquetjs/parquet-thrift/ColumnChunk.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnChunk.js +35 -0
- package/dist/parquetjs/parquet-thrift/ColumnChunk.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnCryptoMetaData.d.ts +35 -0
- package/dist/parquetjs/parquet-thrift/ColumnCryptoMetaData.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/ColumnCryptoMetaData.js +135 -0
- package/dist/parquetjs/parquet-thrift/ColumnCryptoMetaData.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/ColumnMetaData.d.ts +10 -0
- package/dist/parquetjs/parquet-thrift/ColumnMetaData.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/ColumnMetaData.js +73 -0
- package/dist/parquetjs/parquet-thrift/ColumnMetaData.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/EncryptionAlgorithm.d.ts +22 -0
- package/dist/parquetjs/parquet-thrift/EncryptionAlgorithm.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/EncryptionAlgorithm.js +111 -0
- package/dist/parquetjs/parquet-thrift/EncryptionAlgorithm.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/FileCryptoMetaData.d.ts +16 -0
- package/dist/parquetjs/parquet-thrift/FileCryptoMetaData.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/FileCryptoMetaData.js +57 -0
- package/dist/parquetjs/parquet-thrift/FileCryptoMetaData.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/FileMetaData.d.ts +5 -0
- package/dist/parquetjs/parquet-thrift/FileMetaData.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/FileMetaData.js +35 -0
- package/dist/parquetjs/parquet-thrift/FileMetaData.js.map +1 -1
- package/dist/parquetjs/parquet-thrift/GeospatialStatistics.d.ts +18 -0
- package/dist/parquetjs/parquet-thrift/GeospatialStatistics.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/GeospatialStatistics.js +62 -0
- package/dist/parquetjs/parquet-thrift/GeospatialStatistics.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/SizeStatistics.d.ts +26 -0
- package/dist/parquetjs/parquet-thrift/SizeStatistics.d.ts.map +1 -0
- package/dist/parquetjs/parquet-thrift/SizeStatistics.js +85 -0
- package/dist/parquetjs/parquet-thrift/SizeStatistics.js.map +1 -0
- package/dist/parquetjs/parquet-thrift/index.d.ts +6 -0
- package/dist/parquetjs/parquet-thrift/index.d.ts.map +1 -1
- package/dist/parquetjs/parquet-thrift/index.js +6 -0
- package/dist/parquetjs/parquet-thrift/index.js.map +1 -1
- package/dist/parquetjs/parser/decoders.d.ts +10 -1
- package/dist/parquetjs/parser/decoders.d.ts.map +1 -1
- package/dist/parquetjs/parser/decoders.js +318 -14
- package/dist/parquetjs/parser/decoders.js.map +1 -1
- package/dist/parquetjs/parser/parquet-reader.d.ts +78 -12
- package/dist/parquetjs/parser/parquet-reader.d.ts.map +1 -1
- package/dist/parquetjs/parser/parquet-reader.js +605 -66
- package/dist/parquetjs/parser/parquet-reader.js.map +1 -1
- package/dist/parquetjs/schema/declare.d.ts +22 -3
- package/dist/parquetjs/schema/declare.d.ts.map +1 -1
- package/dist/parquetjs/schema/declare.js.map +1 -1
- package/dist/parquetjs/schema/schema.d.ts.map +1 -1
- package/dist/parquetjs/schema/schema.js +10 -0
- package/dist/parquetjs/schema/schema.js.map +1 -1
- package/dist/parquetjs/schema/shred.d.ts.map +1 -1
- package/dist/parquetjs/schema/shred.js +219 -11
- package/dist/parquetjs/schema/shred.js.map +1 -1
- package/dist/parquetjs/schema/types.js +19 -21
- package/dist/parquetjs/schema/types.js.map +1 -1
- package/dist/parquetjs/schema/variant.d.ts +3 -0
- package/dist/parquetjs/schema/variant.d.ts.map +1 -0
- package/dist/parquetjs/schema/variant.js +248 -0
- package/dist/parquetjs/schema/variant.js.map +1 -0
- package/dist/parquetjs/utils/crc32.d.ts +3 -0
- package/dist/parquetjs/utils/crc32.d.ts.map +1 -0
- package/dist/parquetjs/utils/crc32.js +15 -0
- package/dist/parquetjs/utils/crc32.js.map +1 -0
- package/dist/parquetjs/utils/read-utils.d.ts +11 -1
- package/dist/parquetjs/utils/read-utils.d.ts.map +1 -1
- package/dist/parquetjs/utils/read-utils.js +21 -1
- package/dist/parquetjs/utils/read-utils.js.map +1 -1
- package/dist/unbundled.d.ts +2 -1
- package/dist/unbundled.d.ts.map +1 -1
- package/dist/unbundled.js +1 -0
- package/dist/unbundled.js.map +1 -1
- package/package.json +36 -11
- package/src/bundled.ts +3 -0
- package/src/delta-format.ts +12 -0
- package/src/delta-source-loader-types.ts +40 -0
- package/src/delta-source.ts +305 -0
- package/src/delta-types.ts +40 -0
- package/src/iceberg-rest-catalog.ts +122 -0
- package/src/iceberg-table-source.ts +1037 -0
- package/src/iceberg-types.ts +165 -0
- package/src/index.ts +50 -1
- package/src/lib/arrow/convert-schema-from-parquet.ts +113 -19
- package/src/lib/arrow/create-nested-arrow-vector.ts +116 -0
- package/src/lib/encoders/encode-table-to-parquet-js.ts +268 -7
- package/src/lib/geo/geoparquet-covering.ts +201 -0
- package/src/lib/geo/geospatial-metadata.ts +42 -15
- package/src/lib/parquet-bloom-filter-planner.ts +86 -0
- package/src/lib/parquet-bloom-filter.ts +345 -0
- package/src/lib/parquet-encryption.ts +344 -0
- package/src/lib/parquet-page-index.ts +180 -34
- package/src/lib/parquet-predicate.ts +52 -16
- package/src/lib/parquet-source-worker-decoder.ts +116 -20
- package/src/lib/parquet-source-worker-types.ts +25 -0
- package/src/lib/parsers/get-parquet-schema.ts +3 -1
- package/src/lib/parsers/parse-parquet-to-arrow-js.ts +397 -17
- package/src/lib/parsers/parse-parquet-to-arrow.ts +4 -5
- package/src/lib/parsers/parse-parquet-to-columns.ts +3 -1
- package/src/lib/parsers/parse-parquet-to-json.ts +18 -2
- package/src/lib/slice-parquet-batch.ts +32 -0
- package/src/lib/sources/parquet-range-file.ts +35 -29
- package/src/lib/utils/normalize-parquet-options.ts +17 -1
- package/src/parquet-dataset-source.ts +397 -85
- package/src/parquet-js-loader-types.ts +1 -0
- package/src/parquet-js-loader.ts +2 -1
- package/src/parquet-js-writer.ts +30 -0
- package/src/parquet-loader-options.ts +11 -0
- package/src/parquet-source-capabilities.ts +18 -1
- package/src/parquet-source-loader-types.ts +10 -0
- package/src/parquet-source-loader.ts +929 -52
- package/src/parquet-source-types.ts +197 -28
- package/src/parquet-worker-url.ts +6 -1
- package/src/parquetjs/codecs/declare.ts +27 -0
- package/src/parquetjs/codecs/delta.ts +466 -6
- package/src/parquetjs/codecs/index.ts +4 -0
- package/src/parquetjs/codecs/plain.ts +177 -11
- package/src/parquetjs/codecs/rle.ts +573 -3
- package/src/parquetjs/compression.ts +102 -76
- package/src/parquetjs/encoder/dictionary-planner.ts +7 -2
- package/src/parquetjs/encoder/parquet-encoder.ts +1016 -38
- package/src/parquetjs/parquet-thrift/BoundingBox.ts +108 -0
- package/src/parquetjs/parquet-thrift/ColumnChunk.ts +35 -0
- package/src/parquetjs/parquet-thrift/ColumnCryptoMetaData.ts +139 -0
- package/src/parquetjs/parquet-thrift/ColumnMetaData.ts +73 -0
- package/src/parquetjs/parquet-thrift/EncryptionAlgorithm.ts +127 -0
- package/src/parquetjs/parquet-thrift/FileCryptoMetaData.ts +60 -0
- package/src/parquetjs/parquet-thrift/FileMetaData.ts +35 -0
- package/src/parquetjs/parquet-thrift/GeospatialStatistics.ts +68 -0
- package/src/parquetjs/parquet-thrift/SizeStatistics.ts +98 -0
- package/src/parquetjs/parquet-thrift/index.ts +6 -0
- package/src/parquetjs/parser/decoders.ts +451 -26
- package/src/parquetjs/parser/parquet-reader.ts +935 -87
- package/src/parquetjs/schema/declare.ts +22 -2
- package/src/parquetjs/schema/schema.ts +10 -0
- package/src/parquetjs/schema/shred.ts +238 -11
- package/src/parquetjs/schema/types.ts +16 -25
- package/src/parquetjs/schema/variant.ts +313 -0
- package/src/parquetjs/utils/crc32.ts +15 -0
- package/src/parquetjs/utils/read-utils.ts +26 -1
- package/src/unbundled.ts +14 -0
|
@@ -2,24 +2,39 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import {
|
|
6
|
+
executeScanTasks,
|
|
7
|
+
emitScanExecutionTelemetry,
|
|
8
|
+
explainTableQuery,
|
|
9
|
+
validateTableQueryLimit,
|
|
10
|
+
type CoreAPI,
|
|
11
|
+
type ScanFragment,
|
|
12
|
+
type ScanFragmentProvider,
|
|
13
|
+
type ScanTask,
|
|
14
|
+
type ScanExecutionTelemetry
|
|
15
|
+
} from '@loaders.gl/loader-utils';
|
|
6
16
|
import type {Schema} from '@loaders.gl/schema';
|
|
7
17
|
|
|
8
|
-
import {SingleBatchQueue} from './lib/sources/single-batch-queue';
|
|
9
18
|
import {ParquetSource} from './parquet-source-loader';
|
|
19
|
+
import {sliceParquetBatch} from './lib/slice-parquet-batch';
|
|
20
|
+
import {PARQUET_TABLE_QUERY_CAPABILITIES} from './parquet-source-capabilities';
|
|
10
21
|
import type {
|
|
11
22
|
ParquetDatasetBatch,
|
|
12
23
|
ParquetDatasetBatchProvenance,
|
|
13
24
|
ParquetDatasetBoundingBox,
|
|
14
25
|
ParquetDatasetFile,
|
|
26
|
+
ParquetDatasetFileScanPlan,
|
|
15
27
|
ParquetDatasetFileCollection,
|
|
16
28
|
ParquetDatasetFileQuery,
|
|
17
29
|
ParquetDatasetFiles,
|
|
18
30
|
ParquetDatasetPartitionValue,
|
|
19
31
|
ParquetDatasetReadOptions,
|
|
32
|
+
ParquetDatasetExplain,
|
|
20
33
|
ParquetDatasetSourceOptions,
|
|
21
34
|
ParquetDatasetTelemetry,
|
|
22
35
|
ParquetSourceBatch,
|
|
36
|
+
ParquetPredicate,
|
|
37
|
+
ParquetSourceExplain,
|
|
23
38
|
ParquetTelemetry
|
|
24
39
|
} from './parquet-source-types';
|
|
25
40
|
|
|
@@ -27,8 +42,10 @@ export type {
|
|
|
27
42
|
ParquetDatasetBatch,
|
|
28
43
|
ParquetDatasetBatchProvenance,
|
|
29
44
|
ParquetDatasetBoundingBox,
|
|
45
|
+
ParquetDatasetExplain,
|
|
30
46
|
ParquetDatasetFile,
|
|
31
47
|
ParquetDatasetFileCollection,
|
|
48
|
+
ParquetDatasetFileScanPlan,
|
|
32
49
|
ParquetDatasetFileProvider,
|
|
33
50
|
ParquetDatasetFileQuery,
|
|
34
51
|
ParquetDatasetFiles,
|
|
@@ -47,11 +64,15 @@ type IndexedParquetDatasetFile = {
|
|
|
47
64
|
index: number;
|
|
48
65
|
};
|
|
49
66
|
|
|
50
|
-
type
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
|
|
67
|
+
type ParquetDatasetDiscoverySummary = {
|
|
68
|
+
/** Descriptors returned by the provider. */
|
|
69
|
+
discovered: number;
|
|
70
|
+
/** Descriptors retained after local pruning. */
|
|
71
|
+
selected: number;
|
|
72
|
+
/** Descriptors rejected by bounding-box intersection. */
|
|
73
|
+
prunedByBoundingBox: number;
|
|
74
|
+
/** Descriptors rejected by partition constraints. */
|
|
75
|
+
prunedByPartitions: number;
|
|
55
76
|
};
|
|
56
77
|
|
|
57
78
|
/**
|
|
@@ -60,7 +81,9 @@ type ScheduledFileRead = {
|
|
|
60
81
|
* The source accepts static descriptors or a lazy provider, allowing STAC and other catalogs to be
|
|
61
82
|
* injected without coupling `@loaders.gl/parquet` to a catalog protocol.
|
|
62
83
|
*/
|
|
63
|
-
export class ParquetDatasetSource {
|
|
84
|
+
export class ParquetDatasetSource implements ScanFragmentProvider<ParquetPredicate> {
|
|
85
|
+
/** Common projection, predicate, limit, streaming, and cancellation capabilities. */
|
|
86
|
+
readonly tableQueryCapabilities = PARQUET_TABLE_QUERY_CAPABILITIES;
|
|
64
87
|
/** Static descriptors or lazy catalog-backed file provider. */
|
|
65
88
|
readonly files: ParquetDatasetFiles;
|
|
66
89
|
/** Child-source and dataset orchestration options. */
|
|
@@ -121,6 +144,137 @@ export class ParquetDatasetSource {
|
|
|
121
144
|
});
|
|
122
145
|
}
|
|
123
146
|
|
|
147
|
+
/** Discovers catalog-independent fragments after applying descriptor-level pruning. */
|
|
148
|
+
async getScanFragments(
|
|
149
|
+
options: ParquetDatasetReadOptions = {}
|
|
150
|
+
): Promise<readonly ScanFragment[]> {
|
|
151
|
+
this.assertOpen();
|
|
152
|
+
const fragments: ScanFragment[] = [];
|
|
153
|
+
const selectedFiles = this.getSelectedFiles(options);
|
|
154
|
+
for await (const indexedFile of selectedFiles) {
|
|
155
|
+
const file = indexedFile.file;
|
|
156
|
+
if (typeof file.data !== 'string' && !file.id) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
'Parquet dataset Blob fragments require an explicit stable id for fragment discovery'
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
fragments.push(
|
|
162
|
+
Object.freeze({
|
|
163
|
+
id: getDatasetFileId(file, indexedFile.index),
|
|
164
|
+
uri: typeof file.data === 'string' ? file.data : undefined,
|
|
165
|
+
partitionValues: file.partitions,
|
|
166
|
+
metadata: file.metadata
|
|
167
|
+
})
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
return Object.freeze(fragments);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Plans descriptor discovery and every retained file's Parquet physical scan. */
|
|
174
|
+
async getScanPlan(options: ParquetDatasetReadOptions = {}): Promise<ParquetDatasetExplain> {
|
|
175
|
+
this.assertOpen();
|
|
176
|
+
validateTableQueryLimit(options.limit);
|
|
177
|
+
const readContext = createDatasetAbortContext(options.signal);
|
|
178
|
+
this.activeReadControllers.add(readContext.abortController);
|
|
179
|
+
const discovery = createParquetDatasetDiscoverySummary();
|
|
180
|
+
const filePlans: ParquetDatasetFileScanPlan[] = [];
|
|
181
|
+
const tasks = this.getPlanTasks(options, readContext.abortController.signal, discovery);
|
|
182
|
+
const fileConcurrency = normalizeFileConcurrency(
|
|
183
|
+
options.fileConcurrency ?? this.options.parquetDataset?.fileConcurrency
|
|
184
|
+
);
|
|
185
|
+
try {
|
|
186
|
+
for await (const filePlan of executeScanTasks(tasks, {
|
|
187
|
+
concurrency: fileConcurrency,
|
|
188
|
+
signal: readContext.abortController.signal
|
|
189
|
+
})) {
|
|
190
|
+
filePlans.push(filePlan);
|
|
191
|
+
}
|
|
192
|
+
const firstFilePlan = filePlans[0];
|
|
193
|
+
if (!firstFilePlan) {
|
|
194
|
+
throw new Error('ParquetDatasetSource query selected no files');
|
|
195
|
+
}
|
|
196
|
+
const effectivePredicate = firstFilePlan.parquet.plan.find(step => step.kind === 'filter');
|
|
197
|
+
const effectiveLimit = options.limit ?? this.options.parquet?.limit;
|
|
198
|
+
const explanation = explainTableQuery(
|
|
199
|
+
firstFilePlan.parquet.sourceColumns,
|
|
200
|
+
{
|
|
201
|
+
columns: firstFilePlan.parquet.outputColumns,
|
|
202
|
+
predicate:
|
|
203
|
+
effectivePredicate?.kind === 'filter' ? effectivePredicate.predicate : undefined,
|
|
204
|
+
limit: effectiveLimit
|
|
205
|
+
},
|
|
206
|
+
PARQUET_TABLE_QUERY_CAPABILITIES
|
|
207
|
+
);
|
|
208
|
+
return Object.freeze({
|
|
209
|
+
...explanation,
|
|
210
|
+
source: 'parquet-dataset' as const,
|
|
211
|
+
files: Object.freeze({...discovery}),
|
|
212
|
+
filePlans: Object.freeze(filePlans)
|
|
213
|
+
});
|
|
214
|
+
} finally {
|
|
215
|
+
readContext.abortController.abort();
|
|
216
|
+
readContext.removeSignalListener();
|
|
217
|
+
this.activeReadControllers.delete(readContext.abortController);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Explains the common logical query and physical multi-file Parquet plan. */
|
|
222
|
+
async explain(options: ParquetDatasetReadOptions = {}): Promise<ParquetDatasetExplain> {
|
|
223
|
+
return await this.getScanPlan(options);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Executes a previously computed dataset plan while retaining each file's row-group choices. */
|
|
227
|
+
async *executeScanPlan(
|
|
228
|
+
plan: ParquetDatasetExplain,
|
|
229
|
+
options: ParquetDatasetReadOptions = {}
|
|
230
|
+
): AsyncIterable<ParquetDatasetBatch> {
|
|
231
|
+
if (plan.source !== 'parquet-dataset') {
|
|
232
|
+
throw new Error('ParquetDatasetSource can only execute dataset scan plans');
|
|
233
|
+
}
|
|
234
|
+
validateTableQueryLimit(options.limit);
|
|
235
|
+
let remainingRows = options.limit ?? this.options.parquet?.limit ?? Number.POSITIVE_INFINITY;
|
|
236
|
+
if (remainingRows === 0) return;
|
|
237
|
+
const limitStep = plan.plan.find(step => step.kind === 'limit');
|
|
238
|
+
const readOptions: ParquetDatasetReadOptions = {
|
|
239
|
+
...options,
|
|
240
|
+
columns: options.columns ?? plan.outputColumns,
|
|
241
|
+
predicate: options.predicate,
|
|
242
|
+
limit: options.limit ?? (limitStep?.kind === 'limit' ? limitStep.limit : undefined)
|
|
243
|
+
};
|
|
244
|
+
remainingRows = readOptions.limit ?? Number.POSITIVE_INFINITY;
|
|
245
|
+
const readContext = createDatasetAbortContext(readOptions.signal);
|
|
246
|
+
this.activeReadControllers.add(readContext.abortController);
|
|
247
|
+
const filePlans = new Map(
|
|
248
|
+
plan.filePlans.map(filePlan => [filePlan.fileIndex, filePlan.parquet])
|
|
249
|
+
);
|
|
250
|
+
const tasks = this.getReadTasks(readOptions, readContext.abortController.signal, filePlans);
|
|
251
|
+
const fileConcurrency = normalizeFileConcurrency(
|
|
252
|
+
readOptions.fileConcurrency ?? this.options.parquetDataset?.fileConcurrency
|
|
253
|
+
);
|
|
254
|
+
try {
|
|
255
|
+
for await (const batch of executeScanTasks(tasks, {
|
|
256
|
+
concurrency: fileConcurrency,
|
|
257
|
+
signal: readContext.abortController.signal
|
|
258
|
+
})) {
|
|
259
|
+
const outputBatch = sliceParquetBatch(batch, Math.min(batch.length, remainingRows));
|
|
260
|
+
this.telemetry.batchesEmitted++;
|
|
261
|
+
this.telemetry.rowsEmitted += outputBatch.length;
|
|
262
|
+
yield outputBatch;
|
|
263
|
+
remainingRows -= outputBatch.length;
|
|
264
|
+
if (remainingRows === 0) return;
|
|
265
|
+
}
|
|
266
|
+
} finally {
|
|
267
|
+
readContext.abortController.abort();
|
|
268
|
+
readContext.removeSignalListener();
|
|
269
|
+
this.activeReadControllers.delete(readContext.abortController);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Common scan-architecture alias for ordered multi-file reads. */
|
|
274
|
+
scan(options: ParquetDatasetReadOptions = {}): AsyncIterable<ParquetDatasetBatch> {
|
|
275
|
+
return this.read(options);
|
|
276
|
+
}
|
|
277
|
+
|
|
124
278
|
/**
|
|
125
279
|
* Reads selected files as deterministic, file-ordered Arrow batches.
|
|
126
280
|
*
|
|
@@ -129,81 +283,79 @@ export class ParquetDatasetSource {
|
|
|
129
283
|
*/
|
|
130
284
|
async *read(options: ParquetDatasetReadOptions = {}): AsyncIterable<ParquetDatasetBatch> {
|
|
131
285
|
this.assertOpen();
|
|
286
|
+
validateTableQueryLimit(options.limit);
|
|
287
|
+
const startedAt = Date.now();
|
|
288
|
+
const telemetryBefore = this.getTelemetry();
|
|
289
|
+
let remainingRows = options.limit ?? this.options.parquet?.limit ?? Number.POSITIVE_INFINITY;
|
|
290
|
+
if (remainingRows === 0) {
|
|
291
|
+
emitScanExecutionTelemetry(
|
|
292
|
+
options.onTelemetry,
|
|
293
|
+
createParquetDatasetScanExecutionTelemetry(
|
|
294
|
+
telemetryBefore,
|
|
295
|
+
this.getTelemetry(),
|
|
296
|
+
startedAt,
|
|
297
|
+
'early-terminated',
|
|
298
|
+
'limit'
|
|
299
|
+
)
|
|
300
|
+
);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
132
303
|
const readContext = createDatasetAbortContext(options.signal);
|
|
133
304
|
this.activeReadControllers.add(readContext.abortController);
|
|
134
|
-
const
|
|
135
|
-
...options,
|
|
136
|
-
signal: readContext.abortController.signal
|
|
137
|
-
});
|
|
138
|
-
const iterator = selectedFiles[Symbol.asyncIterator]();
|
|
139
|
-
const scheduledReads = new Map<number, ScheduledFileRead>();
|
|
140
|
-
let nextSchedulePosition = 0;
|
|
141
|
-
let nextYieldPosition = 0;
|
|
142
|
-
let providerComplete = false;
|
|
143
|
-
let discoveryError: unknown;
|
|
305
|
+
const tasks = this.getReadTasks(options, readContext.abortController.signal);
|
|
144
306
|
const fileConcurrency = normalizeFileConcurrency(
|
|
145
307
|
options.fileConcurrency ?? this.options.parquetDataset?.fileConcurrency
|
|
146
308
|
);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
const next = await iterator.next();
|
|
153
|
-
if (next.done) {
|
|
154
|
-
providerComplete = true;
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
const position = nextSchedulePosition++;
|
|
158
|
-
const queue = new SingleBatchQueue<ParquetDatasetBatch>();
|
|
159
|
-
const task = this.readFile(next.value, options, queue, readContext.abortController.signal);
|
|
160
|
-
scheduledReads.set(position, {queue, task});
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
const fillAvailableSlots = async (): Promise<void> => {
|
|
164
|
-
try {
|
|
165
|
-
while (scheduledReads.size < fileConcurrency && !providerComplete) {
|
|
166
|
-
await scheduleNext();
|
|
167
|
-
}
|
|
168
|
-
} catch (error) {
|
|
169
|
-
discoveryError = error;
|
|
170
|
-
providerComplete = true;
|
|
171
|
-
}
|
|
172
|
-
};
|
|
309
|
+
let completed = false;
|
|
310
|
+
let limitReached = false;
|
|
311
|
+
let readError: unknown;
|
|
173
312
|
|
|
174
313
|
try {
|
|
175
|
-
await
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
yield batch;
|
|
188
|
-
}
|
|
189
|
-
await scheduledRead.task;
|
|
190
|
-
scheduledReads.delete(nextYieldPosition++);
|
|
191
|
-
await discoveryPromise;
|
|
192
|
-
if (discoveryError !== undefined) {
|
|
193
|
-
throw discoveryError;
|
|
314
|
+
for await (const batch of executeScanTasks(tasks, {
|
|
315
|
+
concurrency: fileConcurrency,
|
|
316
|
+
signal: readContext.abortController.signal
|
|
317
|
+
})) {
|
|
318
|
+
const outputBatch = sliceParquetBatch(batch, Math.min(batch.length, remainingRows));
|
|
319
|
+
this.telemetry.batchesEmitted++;
|
|
320
|
+
this.telemetry.rowsEmitted += outputBatch.length;
|
|
321
|
+
yield outputBatch;
|
|
322
|
+
remainingRows -= outputBatch.length;
|
|
323
|
+
if (remainingRows === 0) {
|
|
324
|
+
limitReached = true;
|
|
325
|
+
return;
|
|
194
326
|
}
|
|
195
|
-
discoveryPromise = fillAvailableSlots();
|
|
196
|
-
}
|
|
197
|
-
await discoveryPromise;
|
|
198
|
-
if (discoveryError !== undefined) {
|
|
199
|
-
throw discoveryError;
|
|
200
327
|
}
|
|
328
|
+
completed = true;
|
|
329
|
+
} catch (error) {
|
|
330
|
+
readError = error;
|
|
331
|
+
throw error;
|
|
201
332
|
} finally {
|
|
333
|
+
const cancelled = readContext.abortController.signal.aborted || options.signal?.aborted;
|
|
202
334
|
readContext.abortController.abort();
|
|
203
335
|
readContext.removeSignalListener();
|
|
204
336
|
this.activeReadControllers.delete(readContext.abortController);
|
|
205
|
-
|
|
206
|
-
|
|
337
|
+
const status: ScanExecutionTelemetry['status'] = readError
|
|
338
|
+
? cancelled
|
|
339
|
+
? 'cancelled'
|
|
340
|
+
: 'failed'
|
|
341
|
+
: limitReached || !completed
|
|
342
|
+
? 'early-terminated'
|
|
343
|
+
: 'completed';
|
|
344
|
+
emitScanExecutionTelemetry(
|
|
345
|
+
options.onTelemetry,
|
|
346
|
+
createParquetDatasetScanExecutionTelemetry(
|
|
347
|
+
telemetryBefore,
|
|
348
|
+
this.getTelemetry(),
|
|
349
|
+
startedAt,
|
|
350
|
+
status,
|
|
351
|
+
limitReached
|
|
352
|
+
? 'limit'
|
|
353
|
+
: !completed && readError === undefined
|
|
354
|
+
? 'consumer-return'
|
|
355
|
+
: undefined,
|
|
356
|
+
readError
|
|
357
|
+
)
|
|
358
|
+
);
|
|
207
359
|
}
|
|
208
360
|
}
|
|
209
361
|
|
|
@@ -219,12 +371,75 @@ export class ParquetDatasetSource {
|
|
|
219
371
|
}
|
|
220
372
|
|
|
221
373
|
/** Reads one child source into its bounded file-order queue. */
|
|
222
|
-
private async
|
|
374
|
+
private async *getReadTasks(
|
|
375
|
+
options: ParquetDatasetReadOptions,
|
|
376
|
+
signal: AbortSignal,
|
|
377
|
+
filePlans?: ReadonlyMap<number, ParquetSourceExplain>
|
|
378
|
+
): AsyncIterable<ScanTask<ParquetDatasetBatch>> {
|
|
379
|
+
const selectedFiles = this.getSelectedFiles({...options, signal});
|
|
380
|
+
for await (const indexedFile of selectedFiles) {
|
|
381
|
+
if (filePlans && !filePlans.has(indexedFile.index)) {
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
yield {
|
|
385
|
+
run: taskSignal =>
|
|
386
|
+
this.readFile(indexedFile, options, taskSignal, filePlans?.get(indexedFile.index))
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** Plans retained files through bounded, ordered common scan tasks. */
|
|
392
|
+
private async *getPlanTasks(
|
|
393
|
+
options: ParquetDatasetReadOptions,
|
|
394
|
+
signal: AbortSignal,
|
|
395
|
+
discovery: ParquetDatasetDiscoverySummary
|
|
396
|
+
): AsyncIterable<ScanTask<ParquetDatasetFileScanPlan>> {
|
|
397
|
+
const selectedFiles = this.getSelectedFiles({...options, signal}, discovery);
|
|
398
|
+
for await (const indexedFile of selectedFiles) {
|
|
399
|
+
yield {run: taskSignal => this.planFile(indexedFile, options, taskSignal)};
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/** Produces one child physical plan and closes its temporary source. */
|
|
404
|
+
private async *planFile(
|
|
223
405
|
indexedFile: IndexedParquetDatasetFile,
|
|
224
406
|
options: ParquetDatasetReadOptions,
|
|
225
|
-
queue: SingleBatchQueue<ParquetDatasetBatch>,
|
|
226
407
|
signal: AbortSignal
|
|
227
|
-
):
|
|
408
|
+
): AsyncIterable<ParquetDatasetFileScanPlan> {
|
|
409
|
+
const source = this.createSource(indexedFile.file);
|
|
410
|
+
this.telemetry.filesOpened++;
|
|
411
|
+
try {
|
|
412
|
+
if (this.options.parquetDataset?.validateSchema !== false) {
|
|
413
|
+
await this.validateFileSchema(source, indexedFile, signal);
|
|
414
|
+
}
|
|
415
|
+
const parquet = await source.getScanPlan({
|
|
416
|
+
columns: options.columns,
|
|
417
|
+
predicate: options.predicate,
|
|
418
|
+
bbox: options.bbox,
|
|
419
|
+
geometryColumn: options.geometryColumn,
|
|
420
|
+
rowGroupFilter: options.rowGroupFilter,
|
|
421
|
+
limit: undefined,
|
|
422
|
+
signal
|
|
423
|
+
});
|
|
424
|
+
yield Object.freeze({
|
|
425
|
+
fileIndex: indexedFile.index,
|
|
426
|
+
fileId: getDatasetFileId(indexedFile.file, indexedFile.index),
|
|
427
|
+
partitions: indexedFile.file.partitions,
|
|
428
|
+
parquet
|
|
429
|
+
});
|
|
430
|
+
} finally {
|
|
431
|
+
await source.close();
|
|
432
|
+
this.addParquetTelemetry(source.getTelemetry());
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** Reads one child source as an asynchronous batch iterable. */
|
|
437
|
+
private async *readFile(
|
|
438
|
+
indexedFile: IndexedParquetDatasetFile,
|
|
439
|
+
options: ParquetDatasetReadOptions,
|
|
440
|
+
signal: AbortSignal,
|
|
441
|
+
scanPlan?: ParquetSourceExplain
|
|
442
|
+
): AsyncIterable<ParquetDatasetBatch> {
|
|
228
443
|
const source = this.createSource(indexedFile.file);
|
|
229
444
|
this.telemetry.filesOpened++;
|
|
230
445
|
try {
|
|
@@ -235,15 +450,18 @@ export class ParquetDatasetSource {
|
|
|
235
450
|
columns: options.columns,
|
|
236
451
|
batchSize: options.batchSize,
|
|
237
452
|
concurrency: options.concurrency,
|
|
453
|
+
rowGroups: scanPlan?.rowGroups.indices,
|
|
238
454
|
rowGroupFilter: options.rowGroupFilter,
|
|
239
|
-
predicate: options.predicate,
|
|
455
|
+
predicate: options.predicate ?? (!options.bbox ? getPlanPredicate(scanPlan) : undefined),
|
|
456
|
+
bbox: options.bbox,
|
|
457
|
+
geometryColumn: options.geometryColumn,
|
|
458
|
+
limit: undefined,
|
|
240
459
|
signal
|
|
241
460
|
})) {
|
|
242
|
-
|
|
461
|
+
yield createDatasetBatch(batch, indexedFile);
|
|
243
462
|
}
|
|
244
|
-
queue.finish();
|
|
245
463
|
} catch (error) {
|
|
246
|
-
|
|
464
|
+
throw error;
|
|
247
465
|
} finally {
|
|
248
466
|
await source.close();
|
|
249
467
|
this.addParquetTelemetry(source.getTelemetry());
|
|
@@ -275,12 +493,16 @@ export class ParquetDatasetSource {
|
|
|
275
493
|
|
|
276
494
|
/** Creates a child source while preserving caller fetch, worker, range, and decode options. */
|
|
277
495
|
private createSource(file: ParquetDatasetFile): ParquetSource {
|
|
278
|
-
|
|
496
|
+
const parquetOptions = this.options.parquet
|
|
497
|
+
? {...this.options.parquet, limit: undefined}
|
|
498
|
+
: undefined;
|
|
499
|
+
return new ParquetSource(file.data, {...this.options, parquet: parquetOptions}, this.coreApi);
|
|
279
500
|
}
|
|
280
501
|
|
|
281
502
|
/** Lazily discovers descriptors and applies conservative local pruning. */
|
|
282
503
|
private async *getSelectedFiles(
|
|
283
|
-
query: ParquetDatasetFileQuery
|
|
504
|
+
query: ParquetDatasetFileQuery,
|
|
505
|
+
discovery?: ParquetDatasetDiscoverySummary
|
|
284
506
|
): AsyncIterable<IndexedParquetDatasetFile> {
|
|
285
507
|
throwIfAborted(query.signal);
|
|
286
508
|
const collection = await getFileCollection(this.files, query);
|
|
@@ -289,17 +511,21 @@ export class ParquetDatasetSource {
|
|
|
289
511
|
throwIfAborted(query.signal);
|
|
290
512
|
validateDatasetFile(file, index);
|
|
291
513
|
this.telemetry.filesDiscovered++;
|
|
514
|
+
if (discovery) discovery.discovered++;
|
|
292
515
|
if (query.bbox && file.bbox && !doBoundingBoxesIntersect(query.bbox, file.bbox)) {
|
|
293
516
|
this.telemetry.filesPrunedByBoundingBox++;
|
|
517
|
+
if (discovery) discovery.prunedByBoundingBox++;
|
|
294
518
|
index++;
|
|
295
519
|
continue;
|
|
296
520
|
}
|
|
297
521
|
if (query.partitions && !matchesPartitions(file.partitions, query.partitions)) {
|
|
298
522
|
this.telemetry.filesPrunedByPartitions++;
|
|
523
|
+
if (discovery) discovery.prunedByPartitions++;
|
|
299
524
|
index++;
|
|
300
525
|
continue;
|
|
301
526
|
}
|
|
302
527
|
this.telemetry.filesSelected++;
|
|
528
|
+
if (discovery) discovery.selected++;
|
|
303
529
|
yield {file, index: index++};
|
|
304
530
|
}
|
|
305
531
|
}
|
|
@@ -319,6 +545,11 @@ export class ParquetDatasetSource {
|
|
|
319
545
|
}
|
|
320
546
|
}
|
|
321
547
|
|
|
548
|
+
/** Creates operation-local descriptor discovery counters. */
|
|
549
|
+
function createParquetDatasetDiscoverySummary(): ParquetDatasetDiscoverySummary {
|
|
550
|
+
return {discovered: 0, selected: 0, prunedByBoundingBox: 0, prunedByPartitions: 0};
|
|
551
|
+
}
|
|
552
|
+
|
|
322
553
|
/** Normalizes static descriptors and lazy providers into one file collection. */
|
|
323
554
|
async function getFileCollection(
|
|
324
555
|
files: ParquetDatasetFiles,
|
|
@@ -353,6 +584,12 @@ function createDatasetBatch(
|
|
|
353
584
|
return {...batch, metadata: provenance, ...datasetProvenance};
|
|
354
585
|
}
|
|
355
586
|
|
|
587
|
+
/** Returns the filter predicate recorded in one child source plan. */
|
|
588
|
+
function getPlanPredicate(plan: ParquetSourceExplain | undefined): ParquetPredicate | undefined {
|
|
589
|
+
const filter = plan?.plan.find(step => step.kind === 'filter');
|
|
590
|
+
return filter?.kind === 'filter' ? filter.predicate : undefined;
|
|
591
|
+
}
|
|
592
|
+
|
|
356
593
|
/** Returns a stable descriptor identity for batch provenance and diagnostics. */
|
|
357
594
|
function getDatasetFileId(file: ParquetDatasetFile, index: number): string {
|
|
358
595
|
if (file.id) {
|
|
@@ -378,18 +615,43 @@ function doBoundingBoxesIntersect(
|
|
|
378
615
|
left: ParquetDatasetBoundingBox,
|
|
379
616
|
right: ParquetDatasetBoundingBox
|
|
380
617
|
): boolean {
|
|
381
|
-
const leftMaximumX = left.length === 6 ? left[3] : left[2];
|
|
382
|
-
const leftMaximumY = left.length === 6 ? left[4] : left[3];
|
|
383
|
-
const rightMaximumX = right.length === 6 ? right[3] : right[2];
|
|
384
|
-
const rightMaximumY = right.length === 6 ? right[4] : right[3];
|
|
618
|
+
const leftMaximumX = left.length === 8 ? left[4] : left.length === 6 ? left[3] : left[2];
|
|
619
|
+
const leftMaximumY = left.length === 8 ? left[5] : left.length === 6 ? left[4] : left[3];
|
|
620
|
+
const rightMaximumX = right.length === 8 ? right[4] : right.length === 6 ? right[3] : right[2];
|
|
621
|
+
const rightMaximumY = right.length === 8 ? right[5] : right.length === 6 ? right[4] : right[3];
|
|
385
622
|
return (
|
|
386
|
-
left[0]
|
|
387
|
-
leftMaximumX >= right[0] &&
|
|
623
|
+
doLongitudeIntervalsIntersect(left[0], leftMaximumX, right[0], rightMaximumX) &&
|
|
388
624
|
left[1] <= rightMaximumY &&
|
|
389
625
|
leftMaximumY >= right[1]
|
|
390
626
|
);
|
|
391
627
|
}
|
|
392
628
|
|
|
629
|
+
/** Tests longitude intervals that may use RFC 7946 antimeridian wrapping. */
|
|
630
|
+
function doLongitudeIntervalsIntersect(
|
|
631
|
+
firstWest: number,
|
|
632
|
+
firstEast: number,
|
|
633
|
+
secondWest: number,
|
|
634
|
+
secondEast: number
|
|
635
|
+
): boolean {
|
|
636
|
+
const firstIntervals =
|
|
637
|
+
firstWest <= firstEast
|
|
638
|
+
? [[firstWest, firstEast]]
|
|
639
|
+
: [
|
|
640
|
+
[firstWest, 180],
|
|
641
|
+
[-180, firstEast]
|
|
642
|
+
];
|
|
643
|
+
const secondIntervals =
|
|
644
|
+
secondWest <= secondEast
|
|
645
|
+
? [[secondWest, secondEast]]
|
|
646
|
+
: [
|
|
647
|
+
[secondWest, 180],
|
|
648
|
+
[-180, secondEast]
|
|
649
|
+
];
|
|
650
|
+
return firstIntervals.some(first =>
|
|
651
|
+
secondIntervals.some(second => first[0] <= second[1] && first[1] >= second[0])
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
|
|
393
655
|
/** Tests exact partition constraints without rejecting files that omit a requested key. */
|
|
394
656
|
function matchesPartitions(
|
|
395
657
|
partitions: Readonly<Record<string, ParquetDatasetPartitionValue>> | undefined,
|
|
@@ -471,6 +733,9 @@ function createParquetDatasetTelemetry(): ParquetDatasetTelemetry {
|
|
|
471
733
|
rowGroupsRequested: 0,
|
|
472
734
|
rowGroupsPruned: 0,
|
|
473
735
|
rowGroupsPrunedByStatistics: 0,
|
|
736
|
+
rowGroupsPrunedByBloomFilter: 0,
|
|
737
|
+
bloomFiltersRead: 0,
|
|
738
|
+
bloomFilterBytesRead: 0,
|
|
474
739
|
rowGroupsPrunedByPageIndex: 0,
|
|
475
740
|
pageIndexesRead: 0,
|
|
476
741
|
pagesRead: 0,
|
|
@@ -486,3 +751,50 @@ function createParquetDatasetTelemetry(): ParquetDatasetTelemetry {
|
|
|
486
751
|
}
|
|
487
752
|
};
|
|
488
753
|
}
|
|
754
|
+
|
|
755
|
+
/** Converts cumulative dataset and child counters into one portable read-scoped snapshot. */
|
|
756
|
+
function createParquetDatasetScanExecutionTelemetry(
|
|
757
|
+
before: ParquetDatasetTelemetry,
|
|
758
|
+
after: ParquetDatasetTelemetry,
|
|
759
|
+
startedAt: number,
|
|
760
|
+
status: ScanExecutionTelemetry['status'],
|
|
761
|
+
earlyTerminationReason?: ScanExecutionTelemetry['earlyTerminationReason'],
|
|
762
|
+
error?: unknown
|
|
763
|
+
): ScanExecutionTelemetry {
|
|
764
|
+
const parquet = Object.fromEntries(
|
|
765
|
+
Object.keys(after.parquet).map(key => {
|
|
766
|
+
const telemetryKey = key as keyof ParquetTelemetry;
|
|
767
|
+
return [key, after.parquet[telemetryKey] - before.parquet[telemetryKey]];
|
|
768
|
+
})
|
|
769
|
+
) as ParquetTelemetry;
|
|
770
|
+
const dataset = Object.freeze({
|
|
771
|
+
filesDiscovered: after.filesDiscovered - before.filesDiscovered,
|
|
772
|
+
filesSelected: after.filesSelected - before.filesSelected,
|
|
773
|
+
filesPrunedByBoundingBox: after.filesPrunedByBoundingBox - before.filesPrunedByBoundingBox,
|
|
774
|
+
filesPrunedByPartitions: after.filesPrunedByPartitions - before.filesPrunedByPartitions,
|
|
775
|
+
filesOpened: after.filesOpened - before.filesOpened,
|
|
776
|
+
batchesEmitted: after.batchesEmitted - before.batchesEmitted,
|
|
777
|
+
rowsEmitted: after.rowsEmitted - before.rowsEmitted
|
|
778
|
+
});
|
|
779
|
+
const rowsRead = Math.max(parquet.predicateRowsTested, parquet.rowsEmitted, dataset.rowsEmitted);
|
|
780
|
+
return Object.freeze({
|
|
781
|
+
status,
|
|
782
|
+
sourcesPlanned: Math.max(dataset.filesSelected, dataset.filesOpened),
|
|
783
|
+
sourcesRead: dataset.filesOpened,
|
|
784
|
+
batchesRead: dataset.batchesEmitted,
|
|
785
|
+
batchesDecoded: parquet.rowGroupsDecoded,
|
|
786
|
+
rowsRead,
|
|
787
|
+
rowsTested: parquet.predicateRowsTested || undefined,
|
|
788
|
+
rowsRetained: parquet.predicateRowsMatched || undefined,
|
|
789
|
+
rowsReturned: dataset.rowsEmitted,
|
|
790
|
+
bytesRead: parquet.downloadedBytes,
|
|
791
|
+
bytesFetched: parquet.downloadedBytes,
|
|
792
|
+
filesOpened: dataset.filesOpened,
|
|
793
|
+
tasksOpened: parquet.rowGroupsDecoded,
|
|
794
|
+
rowsPruned: parquet.rowsPrunedByPageIndex,
|
|
795
|
+
durationMilliseconds: Date.now() - startedAt,
|
|
796
|
+
earlyTerminationReason,
|
|
797
|
+
details: Object.freeze({dataset, parquet: Object.freeze({...parquet})}),
|
|
798
|
+
...(error === undefined ? {} : {error})
|
|
799
|
+
});
|
|
800
|
+
}
|
package/src/parquet-js-loader.ts
CHANGED
|
@@ -25,7 +25,8 @@ const {preload: _ParquetJSLoaderPreload, ...ParquetJSLoaderMetadataWithoutPreloa
|
|
|
25
25
|
/** Default option bag for the experimental parquetjs plain-row loader. */
|
|
26
26
|
const DEFAULT_PARQUET_JS_OPTIONS = {
|
|
27
27
|
columns: undefined,
|
|
28
|
-
preserveBinary: false
|
|
28
|
+
preserveBinary: false,
|
|
29
|
+
verifyFooterSignature: true
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
/** Parser-bearing TypeScript-only Parquet loader implementation. */
|