Skip to content

Commit 61920ad

Browse files
xiaoxmengmeta-codesync[bot]
authored andcommitted
feat(nimble): Add shared integer dictionary encoding (#18637)
Summary: Pull Request resolved: #18637 Add shared dictionary encoding for integer Nimble value streams. Encoded chunks store the normal prefix plus dictionary indices, while the alphabet is resolved from a stripe stream, a file catalog, or an external resolver. This lets selected value streams share alphabets even when their physical stream ids vary by stripe, including FlatMap values. Wire dictionary resolution through tablet readers and bind the resolved alphabet before regular, selective, and index-reader decoding. Writers configure eligible regular columns and flat-map values explicitly, compare shared dictionary encoding with direct encoding for stripe scope on the first chunk, and keep that choice for the rest of the stripe. File and external dictionaries use prebuilt alphabets and avoid per-chunk scope or dictionary-id payload. Unsupported dictionary lifecycles remain rejected until they are implemented. Reviewed By: tanjialiang Differential Revision: D112768733
1 parent a9c90e0 commit 61920ad

48 files changed

Lines changed: 5988 additions & 616 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

velox/dwio/common/SelectiveColumnReader.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,15 +296,17 @@ class SelectiveColumnReader {
296296
numValues_ = size;
297297
}
298298

299-
// The number of passing after filtering.
299+
// The number of result rows after filtering.
300300
int32_t numRows() const {
301301
return outputRows_.size();
302302
}
303303

304-
// The number of values copied into the results.
304+
// The number of result positions produced so far. This includes null
305+
// positions; it is not the count of decoded non-null values.
305306
int32_t numValues() const {
306307
return numValues_;
307308
}
309+
308310
void setNumRows(vector_size_t size) {
309311
outputRows_.resize(size);
310312
}

velox/dwio/nimble/encodings/SharedDictionaryEncoding.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ SharedDictionaryAlphabet::SharedDictionaryAlphabet(
4242
std::shared_ptr<const void> encodedAlphabetOwner,
4343
velox::memory::MemoryPool* pool)
4444
: encodedAlphabetOwner_{std::move(encodedAlphabetOwner)},
45+
encodedAlphabet_{encoded},
4546
dataType_{EncodingPrefix::dataType(encoded)},
4647
encodingType_{EncodingPrefix::encodingType(encoded)},
4748
entryPayload_{*velox::checkedNotNull(pool)},

velox/dwio/nimble/encodings/SharedDictionaryEncoding.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "velox/dwio/nimble/common/Types.h"
4141
#include "velox/dwio/nimble/common/Vector.h"
4242
#include "velox/dwio/nimble/encodings/DictionaryEncoding.h"
43+
#include "velox/dwio/nimble/encodings/NullableEncoding.h"
4344
#include "velox/dwio/nimble/encodings/common/Encoding.h"
4445
#include "velox/dwio/nimble/encodings/common/EncodingFactory.h"
4546
#include "velox/dwio/nimble/encodings/common/EncodingPrefix.h"
@@ -298,6 +299,11 @@ class SharedDictionaryAlphabet {
298299
return encodingType_;
299300
}
300301

302+
/// Returns the encoded alphabet stream passed to create().
303+
std::string_view encodedAlphabet() const {
304+
return encodedAlphabet_;
305+
}
306+
301307
/// Returns the entry stored at index. T must match dataType().
302308
template <typename T>
303309
typename TypeTraits<T>::physicalType physicalValueAt(uint32_t index) const {
@@ -432,6 +438,7 @@ class SharedDictionaryAlphabet {
432438

433439
// Keeps borrowed encoded bytes alive when create() receives an owner.
434440
const std::shared_ptr<const void> encodedAlphabetOwner_;
441+
const std::string_view encodedAlphabet_;
435442
const DataType dataType_;
436443
const EncodingType encodingType_;
437444
uint32_t entryCount_{0};
@@ -503,6 +510,13 @@ class SharedDictionaryEncoding
503510
Buffer& buffer,
504511
const Encoding::Options& options = {});
505512

513+
static std::string_view encodeNullable(
514+
EncodingSelection<physicalType>&& selection,
515+
std::span<const physicalType> values,
516+
std::span<const bool> nulls,
517+
Buffer& buffer,
518+
const Encoding::Options& options = {});
519+
506520
static std::string_view slice(
507521
std::string_view encoded,
508522
uint32_t offset,
@@ -666,6 +680,34 @@ std::string_view SharedDictionaryEncoding<T>::encode(
666680
return {reserved, encodingSize};
667681
}
668682

683+
template <typename T>
684+
std::string_view SharedDictionaryEncoding<T>::encodeNullable(
685+
EncodingSelection<physicalType>&& selection,
686+
std::span<const physicalType> values,
687+
std::span<const bool> nulls,
688+
Buffer& buffer,
689+
const Encoding::Options& options) {
690+
static_assert(isIntegralType<T>() && !std::is_same_v<T, bool>);
691+
692+
auto nullsPolicy = selection.template createNestedPolicy<bool>(
693+
EncodingType::Nullable, EncodingIdentifiers::Nullable::Nulls);
694+
NIMBLE_CHECK_NOT_NULL(nullsPolicy);
695+
auto typedNullsPolicy = std::unique_ptr<EncodingSelectionPolicy<bool>>(
696+
static_cast<EncodingSelectionPolicy<bool>*>(nullsPolicy.release()));
697+
auto* pool = &buffer.getMemoryPool();
698+
ScopedEncodingBuffer scopedBuffer{pool, options.encodingBufferPool};
699+
const auto serializedValues = EncodingFactory::encode<T>(
700+
std::move(selection), values, scopedBuffer.get(), options);
701+
const auto serializedNulls = EncodingFactory::encode<bool>(
702+
std::move(typedNullsPolicy), nulls, scopedBuffer.get(), options);
703+
return NullableEncoding<T>::encodeNullable(
704+
static_cast<uint32_t>(nulls.size()),
705+
serializedValues,
706+
serializedNulls,
707+
buffer,
708+
options);
709+
}
710+
669711
template <typename T>
670712
std::string_view SharedDictionaryEncoding<T>::encodeIndices(
671713
std::span<const uint32_t> indices,

velox/dwio/nimble/encodings/common/EncodingFactory.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,36 @@ std::string_view EncodingFactory::encode(
284284
selection, castedValues, buffer, options);
285285
}
286286
case EncodingType::SharedDictionary: {
287+
if constexpr (isIntegralType<T>() && !std::is_same_v<T, bool>) {
288+
const auto& sharedDictionaryInput = selection.sharedDictionaryInput();
289+
NIMBLE_CHECK(
290+
sharedDictionaryInput.has_value(),
291+
"SharedDictionary encoding requires writer-provided dictionary "
292+
"indices.");
293+
NIMBLE_CHECK_EQ(
294+
sharedDictionaryInput->indices.size(),
295+
castedValues.size(),
296+
"SharedDictionary index count differs from value count.");
297+
EncodingSelectionPolicyCreator nestedPolicyCreator =
298+
[&selection](DataType nestedDataType)
299+
-> std::unique_ptr<EncodingSelectionPolicyBase> {
300+
NIMBLE_CHECK_EQ(
301+
nestedDataType,
302+
DataType::Uint32,
303+
"SharedDictionary index stream must use Uint32.");
304+
return selection.template createNestedPolicy<uint32_t>(
305+
EncodingType::SharedDictionary,
306+
EncodingIdentifiers::SharedDictionary::Indices);
307+
};
308+
return SharedDictionaryEncoding<T>::encode(
309+
sharedDictionaryInput->indices,
310+
nestedPolicyCreator,
311+
buffer,
312+
options);
313+
}
287314
NIMBLE_INCOMPATIBLE_ENCODING(
288-
"SharedDictionary encoding requires writer-provided dictionary "
289-
"indices.");
315+
"SharedDictionary encoding only supports non-bool integer data "
316+
"types.");
290317
}
291318
case EncodingType::FixedBitWidth: {
292319
if constexpr (isNumericType<physicalType>()) {
@@ -429,6 +456,15 @@ std::string_view EncodingFactory::encodeNullable(
429456
return NullableEncoding<T>::encodeNullable(
430457
selection, physicalValues, nulls, buffer, options);
431458
}
459+
case EncodingType::SharedDictionary: {
460+
if constexpr (isIntegralType<T>() && !std::is_same_v<T, bool>) {
461+
return SharedDictionaryEncoding<T>::encodeNullable(
462+
std::move(selection), physicalValues, nulls, buffer, options);
463+
}
464+
NIMBLE_INCOMPATIBLE_ENCODING(
465+
"SharedDictionary encoding only supports non-bool integer data "
466+
"types.");
467+
}
432468
default: {
433469
NIMBLE_UNSUPPORTED(
434470
"Encoding {} is not supported for nullable data.",

velox/dwio/nimble/encodings/common/EncodingFactory.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ class EncodingSelection;
3030
template <typename T>
3131
class EncodingSelectionPolicy;
3232

33+
template <typename T>
34+
class SharedDictionaryEncoding;
35+
3336
class EncodingFactory {
3437
public:
3538
explicit EncodingFactory(Encoding::Options options = {})
@@ -118,6 +121,8 @@ class EncodingFactory {
118121
friend class EncodingSelection<double>;
119122
friend class EncodingSelection<bool>;
120123
friend class EncodingSelection<std::string_view>;
124+
template <typename T>
125+
friend class SharedDictionaryEncoding;
121126
};
122127

123128
} // namespace facebook::nimble

velox/dwio/nimble/encodings/selection/EncodingSelection.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ namespace facebook::nimble {
7171

7272
class EncodingSelectionPolicyBase;
7373

74+
/// Writer-provided input for shared dictionary value-stream encoding.
75+
struct SharedDictionaryEncodingInput {
76+
/// One dictionary index for each non-null input value.
77+
std::span<const uint32_t> indices;
78+
};
79+
7480
/// Type representing a selected encoding.
7581
/// This is the result type returned from the select() method of an encoding
7682
/// selection policy. Also provides access to the compression policies for
@@ -85,6 +91,8 @@ struct EncodingSelectionResult {
8591
std::optional<uint64_t> estimatedSize{};
8692
std::function<std::unique_ptr<CompressionPolicy>()> compressionPolicyFactory =
8793
[]() { return std::make_unique<NoCompressionPolicy>(); };
94+
/// Additional input required when encodingType is SharedDictionary.
95+
std::optional<SharedDictionaryEncodingInput> sharedDictionaryInput{};
8896
};
8997

9098
/// The EncodingSelection class is passed in to the encode() method of each
@@ -114,6 +122,11 @@ class EncodingSelection {
114122
return policy;
115123
}
116124

125+
const std::optional<SharedDictionaryEncodingInput>& sharedDictionaryInput()
126+
const noexcept {
127+
return selectionResult_.sharedDictionaryInput;
128+
}
129+
117130
template <typename NestedT>
118131
std::unique_ptr<EncodingSelectionPolicyBase> createNestedPolicy(
119132
EncodingType parentEncodingType,

0 commit comments

Comments
 (0)