// Licensed to the LF AI & Data foundation 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 "BinaryArithOpEvalRangeExpr.h" namespace milvus { namespace exec { void PhyBinaryArithOpEvalRangeExpr::Eval(EvalCtx& context, VectorPtr& result) { auto input = context.get_offset_input(); SetHasOffsetInput((input != nullptr)); switch (expr_->column_.data_type_) { case DataType::BOOL: { result = ExecRangeVisitorImpl(input); break; } case DataType::INT8: { result = ExecRangeVisitorImpl(input); break; } case DataType::INT16: { result = ExecRangeVisitorImpl(input); break; } case DataType::INT32: { result = ExecRangeVisitorImpl(input); break; } case DataType::INT64: { result = ExecRangeVisitorImpl(input); break; } case DataType::FLOAT: { result = ExecRangeVisitorImpl(input); break; } case DataType::DOUBLE: { result = ExecRangeVisitorImpl(input); break; } case DataType::JSON: { auto value_type = expr_->value_.val_case(); switch (value_type) { case proto::plan::GenericValue::ValCase::kBoolVal: { result = ExecRangeVisitorImplForJson(input); break; } case proto::plan::GenericValue::ValCase::kInt64Val: { result = ExecRangeVisitorImplForJson(input); break; } case proto::plan::GenericValue::ValCase::kFloatVal: { result = ExecRangeVisitorImplForJson(input); break; } default: { ThrowInfo( DataTypeInvalid, fmt::format("unsupported value type {} in expression", value_type)); } } break; } case DataType::ARRAY: { auto value_type = expr_->value_.val_case(); switch (value_type) { case proto::plan::GenericValue::ValCase::kInt64Val: { SetNotUseIndex(); result = ExecRangeVisitorImplForArray(input); break; } case proto::plan::GenericValue::ValCase::kFloatVal: { SetNotUseIndex(); result = ExecRangeVisitorImplForArray(input); break; } default: { ThrowInfo( DataTypeInvalid, fmt::format("unsupported value type {} in expression", value_type)); } } break; } default: ThrowInfo(DataTypeInvalid, "unsupported data type: {}", expr_->column_.data_type_); } } template VectorPtr PhyBinaryArithOpEvalRangeExpr::ExecRangeVisitorImplForJson( OffsetVector* input) { using GetType = std::conditional_t, std::string_view, ValueType>; auto real_batch_size = has_offset_input_ ? input->size() : GetNextBatchSize(); if (real_batch_size == 0) { return nullptr; } auto res_vec = std::make_shared(TargetBitmap(real_batch_size, false), TargetBitmap(real_batch_size, true)); TargetBitmapView res(res_vec->GetRawData(), real_batch_size); TargetBitmapView valid_res(res_vec->GetValidRawData(), real_batch_size); if (!arg_inited_) { value_arg_.SetValue(expr_->value_); if (expr_->arith_op_type_ == proto::plan::ArithOpType::ArrayLength) { right_operand_arg_.SetValue(ValueType()); } else { right_operand_arg_.SetValue(expr_->right_operand_); } arg_inited_ = true; } auto pointer = milvus::Json::pointer(expr_->column_.nested_path_); auto op_type = expr_->op_type_; auto arith_type = expr_->arith_op_type_; auto value = value_arg_.GetValue(); auto right_operand = right_operand_arg_.GetValue(); #define BinaryArithRangeJSONCompare(cmp) \ do { \ for (size_t i = 0; i < size; ++i) { \ auto offset = i; \ if constexpr (filter_type == FilterType::random) { \ offset = (offsets) ? offsets[i] : i; \ } \ if (valid_data != nullptr && !valid_data[offset]) { \ res[i] = false; \ valid_res[i] = false; \ continue; \ } \ auto x = data[offset].template at(pointer); \ if (x.error()) { \ if constexpr (std::is_same_v) { \ auto x = data[offset].template at(pointer); \ res[i] = !x.error() && (cmp); \ continue; \ } \ res[i] = false; \ continue; \ } \ res[i] = (cmp); \ } \ } while (false) #define BinaryArithRangeJSONCompareNotEqual(cmp) \ do { \ for (size_t i = 0; i < size; ++i) { \ auto offset = i; \ if constexpr (filter_type == FilterType::random) { \ offset = (offsets) ? offsets[i] : i; \ } \ if (valid_data != nullptr && !valid_data[offset]) { \ res[i] = false; \ valid_res[i] = false; \ continue; \ } \ auto x = data[offset].template at(pointer); \ if (x.error()) { \ if constexpr (std::is_same_v) { \ auto x = data[offset].template at(pointer); \ res[i] = x.error() || (cmp); \ continue; \ } \ res[i] = true; \ continue; \ } \ res[i] = (cmp); \ } \ } while (false) #define BinaryArithRangeJONCompareArrayLength(cmp) \ do { \ for (size_t i = 0; i < size; ++i) { \ auto offset = i; \ if constexpr (filter_type == FilterType::random) { \ offset = (offsets) ? offsets[i] : i; \ } \ if (valid_data != nullptr && !valid_data[offset]) { \ res[i] = false; \ valid_res[i] = false; \ continue; \ } \ int array_length = 0; \ auto doc = data[offset].doc(); \ auto array = doc.at_pointer(pointer).get_array(); \ if (!array.error()) { \ array_length = array.count_elements(); \ } \ res[i] = (cmp); \ } \ } while (false) auto execute_sub_batch = [ op_type, arith_type ]( const milvus::Json* data, const bool* valid_data, const int32_t* offsets, const int size, TargetBitmapView res, TargetBitmapView valid_res, ValueType val, ValueType right_operand, const std::string& pointer) { switch (op_type) { case proto::plan::OpType::Equal: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeJSONCompare(x.value() + right_operand == val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeJSONCompare(x.value() - right_operand == val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeJSONCompare(x.value() * right_operand == val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeJSONCompare(x.value() / right_operand == val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeJSONCompare( safe_mod(x.value(), right_operand) == val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeJONCompareArrayLength(array_length == val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::NotEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeJSONCompareNotEqual( x.value() + right_operand != val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeJSONCompareNotEqual( x.value() - right_operand != val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeJSONCompareNotEqual( x.value() * right_operand != val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeJSONCompareNotEqual( x.value() / right_operand != val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeJSONCompareNotEqual( safe_mod(x.value(), right_operand) != val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeJONCompareArrayLength(array_length != val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::GreaterThan: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeJSONCompare(x.value() + right_operand > val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeJSONCompare(x.value() - right_operand > val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeJSONCompare(x.value() * right_operand > val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeJSONCompare(x.value() / right_operand > val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeJSONCompare( safe_mod(x.value(), right_operand) > val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeJONCompareArrayLength(array_length > val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::GreaterEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeJSONCompare(x.value() + right_operand >= val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeJSONCompare(x.value() - right_operand >= val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeJSONCompare(x.value() * right_operand >= val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeJSONCompare(x.value() / right_operand >= val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeJSONCompare( safe_mod(x.value(), right_operand) >= val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeJONCompareArrayLength(array_length >= val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::LessThan: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeJSONCompare(x.value() + right_operand < val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeJSONCompare(x.value() - right_operand < val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeJSONCompare(x.value() * right_operand < val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeJSONCompare(x.value() / right_operand < val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeJSONCompare( safe_mod(x.value(), right_operand) < val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeJONCompareArrayLength(array_length < val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::LessEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeJSONCompare(x.value() + right_operand <= val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeJSONCompare(x.value() - right_operand <= val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeJSONCompare(x.value() * right_operand <= val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeJSONCompare(x.value() / right_operand <= val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeJSONCompare( safe_mod(x.value(), right_operand) <= val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeJONCompareArrayLength(array_length <= val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } default: ThrowInfo(OpTypeInvalid, "unsupported operator type for binary " "arithmetic eval expr: {}", op_type); } }; int64_t processed_size; if (has_offset_input_) { processed_size = ProcessDataByOffsets(execute_sub_batch, std::nullptr_t{}, input, res, valid_res, value, right_operand, pointer); } else { processed_size = ProcessDataChunks(execute_sub_batch, std::nullptr_t{}, res, valid_res, value, right_operand, pointer); } AssertInfo(processed_size == real_batch_size, "internal error: expr processed rows {} not equal " "expect batch size {}", processed_size, real_batch_size); return res_vec; } template VectorPtr PhyBinaryArithOpEvalRangeExpr::ExecRangeVisitorImplForArray( OffsetVector* input) { using GetType = std::conditional_t, std::string_view, ValueType>; auto real_batch_size = has_offset_input_ ? input->size() : GetNextBatchSize(); if (!arg_inited_) { value_arg_.SetValue(expr_->value_); if (expr_->arith_op_type_ == proto::plan::ArithOpType::ArrayLength) { right_operand_arg_.SetValue(ValueType()); } else { right_operand_arg_.SetValue(expr_->right_operand_); } arg_inited_ = true; } if (real_batch_size == 0) { return nullptr; } auto res_vec = std::make_shared(TargetBitmap(real_batch_size, false), TargetBitmap(real_batch_size, true)); TargetBitmapView res(res_vec->GetRawData(), real_batch_size); TargetBitmapView valid_res(res_vec->GetValidRawData(), real_batch_size); int index = -1; if (expr_->column_.nested_path_.size() > 0) { index = std::stoi(expr_->column_.nested_path_[0]); } auto op_type = expr_->op_type_; auto arith_type = expr_->arith_op_type_; auto value = value_arg_.GetValue(); auto right_operand = right_operand_arg_.GetValue(); #define BinaryArithRangeArrayCompare(cmp) \ do { \ for (size_t i = 0; i < size; ++i) { \ auto offset = i; \ if constexpr (filter_type == FilterType::random) { \ offset = (offsets) ? offsets[i] : i; \ } \ if (valid_data != nullptr && !valid_data[offset]) { \ res[i] = false; \ valid_res[i] = false; \ continue; \ } \ if (index >= data[offset].length()) { \ res[i] = false; \ continue; \ } \ auto value = data[offset].get_data(index); \ res[i] = (cmp); \ } \ } while (false) #define BinaryArithRangeArrayLengthCompate(cmp) \ do { \ for (size_t i = 0; i < size; ++i) { \ auto offset = i; \ if constexpr (filter_type == FilterType::random) { \ offset = (offsets) ? offsets[i] : i; \ } \ if (valid_data != nullptr && !valid_data[offset]) { \ res[i] = valid_res[i] = false; \ continue; \ } \ res[i] = (cmp); \ } \ } while (false) auto execute_sub_batch = [ op_type, arith_type ]( const ArrayView* data, const bool* valid_data, const int32_t* offsets, const int size, TargetBitmapView res, TargetBitmapView valid_res, ValueType val, ValueType right_operand, int index) { switch (op_type) { case proto::plan::OpType::Equal: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeArrayCompare(value + right_operand == val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeArrayCompare(value - right_operand == val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeArrayCompare(value * right_operand == val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeArrayCompare(value / right_operand == val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeArrayCompare( safe_mod(value, right_operand) == val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeArrayLengthCompate( data[offset].length() == val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::NotEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeArrayCompare(value + right_operand != val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeArrayCompare(value - right_operand != val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeArrayCompare(value * right_operand != val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeArrayCompare(value / right_operand != val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeArrayCompare( safe_mod(value, right_operand) != val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeArrayLengthCompate( data[offset].length() != val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::GreaterThan: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeArrayCompare(value + right_operand > val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeArrayCompare(value - right_operand > val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeArrayCompare(value * right_operand > val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeArrayCompare(value / right_operand > val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeArrayCompare( safe_mod(value, right_operand) > val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeArrayLengthCompate( data[offset].length() > val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::GreaterEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeArrayCompare(value + right_operand >= val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeArrayCompare(value - right_operand >= val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeArrayCompare(value * right_operand >= val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeArrayCompare(value / right_operand >= val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeArrayCompare( safe_mod(value, right_operand) >= val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeArrayLengthCompate( data[offset].length() >= val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::LessThan: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeArrayCompare(value + right_operand < val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeArrayCompare(value - right_operand < val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeArrayCompare(value * right_operand < val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeArrayCompare(value / right_operand < val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeArrayCompare( safe_mod(value, right_operand) < val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeArrayLengthCompate( data[offset].length() < val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::LessEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { BinaryArithRangeArrayCompare(value + right_operand <= val); break; } case proto::plan::ArithOpType::Sub: { BinaryArithRangeArrayCompare(value - right_operand <= val); break; } case proto::plan::ArithOpType::Mul: { BinaryArithRangeArrayCompare(value * right_operand <= val); break; } case proto::plan::ArithOpType::Div: { BinaryArithRangeArrayCompare(value / right_operand <= val); break; } case proto::plan::ArithOpType::Mod: { BinaryArithRangeArrayCompare( safe_mod(value, right_operand) <= val); break; } case proto::plan::ArithOpType::ArrayLength: { BinaryArithRangeArrayLengthCompate( data[offset].length() <= val); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } default: ThrowInfo(OpTypeInvalid, "unsupported operator type for binary " "arithmetic eval expr: {}", op_type); } }; int64_t processed_size; if (has_offset_input_) { processed_size = ProcessDataByOffsets(execute_sub_batch, std::nullptr_t{}, input, res, valid_res, value, right_operand, index); } else { processed_size = ProcessDataChunks(execute_sub_batch, std::nullptr_t{}, res, valid_res, value, right_operand, index); } AssertInfo(processed_size == real_batch_size, "internal error: expr processed rows {} not equal " "expect batch size {}", processed_size, real_batch_size); return res_vec; } template VectorPtr PhyBinaryArithOpEvalRangeExpr::ExecRangeVisitorImpl(OffsetVector* input) { if (CanUseIndex()) { return ExecRangeVisitorImplForIndex(input); } else { return ExecRangeVisitorImplForData(input); } } template VectorPtr PhyBinaryArithOpEvalRangeExpr::ExecRangeVisitorImplForIndex( OffsetVector* input) { using Index = index::ScalarIndex; typedef std::conditional_t && !std::is_same_v, int64_t, T> HighPrecisionType; auto real_batch_size = has_offset_input_ ? input->size() : GetNextBatchSize(); if (real_batch_size == 0) { return nullptr; } if (!arg_inited_) { value_arg_.SetValue(expr_->value_); right_operand_arg_.SetValue(expr_->right_operand_); arg_inited_ = true; } auto value = value_arg_.GetValue(); auto right_operand = right_operand_arg_.GetValue(); auto op_type = expr_->op_type_; auto arith_type = expr_->arith_op_type_; auto sub_batch_size = has_offset_input_ ? input->size() : size_per_chunk_; auto execute_sub_batch = [ op_type, arith_type, sub_batch_size ]( Index * index_ptr, HighPrecisionType value, HighPrecisionType right_operand, const int32_t* offsets = nullptr) { TargetBitmap res; switch (op_type) { case proto::plan::OpType::Equal: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Sub: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mul: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Div: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mod: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::NotEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Sub: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mul: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Div: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mod: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::GreaterThan: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Sub: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mul: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Div: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mod: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::GreaterEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Sub: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mul: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Div: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mod: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::LessThan: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Sub: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mul: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Div: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mod: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::LessEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Sub: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mul: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Div: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } case proto::plan::ArithOpType::Mod: { ArithOpIndexFunc func; res = std::move(func(index_ptr, sub_batch_size, value, right_operand, offsets)); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } default: ThrowInfo(OpTypeInvalid, "unsupported operator type for binary " "arithmetic eval expr: {}", op_type); } return res; }; if (has_offset_input_) { auto res = ProcessIndexChunksByOffsets( execute_sub_batch, input, value, right_operand); AssertInfo(res->size() == real_batch_size, "internal error: expr processed rows {} not equal " "expect batch size {}", res->size(), real_batch_size); return res; } else { auto res = ProcessIndexChunks(execute_sub_batch, value, right_operand); AssertInfo(res->size() == real_batch_size, "internal error: expr processed rows {} not equal " "expect batch size {}", res->size(), real_batch_size); return res; } } template VectorPtr PhyBinaryArithOpEvalRangeExpr::ExecRangeVisitorImplForData( OffsetVector* input) { typedef std::conditional_t && !std::is_same_v, int64_t, T> HighPrecisionType; auto real_batch_size = has_offset_input_ ? input->size() : GetNextBatchSize(); if (real_batch_size == 0) { return nullptr; } auto res_vec = std::make_shared(TargetBitmap(real_batch_size, false), TargetBitmap(real_batch_size, true)); TargetBitmapView res(res_vec->GetRawData(), real_batch_size); TargetBitmapView valid_res(res_vec->GetValidRawData(), real_batch_size); if (!arg_inited_) { value_arg_.SetValue(expr_->value_); right_operand_arg_.SetValue(expr_->right_operand_); arg_inited_ = true; } auto value = value_arg_.GetValue(); auto right_operand = right_operand_arg_.GetValue(); auto op_type = expr_->op_type_; auto arith_type = expr_->arith_op_type_; auto execute_sub_batch = [ op_type, arith_type ]( const T* data, const bool* valid_data, const int32_t* offsets, const int size, TargetBitmapView res, TargetBitmapView valid_res, HighPrecisionType value, HighPrecisionType right_operand) { switch (op_type) { case proto::plan::OpType::Equal: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Sub: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mul: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Div: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mod: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::NotEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Sub: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mul: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Div: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mod: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::GreaterThan: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Sub: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mul: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Div: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mod: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::GreaterEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Sub: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mul: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Div: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mod: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::LessThan: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Sub: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mul: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Div: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mod: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } case proto::plan::OpType::LessEqual: { switch (arith_type) { case proto::plan::ArithOpType::Add: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Sub: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mul: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Div: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } case proto::plan::ArithOpType::Mod: { ArithOpElementFunc func; func(data, size, value, right_operand, res, offsets); break; } default: ThrowInfo( OpTypeInvalid, fmt::format("unsupported arith type for binary " "arithmetic eval expr: {}", arith_type)); } break; } default: ThrowInfo(OpTypeInvalid, "unsupported operator type for binary " "arithmetic eval expr: {}", op_type); } // there is a batch operation in ArithOpElementFunc, // so not divide data again for the reason that it may reduce performance if the null distribution is scattered // but to mask res with valid_data after the batch operation. if (valid_data != nullptr) { for (int i = 0; i < size; i++) { auto offset = i; if constexpr (filter_type == FilterType::random) { offset = (offsets) ? offsets[i] : i; } if (!valid_data[offset]) { res[i] = valid_res[i] = false; } } } }; int64_t processed_size; if (has_offset_input_) { processed_size = ProcessDataByOffsets(execute_sub_batch, std::nullptr_t{}, input, res, valid_res, value, right_operand); } else { processed_size = ProcessDataChunks(execute_sub_batch, std::nullptr_t{}, res, valid_res, value, right_operand); } AssertInfo(processed_size == real_batch_size, "internal error: expr processed rows {} not equal " "expect batch size {}", processed_size, real_batch_size); return res_vec; } } //namespace exec } // namespace milvus