blob: a9356ed7b4057ce20846109add7bdc600acd5332 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "paimon/core/stats/simple_stats_evolution.h"
#include <cassert>
#include <cstddef>
#include <string_view>
#include "paimon/common/data/binary_array.h"
#include "paimon/common/data/binary_array_writer.h"
#include "paimon/common/data/binary_row.h"
#include "paimon/common/data/binary_string.h"
#include "paimon/common/data/generic_row.h"
#include "paimon/common/data/internal_array.h"
#include "paimon/common/utils/object_utils.h"
#include "paimon/common/utils/projected_array.h"
#include "paimon/common/utils/projected_row.h"
#include "paimon/core/casting/casted_row.h"
#include "paimon/core/stats/simple_stats.h"
#include "paimon/core/utils/field_mapping.h"
#include "paimon/data/decimal.h"
#include "paimon/data/timestamp.h"
#include "paimon/status.h"
namespace paimon {
class Bytes;
class CastExecutor;
class InternalMap;
class InternalRow;
class MemoryPool;
SimpleStatsEvolution::SimpleStatsEvolution(const std::vector<DataField>& data_fields,
const std::vector<DataField>& table_fields,
bool need_mapping,
const std::shared_ptr<MemoryPool>& pool)
: need_mapping_(need_mapping), data_fields_(data_fields), table_fields_(table_fields) {
empty_values_ = std::make_shared<GenericRow>(data_fields.size());
empty_null_counts_ = std::make_shared<BinaryArray>();
BinaryArrayWriter array_writer(empty_null_counts_.get(), data_fields.size(),
/*element_size=*/sizeof(int64_t), pool.get());
for (size_t i = 0; i < data_fields.size(); ++i) {
array_writer.SetNullAt(i);
}
array_writer.Complete();
for (size_t i = 0; i < data_fields.size(); i++) {
const auto& data_field = data_fields[i];
id_to_data_fields_.emplace(data_field.Id(), std::make_pair(i, data_field));
}
std::map<std::string, DataField> name_to_table_fields;
for (const auto& field : table_fields) {
name_to_table_fields_.emplace(field.Name(), field);
}
}
class NullCountsEvoArray : public InternalArray {
public:
NullCountsEvoArray(const std::shared_ptr<InternalArray>& array,
const std::vector<int32_t>& mapping, int64_t not_found_value)
: array_(array), mapping_(mapping), not_found_value_(not_found_value) {
assert(array_);
}
int32_t Size() const override {
return mapping_.size();
}
bool IsNullAt(int32_t pos) const override {
assert(static_cast<size_t>(pos) < mapping_.size());
if (mapping_[pos] < 0) {
return false;
}
return array_->IsNullAt(mapping_[pos]);
}
int64_t GetLong(int32_t pos) const override {
if (mapping_[pos] < 0) {
return not_found_value_;
}
return array_->GetLong(mapping_[pos]);
}
private:
// ============================= Unsupported Methods ================================
bool GetBoolean(int32_t pos) const override;
char GetByte(int32_t pos) const override;
int16_t GetShort(int32_t pos) const override;
int32_t GetInt(int32_t pos) const override;
int32_t GetDate(int32_t pos) const override;
float GetFloat(int32_t pos) const override;
double GetDouble(int32_t pos) const override;
BinaryString GetString(int32_t pos) const override;
std::string_view GetStringView(int32_t pos) const override;
Decimal GetDecimal(int32_t pos, int32_t precision, int32_t scale) const override;
Timestamp GetTimestamp(int32_t pos, int32_t precision) const override;
std::shared_ptr<Bytes> GetBinary(int32_t pos) const override;
std::shared_ptr<InternalArray> GetArray(int32_t pos) const override;
std::shared_ptr<InternalMap> GetMap(int32_t pos) const override;
std::shared_ptr<InternalRow> GetRow(int32_t pos, int32_t num_fields) const override;
Result<std::vector<char>> ToBooleanArray() const override;
Result<std::vector<char>> ToByteArray() const override;
Result<std::vector<int16_t>> ToShortArray() const override;
Result<std::vector<int32_t>> ToIntArray() const override;
Result<std::vector<int64_t>> ToLongArray() const override;
Result<std::vector<float>> ToFloatArray() const override;
Result<std::vector<double>> ToDoubleArray() const override;
private:
std::shared_ptr<InternalArray> array_;
std::vector<int32_t> mapping_;
int64_t not_found_value_;
};
Result<SimpleStatsEvolution::EvolutionStats> SimpleStatsEvolution::Evolution(
const SimpleStats& stats, int64_t row_count,
const std::optional<std::vector<std::string>>& dense_fields) {
SimpleStatsEvolution::EvolutionStats evolution_stats(
std::make_shared<BinaryRow>(stats.MinValues()),
std::make_shared<BinaryRow>(stats.MaxValues()),
std::make_shared<BinaryArray>(stats.NullCounts()));
auto& min_values = evolution_stats.min_values;
auto& max_values = evolution_stats.max_values;
auto& null_counts = evolution_stats.null_counts;
if (dense_fields != std::nullopt && dense_fields.value().empty()) {
// optimize for empty dense fields
min_values = empty_values_;
max_values = empty_values_;
null_counts = empty_null_counts_;
} else if (dense_fields != std::nullopt) {
// create dense index mapping
std::vector<int32_t> data_idx_to_dense_idx;
std::optional<std::vector<int32_t>> cached_dense_idx =
dense_fields_mapping_.Find(dense_fields.value());
if (!cached_dense_idx) {
std::map<std::string, int32_t> field_name_to_dense_idx =
ObjectUtils::CreateIdentifierToIndexMap(dense_fields.value());
data_idx_to_dense_idx.resize(data_fields_.size(), -1);
for (size_t i = 0; i < data_fields_.size(); ++i) {
auto iter = field_name_to_dense_idx.find(data_fields_[i].Name());
if (iter != field_name_to_dense_idx.end()) {
data_idx_to_dense_idx[i] = iter->second;
}
}
dense_fields_mapping_.Insert(dense_fields.value(), data_idx_to_dense_idx);
} else {
data_idx_to_dense_idx = std::move(cached_dense_idx).value();
}
min_values = std::make_shared<ProjectedRow>(min_values, data_idx_to_dense_idx);
max_values = std::make_shared<ProjectedRow>(max_values, data_idx_to_dense_idx);
null_counts = std::make_shared<ProjectedArray>(null_counts, data_idx_to_dense_idx);
}
if (!need_mapping_) {
return evolution_stats;
}
return MappingStats(row_count, evolution_stats);
}
Result<SimpleStatsEvolution::EvolutionStats> SimpleStatsEvolution::MappingStats(
int64_t row_count, const SimpleStatsEvolution::EvolutionStats& src_stats) const {
SimpleStatsEvolution::EvolutionStats evolution_stats = src_stats;
auto& min_values = evolution_stats.min_values;
auto& max_values = evolution_stats.max_values;
auto& null_counts = evolution_stats.null_counts;
std::vector<int32_t> table_idx_to_data_idx(table_fields_.size(), -1);
std::vector<DataField> projected_data_fields;
projected_data_fields.reserve(table_fields_.size());
std::map<int32_t, int32_t> field_id_to_data_idx = ObjectUtils::CreateIdentifierToIndexMap(
data_fields_, [](const DataField& field) -> int32_t { return field.Id(); });
for (size_t i = 0; i < table_fields_.size(); ++i) {
auto iter = field_id_to_data_idx.find(table_fields_[i].Id());
if (iter != field_id_to_data_idx.end()) {
table_idx_to_data_idx[i] = iter->second;
projected_data_fields.push_back(data_fields_[iter->second]);
} else {
projected_data_fields.push_back(table_fields_[i]);
}
}
min_values = std::make_shared<ProjectedRow>(min_values, table_idx_to_data_idx);
max_values = std::make_shared<ProjectedRow>(max_values, table_idx_to_data_idx);
null_counts =
std::make_shared<NullCountsEvoArray>(null_counts, table_idx_to_data_idx, row_count);
// cast mapping
PAIMON_ASSIGN_OR_RAISE(
std::vector<std::shared_ptr<CastExecutor>> cast_executors,
FieldMappingBuilder::CreateDataCastExecutors(table_fields_, projected_data_fields));
bool need_cast = false;
for (const auto& executor : cast_executors) {
if (executor) {
need_cast = true;
break;
}
}
if (need_cast) {
PAIMON_ASSIGN_OR_RAISE(min_values, CastedRow::Create(cast_executors, projected_data_fields,
table_fields_, min_values));
PAIMON_ASSIGN_OR_RAISE(max_values, CastedRow::Create(cast_executors, projected_data_fields,
table_fields_, max_values));
}
return evolution_stats;
}
// ============================= Unsupported Methods ================================
bool NullCountsEvoArray::GetBoolean(int32_t pos) const {
assert(false);
return array_->GetBoolean(mapping_[pos]);
}
char NullCountsEvoArray::GetByte(int32_t pos) const {
assert(false);
return array_->GetByte(mapping_[pos]);
}
int16_t NullCountsEvoArray::GetShort(int32_t pos) const {
assert(false);
return array_->GetShort(mapping_[pos]);
}
int32_t NullCountsEvoArray::GetInt(int32_t pos) const {
assert(false);
return array_->GetInt(mapping_[pos]);
}
int32_t NullCountsEvoArray::GetDate(int32_t pos) const {
return NullCountsEvoArray::GetInt(pos);
}
float NullCountsEvoArray::GetFloat(int32_t pos) const {
assert(false);
return array_->GetFloat(mapping_[pos]);
}
double NullCountsEvoArray::GetDouble(int32_t pos) const {
assert(false);
return array_->GetDouble(mapping_[pos]);
}
BinaryString NullCountsEvoArray::GetString(int32_t pos) const {
assert(false);
return array_->GetString(mapping_[pos]);
}
std::string_view NullCountsEvoArray::GetStringView(int32_t pos) const {
assert(false);
return array_->GetStringView(mapping_[pos]);
}
Decimal NullCountsEvoArray::GetDecimal(int32_t pos, int32_t precision, int32_t scale) const {
assert(false);
return array_->GetDecimal(mapping_[pos], precision, scale);
}
Timestamp NullCountsEvoArray::GetTimestamp(int32_t pos, int32_t precision) const {
assert(false);
return array_->GetTimestamp(mapping_[pos], precision);
}
std::shared_ptr<Bytes> NullCountsEvoArray::GetBinary(int32_t pos) const {
assert(false);
return array_->GetBinary(mapping_[pos]);
}
std::shared_ptr<InternalArray> NullCountsEvoArray::GetArray(int32_t pos) const {
assert(false);
return array_->GetArray(mapping_[pos]);
}
std::shared_ptr<InternalMap> NullCountsEvoArray::GetMap(int32_t pos) const {
assert(false);
return array_->GetMap(mapping_[pos]);
}
std::shared_ptr<InternalRow> NullCountsEvoArray::GetRow(int32_t pos, int32_t num_fields) const {
assert(false);
return array_->GetRow(mapping_[pos], num_fields);
}
Result<std::vector<char>> NullCountsEvoArray::ToBooleanArray() const {
return Status::Invalid("NullCountsEvoArray do not support convert to boolean array");
}
Result<std::vector<char>> NullCountsEvoArray::ToByteArray() const {
return Status::Invalid("NullCountsEvoArray do not support convert to byte array");
}
Result<std::vector<int16_t>> NullCountsEvoArray::ToShortArray() const {
return Status::Invalid("NullCountsEvoArray do not support convert to short array");
}
Result<std::vector<int32_t>> NullCountsEvoArray::ToIntArray() const {
return Status::Invalid("NullCountsEvoArray do not support convert to int array");
}
Result<std::vector<int64_t>> NullCountsEvoArray::ToLongArray() const {
return Status::Invalid("NullCountsEvoArray do not support convert to long array");
}
Result<std::vector<float>> NullCountsEvoArray::ToFloatArray() const {
return Status::Invalid("NullCountsEvoArray do not support convert to float array");
}
Result<std::vector<double>> NullCountsEvoArray::ToDoubleArray() const {
return Status::Invalid("NullCountsEvoArray do not support convert to double array");
}
} // namespace paimon