red-arrow-format 23.0.1 → 25.0.0
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 +7 -2
- data/Rakefile +23 -1
- data/lib/arrow-format/array.rb +486 -117
- data/lib/arrow-format/bitmap.rb +25 -6
- data/lib/arrow-format/buffer-alignable.rb +35 -0
- data/lib/arrow-format/dictionary.rb +29 -0
- data/lib/arrow-format/error.rb +1 -1
- data/lib/arrow-format/field.rb +24 -3
- data/lib/arrow-format/file-reader.rb +47 -25
- data/lib/arrow-format/file-writer.rb +56 -0
- data/lib/arrow-format/flatbuffers.rb +67 -0
- data/lib/arrow-format/org/apache/arrow/flatbuf/binary.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/binary_view.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/block.rb +10 -2
- data/lib/arrow-format/org/apache/arrow/flatbuf/body_compression.rb +8 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/body_compression_method.rb +3 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/bool.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/buffer.rb +8 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/compression_type.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/date.rb +7 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/date_unit.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/decimal.rb +9 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/dictionary_batch.rb +9 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/dictionary_encoding.rb +11 -2
- data/lib/arrow-format/org/apache/arrow/flatbuf/dictionary_kind.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/duration.rb +7 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/endianness.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/feature.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/field.rb +13 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/field_node.rb +8 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/fixed_size_binary.rb +7 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/fixed_size_list.rb +7 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/floating_point.rb +7 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/footer.rb +22 -2
- data/lib/arrow-format/org/apache/arrow/flatbuf/int.rb +8 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/interval.rb +7 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/interval_unit.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/key_value.rb +8 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/large_binary.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/large_list.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/large_list_view.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/large_utf8.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/list.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/list_view.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/map.rb +8 -2
- data/lib/arrow-format/org/apache/arrow/flatbuf/message.rb +22 -2
- data/lib/arrow-format/org/apache/arrow/flatbuf/message_header.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/metadata_version.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/null.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/precision.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/record_batch.rb +12 -2
- data/lib/arrow-format/org/apache/arrow/flatbuf/run_end_encoded.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/schema.rb +10 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_matrix_compressed_axis.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_matrix_index_csx.rb +12 -2
- data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor.rb +13 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor_index.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor_index_coo.rb +13 -4
- data/lib/arrow-format/org/apache/arrow/flatbuf/sparse_tensor_index_csf.rb +14 -4
- data/lib/arrow-format/org/apache/arrow/flatbuf/struct_.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/tensor.rb +11 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/tensor_dim.rb +8 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/time.rb +8 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/time_unit.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/timestamp.rb +8 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/type.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/union.rb +8 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/union_mode.rb +1 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/utf8.rb +5 -1
- data/lib/arrow-format/org/apache/arrow/flatbuf/utf8view.rb +5 -1
- data/lib/arrow-format/readable.rb +151 -96
- data/lib/arrow-format/record-batch.rb +70 -1
- data/lib/arrow-format/schema.rb +14 -1
- data/lib/arrow-format/streaming-pull-reader.rb +49 -23
- data/lib/arrow-format/streaming-reader.rb +51 -14
- data/lib/arrow-format/streaming-writer.rb +156 -0
- data/lib/arrow-format/type.rb +397 -34
- data/lib/arrow-format/version.rb +1 -1
- data/lib/arrow-format.rb +2 -0
- data/red-arrow-format.gemspec +2 -1
- metadata +9 -4
|
@@ -17,152 +17,186 @@
|
|
|
17
17
|
|
|
18
18
|
require_relative "array"
|
|
19
19
|
require_relative "field"
|
|
20
|
+
require_relative "flatbuffers"
|
|
20
21
|
require_relative "record-batch"
|
|
21
22
|
require_relative "schema"
|
|
22
23
|
require_relative "type"
|
|
23
24
|
|
|
24
|
-
require_relative "org/apache/arrow/flatbuf/binary"
|
|
25
|
-
require_relative "org/apache/arrow/flatbuf/bool"
|
|
26
|
-
require_relative "org/apache/arrow/flatbuf/date"
|
|
27
|
-
require_relative "org/apache/arrow/flatbuf/date_unit"
|
|
28
|
-
require_relative "org/apache/arrow/flatbuf/decimal"
|
|
29
|
-
require_relative "org/apache/arrow/flatbuf/dictionary_encoding"
|
|
30
|
-
require_relative "org/apache/arrow/flatbuf/dictionary_batch"
|
|
31
|
-
require_relative "org/apache/arrow/flatbuf/duration"
|
|
32
|
-
require_relative "org/apache/arrow/flatbuf/fixed_size_binary"
|
|
33
|
-
require_relative "org/apache/arrow/flatbuf/floating_point"
|
|
34
|
-
require_relative "org/apache/arrow/flatbuf/int"
|
|
35
|
-
require_relative "org/apache/arrow/flatbuf/interval"
|
|
36
|
-
require_relative "org/apache/arrow/flatbuf/interval_unit"
|
|
37
|
-
require_relative "org/apache/arrow/flatbuf/large_binary"
|
|
38
|
-
require_relative "org/apache/arrow/flatbuf/large_list"
|
|
39
|
-
require_relative "org/apache/arrow/flatbuf/large_utf8"
|
|
40
|
-
require_relative "org/apache/arrow/flatbuf/list"
|
|
41
|
-
require_relative "org/apache/arrow/flatbuf/map"
|
|
42
|
-
require_relative "org/apache/arrow/flatbuf/message"
|
|
43
|
-
require_relative "org/apache/arrow/flatbuf/null"
|
|
44
|
-
require_relative "org/apache/arrow/flatbuf/precision"
|
|
45
|
-
require_relative "org/apache/arrow/flatbuf/record_batch"
|
|
46
|
-
require_relative "org/apache/arrow/flatbuf/schema"
|
|
47
|
-
require_relative "org/apache/arrow/flatbuf/struct_"
|
|
48
|
-
require_relative "org/apache/arrow/flatbuf/time"
|
|
49
|
-
require_relative "org/apache/arrow/flatbuf/time_unit"
|
|
50
|
-
require_relative "org/apache/arrow/flatbuf/timestamp"
|
|
51
|
-
require_relative "org/apache/arrow/flatbuf/union"
|
|
52
|
-
require_relative "org/apache/arrow/flatbuf/union_mode"
|
|
53
|
-
require_relative "org/apache/arrow/flatbuf/utf8"
|
|
54
|
-
|
|
55
25
|
module ArrowFormat
|
|
56
26
|
module Readable
|
|
57
27
|
private
|
|
58
|
-
def
|
|
28
|
+
def read_custom_metadata(fb_custom_metadata)
|
|
29
|
+
return nil if fb_custom_metadata.nil?
|
|
30
|
+
metadata = {}
|
|
31
|
+
fb_custom_metadata.each do |key_value|
|
|
32
|
+
metadata[key_value.key] = key_value.value
|
|
33
|
+
end
|
|
34
|
+
metadata
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def read_schema(fb_schema, fb_message_custom_metadata=nil)
|
|
59
38
|
fields = fb_schema.fields.collect do |fb_field|
|
|
60
39
|
read_field(fb_field)
|
|
61
40
|
end
|
|
62
|
-
|
|
41
|
+
message_metadata = read_custom_metadata(fb_message_custom_metadata)
|
|
42
|
+
Schema.new(fields,
|
|
43
|
+
metadata: read_custom_metadata(fb_schema.custom_metadata),
|
|
44
|
+
message_metadata: message_metadata)
|
|
63
45
|
end
|
|
64
46
|
|
|
65
|
-
def read_field(fb_field
|
|
47
|
+
def read_field(fb_field,
|
|
48
|
+
map_entries: false,
|
|
49
|
+
map_key: false,
|
|
50
|
+
map_value: false)
|
|
66
51
|
fb_type = fb_field.type
|
|
67
52
|
case fb_type
|
|
68
|
-
when
|
|
53
|
+
when FB::Null
|
|
69
54
|
type = NullType.singleton
|
|
70
|
-
when
|
|
55
|
+
when FB::Bool
|
|
71
56
|
type = BooleanType.singleton
|
|
72
|
-
when
|
|
57
|
+
when FB::Int
|
|
73
58
|
type = read_type_int(fb_type)
|
|
74
|
-
when
|
|
59
|
+
when FB::FloatingPoint
|
|
75
60
|
case fb_type.precision
|
|
76
|
-
when
|
|
61
|
+
when FB::Precision::SINGLE
|
|
77
62
|
type = Float32Type.singleton
|
|
78
|
-
when
|
|
63
|
+
when FB::Precision::DOUBLE
|
|
79
64
|
type = Float64Type.singleton
|
|
65
|
+
else
|
|
66
|
+
raise ReadError.new("Unsupported type: #{fb_type.inspect}")
|
|
80
67
|
end
|
|
81
|
-
when
|
|
68
|
+
when FB::Date
|
|
82
69
|
case fb_type.unit
|
|
83
|
-
when
|
|
70
|
+
when FB::DateUnit::DAY
|
|
84
71
|
type = Date32Type.singleton
|
|
85
|
-
when
|
|
72
|
+
when FB::DateUnit::MILLISECOND
|
|
86
73
|
type = Date64Type.singleton
|
|
74
|
+
else
|
|
75
|
+
raise ReadError.new("Unsupported type: #{fb_type.inspect}")
|
|
87
76
|
end
|
|
88
|
-
when
|
|
77
|
+
when FB::Time
|
|
89
78
|
case fb_type.bit_width
|
|
90
79
|
when 32
|
|
91
80
|
case fb_type.unit
|
|
92
|
-
when
|
|
81
|
+
when FB::TimeUnit::SECOND
|
|
93
82
|
type = Time32Type.new(:second)
|
|
94
|
-
when
|
|
83
|
+
when FB::TimeUnit::MILLISECOND
|
|
95
84
|
type = Time32Type.new(:millisecond)
|
|
85
|
+
else
|
|
86
|
+
raise ReadError.new("Unsupported type: #{fb_type.inspect}")
|
|
96
87
|
end
|
|
97
88
|
when 64
|
|
98
89
|
case fb_type.unit
|
|
99
|
-
when
|
|
90
|
+
when FB::TimeUnit::MICROSECOND
|
|
100
91
|
type = Time64Type.new(:microsecond)
|
|
101
|
-
when
|
|
92
|
+
when FB::TimeUnit::NANOSECOND
|
|
102
93
|
type = Time64Type.new(:nanosecond)
|
|
94
|
+
else
|
|
95
|
+
raise ReadError.new("Unsupported type: #{fb_type.inspect}")
|
|
103
96
|
end
|
|
104
97
|
end
|
|
105
|
-
when
|
|
98
|
+
when FB::Timestamp
|
|
106
99
|
unit = fb_type.unit.name.downcase.to_sym
|
|
107
100
|
type = TimestampType.new(unit, fb_type.timezone)
|
|
108
|
-
when
|
|
101
|
+
when FB::Interval
|
|
109
102
|
case fb_type.unit
|
|
110
|
-
when
|
|
111
|
-
type = YearMonthIntervalType.
|
|
112
|
-
when
|
|
113
|
-
type = DayTimeIntervalType.
|
|
114
|
-
when
|
|
115
|
-
type = MonthDayNanoIntervalType.
|
|
103
|
+
when FB::IntervalUnit::YEAR_MONTH
|
|
104
|
+
type = YearMonthIntervalType.singleton
|
|
105
|
+
when FB::IntervalUnit::DAY_TIME
|
|
106
|
+
type = DayTimeIntervalType.singleton
|
|
107
|
+
when FB::IntervalUnit::MONTH_DAY_NANO
|
|
108
|
+
type = MonthDayNanoIntervalType.singleton
|
|
109
|
+
else
|
|
110
|
+
raise ReadError.new("Unsupported type: #{fb_type.inspect}")
|
|
116
111
|
end
|
|
117
|
-
when
|
|
112
|
+
when FB::Duration
|
|
118
113
|
unit = fb_type.unit.name.downcase.to_sym
|
|
119
114
|
type = DurationType.new(unit)
|
|
120
|
-
when
|
|
115
|
+
when FB::List
|
|
121
116
|
type = ListType.new(read_field(fb_field.children[0]))
|
|
122
|
-
when
|
|
117
|
+
when FB::LargeList
|
|
123
118
|
type = LargeListType.new(read_field(fb_field.children[0]))
|
|
124
|
-
when
|
|
125
|
-
|
|
119
|
+
when FB::FixedSizeList
|
|
120
|
+
type = FixedSizeListType.new(read_field(fb_field.children[0]),
|
|
121
|
+
fb_type.list_size)
|
|
122
|
+
when FB::Struct
|
|
123
|
+
if map_entries
|
|
124
|
+
fb_children = fb_field.children
|
|
125
|
+
children = [
|
|
126
|
+
read_field(fb_children[0], map_key: true),
|
|
127
|
+
read_field(fb_children[1], map_value: true),
|
|
128
|
+
]
|
|
129
|
+
else
|
|
130
|
+
children = fb_field.children.collect {|child| read_field(child)}
|
|
131
|
+
end
|
|
126
132
|
type = StructType.new(children)
|
|
127
|
-
when
|
|
133
|
+
when FB::Union
|
|
128
134
|
children = fb_field.children.collect {|child| read_field(child)}
|
|
129
135
|
type_ids = fb_type.type_ids
|
|
130
136
|
case fb_type.mode
|
|
131
|
-
when
|
|
137
|
+
when FB::UnionMode::DENSE
|
|
132
138
|
type = DenseUnionType.new(children, type_ids)
|
|
133
|
-
when
|
|
139
|
+
when FB::UnionMode::SPARSE
|
|
134
140
|
type = SparseUnionType.new(children, type_ids)
|
|
141
|
+
else
|
|
142
|
+
raise ReadError.new("Unsupported type: #{fb_type.inspect}")
|
|
135
143
|
end
|
|
136
|
-
when
|
|
137
|
-
type = MapType.new(read_field(fb_field.children[0])
|
|
138
|
-
|
|
144
|
+
when FB::Map
|
|
145
|
+
type = MapType.new(read_field(fb_field.children[0], map_entries: true),
|
|
146
|
+
fb_type.keys_sorted?)
|
|
147
|
+
when FB::Binary
|
|
139
148
|
type = BinaryType.singleton
|
|
140
|
-
when
|
|
149
|
+
when FB::LargeBinary
|
|
141
150
|
type = LargeBinaryType.singleton
|
|
142
|
-
when
|
|
151
|
+
when FB::Utf8
|
|
143
152
|
type = UTF8Type.singleton
|
|
144
|
-
when
|
|
153
|
+
when FB::LargeUtf8
|
|
145
154
|
type = LargeUTF8Type.singleton
|
|
146
|
-
when
|
|
155
|
+
when FB::FixedSizeBinary
|
|
147
156
|
type = FixedSizeBinaryType.new(fb_type.byte_width)
|
|
148
|
-
when
|
|
157
|
+
when FB::Decimal
|
|
149
158
|
case fb_type.bit_width
|
|
150
159
|
when 128
|
|
151
160
|
type = Decimal128Type.new(fb_type.precision, fb_type.scale)
|
|
152
161
|
when 256
|
|
153
162
|
type = Decimal256Type.new(fb_type.precision, fb_type.scale)
|
|
163
|
+
else
|
|
164
|
+
raise ReadError.new("Unsupported type: #{fb_type.inspect}")
|
|
154
165
|
end
|
|
166
|
+
else
|
|
167
|
+
raise ReadError.new("Unsupported type: #{fb_type.inspect}")
|
|
155
168
|
end
|
|
156
169
|
|
|
157
170
|
dictionary = fb_field.dictionary
|
|
158
171
|
if dictionary
|
|
159
172
|
dictionary_id = dictionary.id
|
|
160
173
|
index_type = read_type_int(dictionary.index_type)
|
|
161
|
-
|
|
174
|
+
value_type = type
|
|
175
|
+
type = DictionaryType.new(dictionary_id,
|
|
176
|
+
index_type,
|
|
177
|
+
value_type,
|
|
178
|
+
dictionary.ordered?)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Map type uses static "entries"/"key"/"value" as field names
|
|
182
|
+
# instead of field names in FlatBuffers. It's based on the
|
|
183
|
+
# specification:
|
|
184
|
+
#
|
|
185
|
+
# The names of the child fields may be respectively "entries",
|
|
186
|
+
# "key", and "value", but this is not enforced.
|
|
187
|
+
if map_entries
|
|
188
|
+
name = "entries"
|
|
189
|
+
elsif map_key
|
|
190
|
+
name = "key"
|
|
191
|
+
elsif map_value
|
|
192
|
+
name = "value"
|
|
162
193
|
else
|
|
163
|
-
|
|
194
|
+
name = fb_field.name
|
|
164
195
|
end
|
|
165
|
-
Field.new(
|
|
196
|
+
Field.new(name,
|
|
197
|
+
type,
|
|
198
|
+
nullable: fb_field.nullable?,
|
|
199
|
+
metadata: read_custom_metadata(fb_field.custom_metadata))
|
|
166
200
|
end
|
|
167
201
|
|
|
168
202
|
def read_type_int(fb_type)
|
|
@@ -194,17 +228,23 @@ module ArrowFormat
|
|
|
194
228
|
end
|
|
195
229
|
end
|
|
196
230
|
|
|
197
|
-
def read_record_batch(
|
|
231
|
+
def read_record_batch(version,
|
|
232
|
+
fb_record_batch,
|
|
233
|
+
fb_message_custom_metadata,
|
|
234
|
+
schema,
|
|
235
|
+
body)
|
|
236
|
+
message_metadata = read_custom_metadata(fb_message_custom_metadata)
|
|
198
237
|
n_rows = fb_record_batch.length
|
|
199
238
|
nodes = fb_record_batch.nodes
|
|
200
239
|
buffers = fb_record_batch.buffers
|
|
201
240
|
columns = schema.fields.collect do |field|
|
|
202
|
-
read_column(field, nodes, buffers, body)
|
|
241
|
+
read_column(version, field, nodes, buffers, body)
|
|
203
242
|
end
|
|
204
|
-
RecordBatch.new(schema, n_rows, columns
|
|
243
|
+
RecordBatch.new(schema, n_rows, columns,
|
|
244
|
+
message_metadata: message_metadata)
|
|
205
245
|
end
|
|
206
246
|
|
|
207
|
-
def read_column(field, nodes, buffers, body)
|
|
247
|
+
def read_column(version, field, nodes, buffers, body)
|
|
208
248
|
node = nodes.shift
|
|
209
249
|
length = node.length
|
|
210
250
|
|
|
@@ -222,49 +262,64 @@ module ArrowFormat
|
|
|
222
262
|
NumberType,
|
|
223
263
|
TemporalType
|
|
224
264
|
values_buffer = buffers.shift
|
|
225
|
-
values = body
|
|
265
|
+
values = body&.slice(values_buffer.offset, values_buffer.length)
|
|
226
266
|
field.type.build_array(length, validity, values)
|
|
227
267
|
when VariableSizeBinaryType
|
|
228
268
|
offsets_buffer = buffers.shift
|
|
229
269
|
values_buffer = buffers.shift
|
|
230
|
-
offsets = body
|
|
231
|
-
values = body
|
|
270
|
+
offsets = body&.slice(offsets_buffer.offset, offsets_buffer.length)
|
|
271
|
+
values = body&.slice(values_buffer.offset, values_buffer.length)
|
|
232
272
|
field.type.build_array(length, validity, offsets, values)
|
|
233
273
|
when FixedSizeBinaryType
|
|
234
274
|
values_buffer = buffers.shift
|
|
235
|
-
values = body
|
|
275
|
+
values = body&.slice(values_buffer.offset, values_buffer.length)
|
|
236
276
|
field.type.build_array(length, validity, values)
|
|
237
277
|
when VariableSizeListType
|
|
238
278
|
offsets_buffer = buffers.shift
|
|
239
|
-
offsets = body
|
|
240
|
-
child = read_column(field.type.child, nodes, buffers, body)
|
|
279
|
+
offsets = body&.slice(offsets_buffer.offset, offsets_buffer.length)
|
|
280
|
+
child = read_column(version, field.type.child, nodes, buffers, body)
|
|
241
281
|
field.type.build_array(length, validity, offsets, child)
|
|
282
|
+
when FixedSizeListType
|
|
283
|
+
child = read_column(version, field.type.child, nodes, buffers, body)
|
|
284
|
+
field.type.build_array(length, validity, child)
|
|
242
285
|
when StructType
|
|
243
286
|
children = field.type.children.collect do |child|
|
|
244
|
-
read_column(child, nodes, buffers, body)
|
|
287
|
+
read_column(version, child, nodes, buffers, body)
|
|
245
288
|
end
|
|
246
289
|
field.type.build_array(length, validity, children)
|
|
247
290
|
when DenseUnionType
|
|
248
|
-
|
|
249
|
-
|
|
291
|
+
if version == FB::MetadataVersion::V4
|
|
292
|
+
# Dense union type has validity with V4.
|
|
293
|
+
types_buffer = buffers.shift
|
|
294
|
+
types = body&.slice(types_buffer.offset, types_buffer.length)
|
|
295
|
+
else
|
|
296
|
+
# Dense union type doesn't have validity.
|
|
297
|
+
types = validity
|
|
298
|
+
end
|
|
250
299
|
offsets_buffer = buffers.shift
|
|
251
|
-
offsets = body
|
|
300
|
+
offsets = body&.slice(offsets_buffer.offset, offsets_buffer.length)
|
|
252
301
|
children = field.type.children.collect do |child|
|
|
253
|
-
read_column(child, nodes, buffers, body)
|
|
302
|
+
read_column(version, child, nodes, buffers, body)
|
|
254
303
|
end
|
|
255
304
|
field.type.build_array(length, types, offsets, children)
|
|
256
305
|
when SparseUnionType
|
|
257
|
-
|
|
258
|
-
|
|
306
|
+
if version == FB::MetadataVersion::V4
|
|
307
|
+
# Sparse union type has validity with V4.
|
|
308
|
+
types_buffer = buffers.shift
|
|
309
|
+
types = body&.slice(types_buffer.offset, types_buffer.length)
|
|
310
|
+
else
|
|
311
|
+
# Sparse union type doesn't have validity.
|
|
312
|
+
types = validity
|
|
313
|
+
end
|
|
259
314
|
children = field.type.children.collect do |child|
|
|
260
|
-
read_column(child, nodes, buffers, body)
|
|
315
|
+
read_column(version, child, nodes, buffers, body)
|
|
261
316
|
end
|
|
262
317
|
field.type.build_array(length, types, children)
|
|
263
318
|
when DictionaryType
|
|
264
319
|
indices_buffer = buffers.shift
|
|
265
|
-
indices = body
|
|
266
|
-
|
|
267
|
-
field.type.build_array(length, validity, indices,
|
|
320
|
+
indices = body&.slice(indices_buffer.offset, indices_buffer.length)
|
|
321
|
+
dictionaries = find_dictionaries(field.type.id)
|
|
322
|
+
field.type.build_array(length, validity, indices, dictionaries)
|
|
268
323
|
end
|
|
269
324
|
end
|
|
270
325
|
end
|
|
@@ -14,15 +14,27 @@
|
|
|
14
14
|
# specific language governing permissions and limitations
|
|
15
15
|
# under the License.
|
|
16
16
|
|
|
17
|
+
require_relative "buffer-alignable"
|
|
18
|
+
|
|
17
19
|
module ArrowFormat
|
|
18
20
|
class RecordBatch
|
|
21
|
+
include BufferAlignable
|
|
22
|
+
|
|
19
23
|
attr_reader :schema
|
|
20
24
|
attr_reader :n_rows
|
|
25
|
+
alias_method :size, :n_rows
|
|
26
|
+
alias_method :length, :n_rows
|
|
21
27
|
attr_reader :columns
|
|
22
|
-
|
|
28
|
+
attr_reader :message_metadata
|
|
29
|
+
def initialize(schema, n_rows, columns, message_metadata: nil)
|
|
23
30
|
@schema = schema
|
|
24
31
|
@n_rows = n_rows
|
|
25
32
|
@columns = columns
|
|
33
|
+
@message_metadata = message_metadata
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def empty?
|
|
37
|
+
@n_rows.zero?
|
|
26
38
|
end
|
|
27
39
|
|
|
28
40
|
def to_h
|
|
@@ -32,5 +44,62 @@ module ArrowFormat
|
|
|
32
44
|
end
|
|
33
45
|
hash
|
|
34
46
|
end
|
|
47
|
+
|
|
48
|
+
def to_flatbuffers
|
|
49
|
+
fb_record_batch = FB::RecordBatch::Data.new
|
|
50
|
+
fb_record_batch.length = @n_rows
|
|
51
|
+
fb_record_batch.nodes = all_columns_enumerator.collect do |array|
|
|
52
|
+
field_node = FB::FieldNode::Data.new
|
|
53
|
+
field_node.length = array.size
|
|
54
|
+
field_node.null_count = array.n_nulls
|
|
55
|
+
field_node
|
|
56
|
+
end
|
|
57
|
+
offset = 0
|
|
58
|
+
fb_record_batch.buffers = all_buffers_enumerator.collect do |buffer|
|
|
59
|
+
fb_buffer = FB::Buffer::Data.new
|
|
60
|
+
fb_buffer.offset = offset
|
|
61
|
+
if buffer
|
|
62
|
+
aligned_size = aligned_buffer_size(buffer)
|
|
63
|
+
offset += aligned_size
|
|
64
|
+
fb_buffer.length = aligned_size
|
|
65
|
+
else
|
|
66
|
+
fb_buffer.length = 0
|
|
67
|
+
end
|
|
68
|
+
fb_buffer
|
|
69
|
+
end
|
|
70
|
+
# body_compression = FB::BodyCompression::Data.new
|
|
71
|
+
# body_compression.codec = ...
|
|
72
|
+
# fb_record_batch.compression = body_compression
|
|
73
|
+
fb_record_batch
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Pre-order depth-first traversal
|
|
77
|
+
def all_columns_enumerator
|
|
78
|
+
Enumerator.new do |yielder|
|
|
79
|
+
traverse = lambda do |array|
|
|
80
|
+
yielder << array
|
|
81
|
+
if array.respond_to?(:child)
|
|
82
|
+
traverse.call(array.child)
|
|
83
|
+
elsif array.respond_to?(:children)
|
|
84
|
+
array.children.each do |child_array|
|
|
85
|
+
traverse.call(child_array)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
@columns.each do |array|
|
|
90
|
+
traverse.call(array)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def all_buffers_enumerator
|
|
96
|
+
Enumerator.new do |yielder|
|
|
97
|
+
all_columns_enumerator.each do |array|
|
|
98
|
+
array.each_buffer do |buffer|
|
|
99
|
+
yielder << buffer
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
35
104
|
end
|
|
36
105
|
end
|
data/lib/arrow-format/schema.rb
CHANGED
|
@@ -17,8 +17,21 @@
|
|
|
17
17
|
module ArrowFormat
|
|
18
18
|
class Schema
|
|
19
19
|
attr_reader :fields
|
|
20
|
-
|
|
20
|
+
attr_reader :metadata
|
|
21
|
+
attr_reader :message_metadata
|
|
22
|
+
def initialize(fields, metadata: nil, message_metadata: nil)
|
|
21
23
|
@fields = fields
|
|
24
|
+
@metadata = metadata
|
|
25
|
+
@message_metadata = message_metadata
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_flatbuffers
|
|
29
|
+
fb_schema = FB::Schema::Data.new
|
|
30
|
+
fb_schema.endianness = FB::Endianness::LITTLE
|
|
31
|
+
fb_schema.fields = fields.collect(&:to_flatbuffers)
|
|
32
|
+
fb_schema.custom_metadata = FB.build_custom_metadata(@metadata)
|
|
33
|
+
# fb_schema.features = @features
|
|
34
|
+
fb_schema
|
|
22
35
|
end
|
|
23
36
|
end
|
|
24
37
|
end
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
# under the License.
|
|
17
17
|
|
|
18
18
|
require_relative "array"
|
|
19
|
+
require_relative "dictionary"
|
|
19
20
|
require_relative "error"
|
|
20
21
|
require_relative "field"
|
|
21
22
|
require_relative "readable"
|
|
@@ -100,11 +101,23 @@ module ArrowFormat
|
|
|
100
101
|
private
|
|
101
102
|
def consume_initial(target)
|
|
102
103
|
continuation = target.get_value(CONTINUATION_TYPE, 0)
|
|
103
|
-
|
|
104
|
+
if continuation == CONTINUATION_INT32
|
|
105
|
+
@state = :metadata_length
|
|
106
|
+
elsif continuation < 0
|
|
104
107
|
raise ReadError.new("Invalid continuation token: " +
|
|
105
108
|
continuation.inspect)
|
|
109
|
+
else
|
|
110
|
+
# For backward compatibility of data produced prior to version
|
|
111
|
+
# 0.15.0. It doesn't have continuation token. Ignore it and
|
|
112
|
+
# re-read it as metadata length.
|
|
113
|
+
metadata_length = continuation
|
|
114
|
+
if metadata_length == 0
|
|
115
|
+
@state = :eos
|
|
116
|
+
else
|
|
117
|
+
@metadata_length = metadata_length
|
|
118
|
+
@state = :metadata
|
|
119
|
+
end
|
|
106
120
|
end
|
|
107
|
-
@state = :metadata_length
|
|
108
121
|
end
|
|
109
122
|
|
|
110
123
|
def consume_metadata_length(target)
|
|
@@ -123,7 +136,7 @@ module ArrowFormat
|
|
|
123
136
|
|
|
124
137
|
def consume_metadata(target)
|
|
125
138
|
metadata_buffer = target.slice(0, @metadata_length)
|
|
126
|
-
@message =
|
|
139
|
+
@message = FB::Message.new(metadata_buffer)
|
|
127
140
|
@body_length = @message.body_length
|
|
128
141
|
if @body_length < 0
|
|
129
142
|
raise ReadError.new("Negative body length: " +
|
|
@@ -174,7 +187,7 @@ module ArrowFormat
|
|
|
174
187
|
process_schema_message(message, body)
|
|
175
188
|
when :initial_dictionaries
|
|
176
189
|
header = message.header
|
|
177
|
-
unless header.is_a?(
|
|
190
|
+
unless header.is_a?(FB::DictionaryBatch)
|
|
178
191
|
raise ReadError.new("Not a dictionary batch message: " +
|
|
179
192
|
header.inspect)
|
|
180
193
|
end
|
|
@@ -184,9 +197,9 @@ module ArrowFormat
|
|
|
184
197
|
end
|
|
185
198
|
when :data
|
|
186
199
|
case message.header
|
|
187
|
-
when
|
|
200
|
+
when FB::DictionaryBatch
|
|
188
201
|
process_dictionary_batch_message(message, body)
|
|
189
|
-
when
|
|
202
|
+
when FB::RecordBatch
|
|
190
203
|
process_record_batch_message(message, body)
|
|
191
204
|
end
|
|
192
205
|
end
|
|
@@ -194,17 +207,17 @@ module ArrowFormat
|
|
|
194
207
|
|
|
195
208
|
def process_schema_message(message, body)
|
|
196
209
|
header = message.header
|
|
197
|
-
unless header.is_a?(
|
|
210
|
+
unless header.is_a?(FB::Schema)
|
|
198
211
|
raise ReadError.new("Not a schema message: " +
|
|
199
212
|
header.inspect)
|
|
200
213
|
end
|
|
201
214
|
|
|
202
|
-
@schema = read_schema(header)
|
|
215
|
+
@schema = read_schema(header, message.custom_metadata)
|
|
203
216
|
@dictionaries = {}
|
|
204
217
|
@dictionary_fields = {}
|
|
205
218
|
@schema.fields.each do |field|
|
|
206
219
|
next unless field.type.is_a?(DictionaryType)
|
|
207
|
-
@dictionary_fields[field.
|
|
220
|
+
@dictionary_fields[field.type.id] = field
|
|
208
221
|
end
|
|
209
222
|
if @dictionaries.size < @dictionary_fields.size
|
|
210
223
|
@state = :initial_dictionaries
|
|
@@ -213,31 +226,44 @@ module ArrowFormat
|
|
|
213
226
|
end
|
|
214
227
|
end
|
|
215
228
|
|
|
216
|
-
def process_dictionary_batch_message(
|
|
217
|
-
|
|
218
|
-
if @state == :initial_dictionaries and
|
|
229
|
+
def process_dictionary_batch_message(fb_message, body)
|
|
230
|
+
fb_header = fb_message.header
|
|
231
|
+
if @state == :initial_dictionaries and fb_header.delta?
|
|
219
232
|
raise ReadError.new("An initial dictionary batch message must be " +
|
|
220
233
|
"a non delta dictionary batch message: " +
|
|
221
|
-
|
|
234
|
+
fb_header.inspect)
|
|
222
235
|
end
|
|
223
|
-
field = @dictionary_fields[
|
|
236
|
+
field = @dictionary_fields[fb_header.id]
|
|
224
237
|
value_type = field.type.value_type
|
|
225
|
-
schema = Schema.new([Field.new("dummy", value_type
|
|
226
|
-
record_batch = read_record_batch(
|
|
227
|
-
|
|
228
|
-
|
|
238
|
+
schema = Schema.new([Field.new("dummy", value_type)])
|
|
239
|
+
record_batch = read_record_batch(fb_message.version,
|
|
240
|
+
fb_header.data,
|
|
241
|
+
nil,
|
|
242
|
+
schema,
|
|
243
|
+
body)
|
|
244
|
+
message_metadata = read_custom_metadata(fb_message.custom_metadata)
|
|
245
|
+
dictionary = Dictionary.new(fb_header.id,
|
|
246
|
+
record_batch.columns[0],
|
|
247
|
+
message_metadata: message_metadata)
|
|
248
|
+
if fb_header.delta?
|
|
249
|
+
@dictionaries[fb_header.id] << dictionary
|
|
229
250
|
else
|
|
230
|
-
@dictionaries[
|
|
251
|
+
@dictionaries[fb_header.id] = [dictionary]
|
|
231
252
|
end
|
|
232
253
|
end
|
|
233
254
|
|
|
234
|
-
def
|
|
255
|
+
def find_dictionaries(id)
|
|
235
256
|
@dictionaries[id]
|
|
236
257
|
end
|
|
237
258
|
|
|
238
|
-
def process_record_batch_message(
|
|
239
|
-
|
|
240
|
-
|
|
259
|
+
def process_record_batch_message(fb_message, body)
|
|
260
|
+
fb_header = fb_message.header
|
|
261
|
+
record_batch = read_record_batch(fb_message.version,
|
|
262
|
+
fb_header,
|
|
263
|
+
fb_message.custom_metadata,
|
|
264
|
+
@schema,
|
|
265
|
+
body)
|
|
266
|
+
@on_read.call(record_batch)
|
|
241
267
|
end
|
|
242
268
|
end
|
|
243
269
|
end
|