parquet 0.7.3-aarch64-linux → 0.9.0-aarch64-linux
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.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +134 -6
- data/lib/parquet/3.2/parquet.so +0 -0
- data/lib/parquet/3.3/parquet.so +0 -0
- data/lib/parquet/3.4/parquet.so +0 -0
- data/lib/parquet/4.0/parquet.so +0 -0
- data/lib/parquet/schema.rb +6 -2
- data/lib/parquet/version.rb +1 -1
- data/lib/parquet.rbi +115 -16
- metadata +18 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 06deeee590e4572ff7d4b302597e26804ca0a7dc4a8eccfd7687f926276a5ef7
|
|
4
|
+
data.tar.gz: 5514690113ee28379aa505d49ee88cd0e806ad8f4fb7e442c3ffef6e0d36305c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e68aced5c5b45ae7dbcd5f3b8215817c10a0cc72379044523895870e3e164a4212fd24d34b9eca9e7913d3f6ff8f43c040ac3d3094a0af955b4353a710db38e2
|
|
7
|
+
data.tar.gz: 44998090036e3de92c39f2418ccb68369564209e2a3d165405fa56e14d96b1b283aa3e3980cd5880c861e578b1fb90f0332412ee472669e09ad5f2256af11d6c
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -145,6 +145,33 @@ puts metadata["row_groups"].size # Number of row groups
|
|
|
145
145
|
|
|
146
146
|
## Writing Parquet Files
|
|
147
147
|
|
|
148
|
+
`write_rows` and `write_columns` stream an enumerable to a path or writable IO
|
|
149
|
+
and return `nil`. Each row is an array in schema order. For column writing, each
|
|
150
|
+
yielded batch contains one array per field, all of the same length.
|
|
151
|
+
|
|
152
|
+
Both methods require `schema:` and `write_to:`. `schema:` accepts the array form
|
|
153
|
+
shown below, a `Parquet::Schema` DSL result, or a `fields` schema hash. Use `nil`
|
|
154
|
+
or `[]` to infer string columns named `f0`, `f1`, ... from the first row or
|
|
155
|
+
batch. Empty input requires an explicit schema.
|
|
156
|
+
|
|
157
|
+
`compression:` accepts `"none"`, `"uncompressed"`, `"snappy"`, `"gzip"`,
|
|
158
|
+
`"lz4"`, `"zstd"`, and `"brotli"`; `nil` defaults to Snappy.
|
|
159
|
+
`flush_threshold:` defaults to 100 MiB. `logger:` accepts a Ruby logger with
|
|
160
|
+
`debug`, `info`, `warn`, and `error` methods.
|
|
161
|
+
|
|
162
|
+
`write_rows` also accepts `batch_size:`, `sample_size:`, and `string_cache:`.
|
|
163
|
+
Without `batch_size:`, sizing starts at 1,000 rows and adapts to row size; the
|
|
164
|
+
cap is 1,000,000 rows and lower for wide schemas. Sampling defaults to 100 rows
|
|
165
|
+
and is capped at 10,000. `string_cache: true` uses a capacity of 100, or you can
|
|
166
|
+
pass a capacity up to 65,536; `nil` and `false` disable it.
|
|
167
|
+
|
|
168
|
+
Path output is staged and atomically published only after the complete file has
|
|
169
|
+
been written. On Unix, replacing an existing path preserves its uid, gid, and
|
|
170
|
+
mode and uses standard last-committer-wins rename semantics; creating a path is
|
|
171
|
+
no-clobber. Extended attributes and ACLs are not preserved. IO output is first
|
|
172
|
+
staged on disk, then copied to the IO; a failed copy may leave the IO partially
|
|
173
|
+
written.
|
|
174
|
+
|
|
148
175
|
### Row-wise Writing
|
|
149
176
|
|
|
150
177
|
Best for: Streaming data, converting from other formats, memory-constrained environments
|
|
@@ -159,17 +186,109 @@ schema = [
|
|
|
159
186
|
]
|
|
160
187
|
|
|
161
188
|
# Stream data from any enumerable
|
|
162
|
-
rows = CSV.foreach("input.csv").map do |row|
|
|
189
|
+
rows = CSV.foreach("input.csv").lazy.map do |row|
|
|
163
190
|
[row[0].to_i, row[1], row[2] == "true", row[3].to_f]
|
|
164
191
|
end
|
|
165
192
|
|
|
166
193
|
Parquet.write_rows(rows,
|
|
167
194
|
schema: schema,
|
|
168
195
|
write_to: "output.parquet",
|
|
169
|
-
batch_size: 5000
|
|
196
|
+
batch_size: 5000
|
|
197
|
+
)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Repacking Existing Parquet Files
|
|
201
|
+
|
|
202
|
+
Concatenate Parquet files and re-split them into differently sized files without
|
|
203
|
+
translating rows through Ruby.
|
|
204
|
+
|
|
205
|
+
```ruby
|
|
206
|
+
Parquet.repack(
|
|
207
|
+
["input-0.parquet", "input-1.parquet"],
|
|
208
|
+
output_dir: "repacked",
|
|
209
|
+
rows_per_file: 100_000
|
|
170
210
|
)
|
|
211
|
+
# => [{ "path" => "repacked/batch-0.parquet", "num_rows" => 100_000 },
|
|
212
|
+
# { "path" => "repacked/batch-1.parquet", "num_rows" => 42_137 }]
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The outputs hold exactly the input rows, in input order. Every output but the
|
|
216
|
+
last holds `rows_per_file` rows, and there is always at least one output even
|
|
217
|
+
when the inputs are empty. Omit `rows_per_file:` to concatenate everything into
|
|
218
|
+
a single file.
|
|
219
|
+
|
|
220
|
+
Each output's Parquet schema is identical to the first input's, and that input's
|
|
221
|
+
file-level key/value metadata (`ARROW:schema`, `pandas`, and so on) is carried
|
|
222
|
+
over. Inputs must agree on leaf column shape — path, physical and logical type,
|
|
223
|
+
nesting — but may differ in key/value metadata and Parquet field ids.
|
|
224
|
+
|
|
225
|
+
#### Compression and copying
|
|
226
|
+
|
|
227
|
+
With no `compression:`, each column keeps its own codec — Parquet records one
|
|
228
|
+
per column, and a file may legitimately use several. Naming a codec applies it
|
|
229
|
+
to every column instead:
|
|
230
|
+
|
|
231
|
+
```ruby
|
|
232
|
+
Parquet.repack("input.parquet", output_dir: "out", compression: "zstd")
|
|
171
233
|
```
|
|
172
234
|
|
|
235
|
+
Keeping the inputs' codecs also lets repack copy whole row groups into the
|
|
236
|
+
output byte-for-byte, skipping decompression and re-encoding entirely. A row
|
|
237
|
+
group is copied when it fits the output's remaining row budget, is large enough
|
|
238
|
+
to be worth copying, and the request did not ask for a different codec;
|
|
239
|
+
otherwise its rows are decoded and re-encoded. Both routes produce the same
|
|
240
|
+
rows, so which one runs is not something callers need to reason about — but the
|
|
241
|
+
copy route is dramatically faster, so a plain concatenation is close to an
|
|
242
|
+
I/O-bound copy.
|
|
243
|
+
|
|
244
|
+
Small row groups are deliberately merged rather than copied: copying them
|
|
245
|
+
one-for-one would make a compaction of many small files reproduce exactly the
|
|
246
|
+
fragmentation it was meant to remove.
|
|
247
|
+
|
|
248
|
+
#### Output directory ownership
|
|
249
|
+
|
|
250
|
+
`repack` owns the `{output_file_prefix}-{n}.parquet` names in `output_dir`. If
|
|
251
|
+
any already exist it raises `ArgumentError` rather than mixing two runs' files
|
|
252
|
+
in one directory:
|
|
253
|
+
|
|
254
|
+
```ruby
|
|
255
|
+
Parquet.repack("input.parquet", output_dir: "out", rows_per_file: 1000, overwrite: true)
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`overwrite: true` replaces that set and deletes members left over from a longer
|
|
259
|
+
earlier run, so the returned list always equals what a reader finds in the
|
|
260
|
+
directory. Files outside the set are never touched.
|
|
261
|
+
|
|
262
|
+
#### Bounds
|
|
263
|
+
|
|
264
|
+
`max_read_rows_per_chunk:` (default 8192, reduced for wide schemas) bounds rows
|
|
265
|
+
buffered while reading; output row groups are bounded in rows by the same slot
|
|
266
|
+
budget. Both are resource controls: varying them cannot change the returned
|
|
267
|
+
list, the rows, the schema, or the codecs. They do shift compressed byte counts
|
|
268
|
+
and page boundaries, which are representation rather than contract.
|
|
269
|
+
|
|
270
|
+
Input metadata is read one file at a time, so peak memory is set by the widest
|
|
271
|
+
single file and its row-group size, not by how many files you pass or how many
|
|
272
|
+
rows they hold in total. Note that the row-group bound is in rows, not bytes: a
|
|
273
|
+
schema with very large values still buffers one row group's worth of encoded
|
|
274
|
+
data.
|
|
275
|
+
|
|
276
|
+
Reading and writing run with the GVL released, so other Ruby threads keep
|
|
277
|
+
running and `Interrupt` / `Timeout` are honoured. An interrupted call leaves no
|
|
278
|
+
output behind.
|
|
279
|
+
|
|
280
|
+
A repacked output is capped at 32,767 row groups. Merging small groups keeps
|
|
281
|
+
that limit out of reach in practice; if a single output would exceed it,
|
|
282
|
+
repack raises rather than writing an unreadable file, and `rows_per_file:` is
|
|
283
|
+
the way out.
|
|
284
|
+
|
|
285
|
+
#### Page indexes and other optional structures
|
|
286
|
+
|
|
287
|
+
Every row group in a Parquet file must agree on whether it carries a page index,
|
|
288
|
+
and a copied row group can only contribute the index its source had. So an
|
|
289
|
+
output carries one exactly when every contributing input does. Bloom filters are
|
|
290
|
+
not carried over on either route.
|
|
291
|
+
|
|
173
292
|
### Column-wise Writing
|
|
174
293
|
|
|
175
294
|
Best for: Pre-columnar data, better compression, higher performance
|
|
@@ -196,7 +315,7 @@ schema = [
|
|
|
196
315
|
Parquet.write_columns(batches.each,
|
|
197
316
|
schema: schema,
|
|
198
317
|
write_to: "output.parquet",
|
|
199
|
-
compression: "snappy"
|
|
318
|
+
compression: "snappy"
|
|
200
319
|
)
|
|
201
320
|
```
|
|
202
321
|
|
|
@@ -340,7 +459,7 @@ Parquet.write_rows(data.each, schema: schema, write_to: "complex.parquet")
|
|
|
340
459
|
|
|
341
460
|
### Timezone Handling in Parquet
|
|
342
461
|
|
|
343
|
-
|
|
462
|
+
The Parquet specification has a fundamental limitation with timezone storage:
|
|
344
463
|
|
|
345
464
|
1. **UTC-normalized**: Any timestamp with timezone info (including "+09:00" or "America/New_York") is converted to UTC
|
|
346
465
|
2. **Local/unzoned**: Timestamps without timezone info are stored as-is
|
|
@@ -382,11 +501,20 @@ Control memory usage with flush thresholds:
|
|
|
382
501
|
Parquet.write_rows(huge_dataset.each,
|
|
383
502
|
schema: schema,
|
|
384
503
|
write_to: "output.parquet",
|
|
385
|
-
batch_size:
|
|
386
|
-
flush_threshold: 32 * 1024**2
|
|
504
|
+
batch_size: 1_000,
|
|
505
|
+
flush_threshold: 32 * 1024**2 # 32 MiB
|
|
387
506
|
)
|
|
388
507
|
```
|
|
389
508
|
|
|
509
|
+
Writer-owned memory stays bounded as the file grows. `flush_threshold` controls
|
|
510
|
+
the converted-value buffer; a single larger row may exceed it temporarily. The
|
|
511
|
+
row-group target is at least 8 MiB, and each file may contain up to 32,768 row
|
|
512
|
+
groups.
|
|
513
|
+
|
|
514
|
+
Encoded data and completed row-group metadata are staged on disk, so large
|
|
515
|
+
writes need temporary disk space. Ruby still owns the current row or batch, and
|
|
516
|
+
an in-memory destination such as `StringIO` holds the output in memory.
|
|
517
|
+
|
|
390
518
|
## Architecture
|
|
391
519
|
|
|
392
520
|
This gem uses a modular architecture:
|
data/lib/parquet/3.2/parquet.so
CHANGED
|
Binary file
|
data/lib/parquet/3.3/parquet.so
CHANGED
|
Binary file
|
data/lib/parquet/3.4/parquet.so
CHANGED
|
Binary file
|
|
Binary file
|
data/lib/parquet/schema.rb
CHANGED
|
@@ -116,8 +116,12 @@ module Parquet
|
|
|
116
116
|
key_type = kwargs[:key]
|
|
117
117
|
value_type = kwargs[:value]
|
|
118
118
|
raise ArgumentError, "map field `#{name}` requires `key:` and `value:`" if key_type.nil? || value_type.nil?
|
|
119
|
-
#
|
|
120
|
-
|
|
119
|
+
# Map keys are required by the Parquet spec. Reject an explicit nullable
|
|
120
|
+
# key at this boundary rather than letting it fail deep in the writer.
|
|
121
|
+
if kwargs[:key_nullable]
|
|
122
|
+
raise ArgumentError, "map field `#{name}` keys are always required; remove `key_nullable: true`"
|
|
123
|
+
end
|
|
124
|
+
key_nullable = false
|
|
121
125
|
value_nullable = kwargs[:value_nullable].nil? ? true : !!kwargs[:value_nullable]
|
|
122
126
|
|
|
123
127
|
field_hash[:key] = wrap_subtype(key_type, nullable: key_nullable)
|
data/lib/parquet/version.rb
CHANGED
data/lib/parquet.rbi
CHANGED
|
@@ -18,12 +18,29 @@ module Parquet
|
|
|
18
18
|
# ("hash" or "array" or :hash or :array)
|
|
19
19
|
# - `columns`: When present, only the specified columns will be included in the output.
|
|
20
20
|
# This is useful for reducing how much data is read and improving performance.
|
|
21
|
+
# - `string_storage`: How string *values* become Ruby strings (default `:copy`). Hash keys
|
|
22
|
+
# (struct field names and top-level column names) are always interned and
|
|
23
|
+
# reused regardless of this setting.
|
|
24
|
+
# - `:copy` allocates a fresh mutable String per value.
|
|
25
|
+
# - `:intern` deduplicates low-cardinality equal values into frozen interned
|
|
26
|
+
# Strings up to a bounded per-read cache, then falls back to frozen copies.
|
|
27
|
+
# A transient copy still happens per value, so it is not a per-value speedup.
|
|
28
|
+
# - `:shared` returns frozen, zero-copy strings backed by Rust memory for
|
|
29
|
+
# short, repeated, low-cardinality values. Each read returns at most the
|
|
30
|
+
# configured number of shared values and only values up to the configured
|
|
31
|
+
# byte size; values past those bounds become frozen copies. New process-wide
|
|
32
|
+
# leaks are also capped by the requested budget and hard process ceilings.
|
|
33
|
+
# All `:shared` results are frozen. Not recommended for high-cardinality or
|
|
34
|
+
# large-blob string columns.
|
|
35
|
+
# Pass a hash to set the `:shared` leak budget, e.g.
|
|
36
|
+
# `{ mode: :shared, max_entries: 16_384, max_value_bytes: 1024 }`.
|
|
21
37
|
sig do
|
|
22
38
|
params(
|
|
23
39
|
input: T.any(String, File, StringIO, IO),
|
|
24
40
|
result_type: T.nilable(T.any(String, Symbol)),
|
|
25
41
|
columns: T.nilable(T::Array[String]),
|
|
26
|
-
strict: T.nilable(T::Boolean)
|
|
42
|
+
strict: T.nilable(T::Boolean),
|
|
43
|
+
string_storage: T.nilable(T.any(String, Symbol, T::Hash[Symbol, T.untyped]))
|
|
27
44
|
).returns(T::Enumerator[T.any(T::Hash[String, T.untyped], T::Array[T.untyped])])
|
|
28
45
|
end
|
|
29
46
|
sig do
|
|
@@ -32,10 +49,11 @@ module Parquet
|
|
|
32
49
|
result_type: T.nilable(T.any(String, Symbol)),
|
|
33
50
|
columns: T.nilable(T::Array[String]),
|
|
34
51
|
strict: T.nilable(T::Boolean),
|
|
52
|
+
string_storage: T.nilable(T.any(String, Symbol, T::Hash[Symbol, T.untyped])),
|
|
35
53
|
blk: T.nilable(T.proc.params(row: T.any(T::Hash[String, T.untyped], T::Array[T.untyped])).void)
|
|
36
54
|
).returns(NilClass)
|
|
37
55
|
end
|
|
38
|
-
def self.each_row(input, result_type: nil, columns: nil, strict: nil, &blk)
|
|
56
|
+
def self.each_row(input, result_type: nil, columns: nil, strict: nil, string_storage: nil, &blk)
|
|
39
57
|
end
|
|
40
58
|
|
|
41
59
|
# Options:
|
|
@@ -44,13 +62,16 @@ module Parquet
|
|
|
44
62
|
# ("hash" or "array" or :hash or :array)
|
|
45
63
|
# - `columns`: When present, only the specified columns will be included in the output.
|
|
46
64
|
# - `batch_size`: When present, specifies the number of rows per batch
|
|
65
|
+
# - `string_storage`: How string values become Ruby strings (`:copy` (default), `:intern`,
|
|
66
|
+
# or `:shared`). See `each_row` for the semantics of each mode.
|
|
47
67
|
sig do
|
|
48
68
|
params(
|
|
49
69
|
input: T.any(String, File, StringIO, IO),
|
|
50
70
|
result_type: T.nilable(T.any(String, Symbol)),
|
|
51
71
|
columns: T.nilable(T::Array[String]),
|
|
52
72
|
batch_size: T.nilable(Integer),
|
|
53
|
-
strict: T.nilable(T::Boolean)
|
|
73
|
+
strict: T.nilable(T::Boolean),
|
|
74
|
+
string_storage: T.nilable(T.any(String, Symbol, T::Hash[Symbol, T.untyped]))
|
|
54
75
|
).returns(T::Enumerator[T.any(T::Hash[String, T.untyped], T::Array[T.untyped])])
|
|
55
76
|
end
|
|
56
77
|
sig do
|
|
@@ -60,15 +81,17 @@ module Parquet
|
|
|
60
81
|
columns: T.nilable(T::Array[String]),
|
|
61
82
|
batch_size: T.nilable(Integer),
|
|
62
83
|
strict: T.nilable(T::Boolean),
|
|
84
|
+
string_storage: T.nilable(T.any(String, Symbol, T::Hash[Symbol, T.untyped])),
|
|
63
85
|
blk:
|
|
64
86
|
T.nilable(T.proc.params(batch: T.any(T::Hash[String, T::Array[T.untyped]], T::Array[T::Array[T.untyped]])).void)
|
|
65
87
|
).returns(NilClass)
|
|
66
88
|
end
|
|
67
|
-
def self.each_column(input, result_type: nil, columns: nil, batch_size: nil, strict: nil, &blk)
|
|
89
|
+
def self.each_column(input, result_type: nil, columns: nil, batch_size: nil, strict: nil, string_storage: nil, &blk)
|
|
68
90
|
end
|
|
69
91
|
|
|
70
92
|
# Options:
|
|
71
|
-
# - `read_from`: An
|
|
93
|
+
# - `read_from`: An Enumerable yielding arrays of values representing each row. The outer
|
|
94
|
+
# enumerable is pulled incrementally and is never materialized with `to_a`.
|
|
72
95
|
# - `schema`: Array of hashes specifying column names and types. Supported types:
|
|
73
96
|
# - `int8`, `int16`, `int32`, `int64`
|
|
74
97
|
# - `uint8`, `uint16`, `uint32`, `uint64`
|
|
@@ -79,20 +102,30 @@ module Parquet
|
|
|
79
102
|
# - `date32`
|
|
80
103
|
# - `timestamp_millis`, `timestamp_micros`
|
|
81
104
|
# - `write_to`: String path or IO object to write the parquet file to
|
|
82
|
-
# - `batch_size`: Optional batch size for writing (defaults to 1000
|
|
83
|
-
#
|
|
105
|
+
# - `batch_size`: Optional positive batch size for writing (defaults to 1000, at most 1_000_000
|
|
106
|
+
# for one-column schemas; wide schemas may have a lower safety cap)
|
|
107
|
+
# - `flush_threshold`: Optional positive byte quantum for converted native values (defaults
|
|
108
|
+
# to 100MB). One larger row is written alone. Encoded row groups use this
|
|
109
|
+
# value with an 8MB minimum; completed footer metadata is disk-spooled.
|
|
84
110
|
# - `compression`: Optional compression type to use (defaults to "zstd")
|
|
85
111
|
# Supported values: "none", "uncompressed", "snappy", "gzip", "lz4", "zstd"
|
|
86
|
-
# - `sample_size`: Optional number of rows to sample for size estimation
|
|
112
|
+
# - `sample_size`: Optional positive number of rows to sample for size estimation
|
|
113
|
+
# (defaults to 100, at most 10_000)
|
|
114
|
+
# - `string_cache`: Deduplicate repeated string values while writing. `false` (default)
|
|
115
|
+
# disables it, `true` enables it with a default capacity, and an Integer
|
|
116
|
+
# enables it with that many retained distinct strings (at most 65_536).
|
|
117
|
+
# Retention also skips values larger than 4KB and stops after 16MB of
|
|
118
|
+
# cached string content.
|
|
87
119
|
sig do
|
|
88
120
|
params(
|
|
89
|
-
read_from: T::
|
|
121
|
+
read_from: T::Enumerable[T::Array[T.untyped]],
|
|
90
122
|
schema: T::Array[T::Hash[String, String]],
|
|
91
123
|
write_to: T.any(String, IO),
|
|
92
124
|
batch_size: T.nilable(Integer),
|
|
93
125
|
flush_threshold: T.nilable(Integer),
|
|
94
126
|
compression: T.nilable(String),
|
|
95
|
-
sample_size: T.nilable(Integer)
|
|
127
|
+
sample_size: T.nilable(Integer),
|
|
128
|
+
string_cache: T.nilable(T.any(T::Boolean, Integer))
|
|
96
129
|
).void
|
|
97
130
|
end
|
|
98
131
|
def self.write_rows(
|
|
@@ -102,12 +135,14 @@ module Parquet
|
|
|
102
135
|
batch_size: nil,
|
|
103
136
|
flush_threshold: nil,
|
|
104
137
|
compression: nil,
|
|
105
|
-
sample_size: nil
|
|
138
|
+
sample_size: nil,
|
|
139
|
+
string_cache: nil
|
|
106
140
|
)
|
|
107
141
|
end
|
|
108
142
|
|
|
109
143
|
# Options:
|
|
110
|
-
# - `read_from`: An
|
|
144
|
+
# - `read_from`: An Enumerable yielding arrays of column batches. Batches are validated and
|
|
145
|
+
# consumed one at a time; all columns in each batch must have equal length.
|
|
111
146
|
# - `schema`: Array of hashes specifying column names and types. Supported types:
|
|
112
147
|
# - `int8`, `int16`, `int32`, `int64`
|
|
113
148
|
# - `uint8`, `uint16`, `uint32`, `uint64`
|
|
@@ -119,18 +154,82 @@ module Parquet
|
|
|
119
154
|
# - `timestamp_millis`, `timestamp_micros`
|
|
120
155
|
# - Looks like [{"column_name" => {"type" => "date32", "format" => "%Y-%m-%d"}}, {"column_name" => "int8"}]
|
|
121
156
|
# - `write_to`: String path or IO object to write the parquet file to
|
|
122
|
-
# - `flush_threshold`: Optional
|
|
157
|
+
# - `flush_threshold`: Optional positive byte quantum for converted native values (defaults
|
|
158
|
+
# to 100MB). One larger row is written alone. Encoded row groups use this
|
|
159
|
+
# value with an 8MB minimum; completed footer metadata is disk-spooled.
|
|
123
160
|
# - `compression`: Optional compression type to use (defaults to "zstd")
|
|
124
161
|
# Supported values: "none", "uncompressed", "snappy", "gzip", "lz4", "zstd"
|
|
162
|
+
# - `logger`: Optional Ruby logger for column-write progress messages
|
|
125
163
|
sig do
|
|
126
164
|
params(
|
|
127
|
-
read_from: T::
|
|
165
|
+
read_from: T::Enumerable[T::Array[T::Array[T.untyped]]],
|
|
128
166
|
schema: T::Array[T::Hash[String, String]],
|
|
129
167
|
write_to: T.any(String, IO),
|
|
130
168
|
flush_threshold: T.nilable(Integer),
|
|
131
|
-
compression: T.nilable(String)
|
|
169
|
+
compression: T.nilable(String),
|
|
170
|
+
logger: T.nilable(T.untyped)
|
|
132
171
|
).void
|
|
133
172
|
end
|
|
134
|
-
def self.write_columns(
|
|
173
|
+
def self.write_columns(
|
|
174
|
+
read_from,
|
|
175
|
+
schema:,
|
|
176
|
+
write_to:,
|
|
177
|
+
flush_threshold: nil,
|
|
178
|
+
compression: nil,
|
|
179
|
+
logger: nil
|
|
180
|
+
)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Concatenates Parquet files and re-splits them into a new set of files
|
|
184
|
+
# without translating rows through Ruby. Returns one hash per output file,
|
|
185
|
+
# `{"path" => String, "num_rows" => Integer}`, in output order.
|
|
186
|
+
#
|
|
187
|
+
# The outputs hold exactly the input rows, in input order. Every output but
|
|
188
|
+
# the last holds `rows_per_file` rows; there is always at least one output,
|
|
189
|
+
# even when the inputs are empty. Each output's Parquet schema is identical
|
|
190
|
+
# to the first input's, and that input's file-level key/value metadata (such
|
|
191
|
+
# as `ARROW:schema` or `pandas`) is carried over.
|
|
192
|
+
#
|
|
193
|
+
# Inputs must agree on leaf column shape — path, physical and logical type,
|
|
194
|
+
# nesting. They may differ in key/value metadata and Parquet field ids.
|
|
195
|
+
#
|
|
196
|
+
# Options:
|
|
197
|
+
# - `read_from`: String path or array of paths to Parquet files with matching schemas
|
|
198
|
+
# - `output_dir`: Directory where {output_file_prefix}-{n}.parquet files will be written
|
|
199
|
+
# - `output_file_prefix`: Single filename component used for outputs, default "batch".
|
|
200
|
+
# Path separators and `..` are rejected.
|
|
201
|
+
# - `rows_per_file`: Optional maximum number of rows per output file. When nil, all input
|
|
202
|
+
# rows are concatenated into one file.
|
|
203
|
+
# - `max_read_rows_per_chunk`: Optional upper bound for rows read per chunk, default 8192
|
|
204
|
+
# and reduced for wide schemas. It bounds memory only; it never changes the returned
|
|
205
|
+
# list, the rows, the schema, or the codecs.
|
|
206
|
+
# - `compression`: Optional codec for the outputs. When nil each column keeps its own
|
|
207
|
+
# codec, which also lets whole row groups be copied without re-encoding.
|
|
208
|
+
# - `overwrite`: When false (default), a non-empty `{output_file_prefix}-*.parquet` set in
|
|
209
|
+
# `output_dir` raises ArgumentError. When true, that set is replaced and any files left
|
|
210
|
+
# over from a longer earlier run are removed. Files outside the set are never touched.
|
|
211
|
+
#
|
|
212
|
+
# Raises ArgumentError for an invalid request or mismatched input schemas, and
|
|
213
|
+
# IOError when an input or output cannot be read or written.
|
|
214
|
+
sig do
|
|
215
|
+
params(
|
|
216
|
+
read_from: T.any(String, T::Array[String]),
|
|
217
|
+
output_dir: String,
|
|
218
|
+
output_file_prefix: T.nilable(String),
|
|
219
|
+
rows_per_file: T.nilable(Integer),
|
|
220
|
+
max_read_rows_per_chunk: T.nilable(Integer),
|
|
221
|
+
compression: T.nilable(String),
|
|
222
|
+
overwrite: T.nilable(T::Boolean)
|
|
223
|
+
).returns(T::Array[T::Hash[String, T.any(String, Integer)]])
|
|
224
|
+
end
|
|
225
|
+
def self.repack(
|
|
226
|
+
read_from,
|
|
227
|
+
output_dir:,
|
|
228
|
+
output_file_prefix: nil,
|
|
229
|
+
rows_per_file: nil,
|
|
230
|
+
max_read_rows_per_chunk: nil,
|
|
231
|
+
compression: nil,
|
|
232
|
+
overwrite: nil
|
|
233
|
+
)
|
|
135
234
|
end
|
|
136
235
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: parquet
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.9.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Nathan Jaremko
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-08-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bigdecimal
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
13
27
|
- !ruby/object:Gem::Dependency
|
|
14
28
|
name: rake-compiler
|
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -42,6 +56,7 @@ files:
|
|
|
42
56
|
- lib/parquet/3.2/parquet.so
|
|
43
57
|
- lib/parquet/3.3/parquet.so
|
|
44
58
|
- lib/parquet/3.4/parquet.so
|
|
59
|
+
- lib/parquet/4.0/parquet.so
|
|
45
60
|
- lib/parquet/schema.rb
|
|
46
61
|
- lib/parquet/version.rb
|
|
47
62
|
homepage: https://github.com/njaremko/parquet-ruby
|
|
@@ -65,7 +80,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
65
80
|
version: '3.2'
|
|
66
81
|
- - "<"
|
|
67
82
|
- !ruby/object:Gem::Version
|
|
68
|
-
version:
|
|
83
|
+
version: 4.1.dev
|
|
69
84
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
85
|
requirements:
|
|
71
86
|
- - ">="
|