blob: 392dac73f160c2046dbbff45bbabbe64133c91ae [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 <optional>
#include <gtest/gtest.h>
#include "compute/delta/RoaringBitmapArray.h"
#include "operators/functions/delta/DeltaBitmapAggregator.h"
#include "velox/common/base/tests/GTestUtils.h"
#include "velox/exec/tests/utils/AssertQueryBuilder.h"
#include "velox/exec/tests/utils/HiveConnectorTestBase.h"
#include "velox/exec/tests/utils/PlanBuilder.h"
namespace gluten::delta {
namespace {
using facebook::velox::StringView;
using facebook::velox::exec::test::AssertQueryBuilder;
using facebook::velox::exec::test::HiveConnectorTestBase;
using facebook::velox::exec::test::PlanBuilder;
class DeltaBitmapAggregatorTest : public HiveConnectorTestBase {
protected:
void SetUp() override {
HiveConnectorTestBase::SetUp();
gluten::registerDeltaBitmapAggregator();
}
RoaringBitmapArray extractBitmap(
const facebook::velox::RowVectorPtr& results,
facebook::velox::vector_size_t row,
facebook::velox::column_index_t column,
int64_t expectedCardinality,
std::optional<int64_t> expectedLast) {
const auto bitmapResult = results->childAt(column)->as<facebook::velox::RowVector>();
EXPECT_EQ(bitmapResult->childAt(0)->asFlatVector<int64_t>()->valueAt(row), expectedCardinality);
if (expectedLast.has_value()) {
EXPECT_FALSE(bitmapResult->childAt(1)->isNullAt(row));
EXPECT_EQ(bitmapResult->childAt(1)->asFlatVector<int64_t>()->valueAt(row), expectedLast.value());
} else {
EXPECT_TRUE(bitmapResult->childAt(1)->isNullAt(row));
}
const auto payload = bitmapResult->childAt(2)->asFlatVector<StringView>()->valueAt(row);
RoaringBitmapArray bitmap;
bitmap.deserialize(payload.data(), payload.size());
return bitmap;
}
};
TEST_F(DeltaBitmapAggregatorTest, SingleAggregationIgnoresNullsAndDuplicates) {
const auto input = makeRowVector(
{"row_index"}, {makeNullableFlatVector<int64_t>({1, 7, 7, std::nullopt, static_cast<int64_t>(1ULL << 33)})});
const auto plan =
PlanBuilder(pool()).values({input}).singleAggregation({}, {"bitmapaggregator(row_index) AS dv"}).planNode();
const auto results = AssertQueryBuilder(plan).copyResults(pool());
ASSERT_EQ(results->size(), 1);
const auto bitmap = extractBitmap(results, 0, 0, 3, static_cast<int64_t>(1ULL << 33));
EXPECT_TRUE(bitmap.containsSafe(1));
EXPECT_TRUE(bitmap.containsSafe(7));
EXPECT_TRUE(bitmap.containsSafe(1ULL << 33));
EXPECT_FALSE(bitmap.containsSafe(2));
}
TEST_F(DeltaBitmapAggregatorTest, PartialFinalAggregationMergesPayloadsByGroup) {
const auto input = makeRowVector(
{"file_id", "row_index"},
{makeFlatVector<int64_t>({10, 10, 20, 10, 20, 20}),
makeFlatVector<int64_t>({1, 1, 3, static_cast<int64_t>(1ULL << 32), 5, 5})});
const auto plan = PlanBuilder(pool())
.values({input})
.partialAggregation({"file_id"}, {"bitmapaggregator(row_index) AS dv"})
.finalAggregation()
.planNode();
const auto results = AssertQueryBuilder(plan).copyResults(pool());
ASSERT_EQ(results->size(), 2);
for (facebook::velox::vector_size_t row = 0; row < results->size(); ++row) {
const auto fileId = results->childAt(0)->asFlatVector<int64_t>()->valueAt(row);
if (fileId == 10) {
const auto bitmap = extractBitmap(results, row, 1, 2, static_cast<int64_t>(1ULL << 32));
EXPECT_TRUE(bitmap.containsSafe(1));
EXPECT_TRUE(bitmap.containsSafe(1ULL << 32));
} else {
ASSERT_EQ(fileId, 20);
const auto bitmap = extractBitmap(results, row, 1, 2, 5);
EXPECT_TRUE(bitmap.containsSafe(3));
EXPECT_TRUE(bitmap.containsSafe(5));
}
}
}
TEST_F(DeltaBitmapAggregatorTest, AllNullInputProducesEmptyBitmap) {
const auto input = makeRowVector({"row_index"}, {makeNullableFlatVector<int64_t>({std::nullopt})});
const auto plan =
PlanBuilder(pool()).values({input}).singleAggregation({}, {"bitmapaggregator(row_index) AS dv"}).planNode();
const auto results = AssertQueryBuilder(plan).copyResults(pool());
ASSERT_EQ(results->size(), 1);
const auto bitmap = extractBitmap(results, 0, 0, 0, std::nullopt);
EXPECT_EQ(bitmap.cardinality(), 0);
}
TEST_F(DeltaBitmapAggregatorTest, RejectsNegativeRowIndexes) {
const auto input = makeRowVector({"row_index"}, {makeFlatVector<int64_t>({-1})});
const auto plan =
PlanBuilder(pool()).values({input}).singleAggregation({}, {"bitmapaggregator(row_index) AS dv"}).planNode();
VELOX_ASSERT_THROW(AssertQueryBuilder(plan).copyResults(pool()), "Delta bitmap row index cannot be negative");
}
TEST_F(DeltaBitmapAggregatorTest, RejectsRowIndexesAboveDeltaMax) {
const auto tooLarge = static_cast<int64_t>(RoaringBitmapArray::kMaxRepresentableValue + 1);
const auto input = makeRowVector({"row_index"}, {makeFlatVector<int64_t>({tooLarge})});
const auto plan =
PlanBuilder(pool()).values({input}).singleAggregation({}, {"bitmapaggregator(row_index) AS dv"}).planNode();
VELOX_ASSERT_THROW(AssertQueryBuilder(plan).copyResults(pool()), "exceeds max representable value");
}
} // namespace
} // namespace gluten::delta