Skip to content

Commit ff3cd4d

Browse files
committed
feat: optimize predicate in
1 parent 22197d2 commit ff3cd4d

6 files changed

Lines changed: 974 additions & 5 deletions

File tree

src/paimon/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ set(PAIMON_COMMON_SRCS
124124
common/predicate/less_than.cpp
125125
common/predicate/like.cpp
126126
common/predicate/literal_converter.cpp
127+
common/predicate/literal_set.cpp
127128
common/predicate/literal.cpp
128129
common/predicate/not_equal.cpp
129130
common/predicate/not_in.cpp
@@ -604,6 +605,7 @@ if(PAIMON_BUILD_TESTS)
604605
common/options/memory_size_test.cpp
605606
common/options/time_duration_test.cpp
606607
common/predicate/literal_converter_test.cpp
608+
common/predicate/literal_set_test.cpp
607609
common/predicate/literal_test.cpp
608610
common/predicate/predicate_test.cpp
609611
common/predicate/predicate_utils_test.cpp

src/paimon/common/predicate/leaf_predicate_impl.h

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@
2020

2121
#include <memory>
2222
#include <string>
23+
#include <utility>
2324
#include <vector>
2425

2526
#include "arrow/api.h"
2627
#include "paimon/common/predicate/compound_function.h"
2728
#include "paimon/common/predicate/leaf_function.h"
2829
#include "paimon/common/predicate/literal_converter.h"
30+
#include "paimon/common/predicate/literal_set.h"
2931
#include "paimon/common/predicate/predicate_filter.h"
3032
#include "paimon/common/utils/checked_cast.h"
3133
#include "paimon/predicate/leaf_predicate.h"
@@ -35,7 +37,8 @@ class LeafPredicateImpl : public LeafPredicate, public PredicateFilter {
3537
LeafPredicateImpl(const LeafFunction& leaf_function, int32_t field_index,
3638
const std::string& field_name, const FieldType& field_type,
3739
const std::vector<Literal>& literals)
38-
: LeafPredicate(leaf_function, field_index, field_name, field_type, literals) {}
40+
: LeafPredicateImpl(leaf_function, field_index, field_name, field_type, literals,
41+
BuildLiteralSet(leaf_function, field_type, literals)) {}
3942

4043
const LeafFunction& GetLeafFunction() const {
4144
return leaf_function_;
@@ -49,6 +52,11 @@ class LeafPredicateImpl : public LeafPredicate, public PredicateFilter {
4952
struct_array.fields().size()));
5053
}
5154
const auto& field_array = struct_array.field(field_index_);
55+
if (literal_set_ && literal_set_->MatchesArrowType(*field_array)) {
56+
std::vector<char> is_valid(field_array->length(), 0);
57+
PAIMON_RETURN_NOT_OK(literal_set_->TestArray(*field_array, negate_in_, &is_valid));
58+
return is_valid;
59+
}
5260
return leaf_function_.Test(*field_array, literals_);
5361
}
5462

@@ -60,6 +68,9 @@ class LeafPredicateImpl : public LeafPredicate, public PredicateFilter {
6068
}
6169
PAIMON_ASSIGN_OR_RAISE(Literal value, LiteralConverter::ConvertLiteralsFromRow(
6270
schema, row, field_index_, field_type_));
71+
if (literal_set_ && value.GetType() == field_type_) {
72+
return literal_set_->TestValue(value, negate_in_);
73+
}
6374
return leaf_function_.Test(value, literals_);
6475
}
6576

@@ -86,14 +97,41 @@ class LeafPredicateImpl : public LeafPredicate, public PredicateFilter {
8697
return leaf_function_.Test(row_count, min_value, max_value, null_count, literals_);
8798
}
8899

100+
// Rebinding to another schema keeps the literals untouched, so the lookup structure is shared
101+
// instead of rebuilt for every reader.
89102
std::shared_ptr<LeafPredicateImpl> NewLeafPredicate(int32_t new_field_index) const {
90-
return std::make_shared<LeafPredicateImpl>(leaf_function_, new_field_index, field_name_,
91-
field_type_, literals_);
103+
return std::shared_ptr<LeafPredicateImpl>(new LeafPredicateImpl(
104+
leaf_function_, new_field_index, field_name_, field_type_, literals_, literal_set_));
92105
}
93106

94107
std::shared_ptr<LeafPredicateImpl> NewLeafPredicate(const std::string& new_field_name) const {
95-
return std::make_shared<LeafPredicateImpl>(leaf_function_, field_index_, new_field_name,
96-
field_type_, literals_);
108+
return std::shared_ptr<LeafPredicateImpl>(new LeafPredicateImpl(
109+
leaf_function_, field_index_, new_field_name, field_type_, literals_, literal_set_));
97110
}
111+
112+
private:
113+
LeafPredicateImpl(const LeafFunction& leaf_function, int32_t field_index,
114+
const std::string& field_name, const FieldType& field_type,
115+
const std::vector<Literal>& literals,
116+
std::shared_ptr<const LiteralSet> literal_set)
117+
: LeafPredicate(leaf_function, field_index, field_name, field_type, literals),
118+
literal_set_(std::move(literal_set)),
119+
negate_in_(leaf_function.GetType() == Function::Type::NOT_IN) {}
120+
121+
static std::shared_ptr<const LiteralSet> BuildLiteralSet(const LeafFunction& leaf_function,
122+
const FieldType& field_type,
123+
const std::vector<Literal>& literals) {
124+
Function::Type type = leaf_function.GetType();
125+
if (type != Function::Type::IN && type != Function::Type::NOT_IN) {
126+
return nullptr;
127+
}
128+
return LiteralSet::CreateOrNull(field_type, literals);
129+
}
130+
131+
// Built once at construction time and never mutated afterwards, so concurrent `Test` calls on
132+
// the same predicate stay safe. Null when the type or the literals are not supported, in which
133+
// case every path falls back to `leaf_function_`.
134+
std::shared_ptr<const LiteralSet> literal_set_;
135+
bool negate_in_;
98136
};
99137
} // namespace paimon

0 commit comments

Comments
 (0)