blob: fefe61ddb5ff8f487260e2bece8def2cd95a1099 [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 "vec/exprs/vsearch.h"
#include <memory>
#include <roaring/roaring.hh>
#include "common/logging.h"
#include "common/status.h"
#include "glog/logging.h"
#include "olap/rowset/segment_v2/inverted_index_reader.h"
#include "vec/columns/column_const.h"
#include "vec/exprs/vexpr_context.h"
#include "vec/exprs/vliteral.h"
#include "vec/exprs/vslot_ref.h"
#include "vec/functions/function_search.h"
namespace doris::vectorized {
using namespace segment_v2;
namespace {
struct SearchInputBundle {
std::unordered_map<std::string, IndexIterator*> iterators;
std::unordered_map<std::string, vectorized::IndexFieldNameAndTypePair> field_types;
std::vector<int> column_ids;
vectorized::ColumnsWithTypeAndName literal_args;
};
Status collect_search_inputs(const VSearchExpr& expr, VExprContext* context,
SearchInputBundle* bundle) {
DCHECK(bundle != nullptr);
auto index_context = context->get_inverted_index_context();
if (index_context == nullptr) {
return Status::OK();
}
for (const auto& child : expr.children()) {
if (child->is_slot_ref()) {
auto* column_slot_ref = assert_cast<VSlotRef*>(child.get());
int column_id = column_slot_ref->column_id();
auto* iterator = index_context->get_inverted_index_iterator_by_column_id(column_id);
if (iterator == nullptr) {
continue;
}
const auto* storage_name_type =
index_context->get_storage_name_and_type_by_column_id(column_id);
if (storage_name_type == nullptr) {
auto err_msg = fmt::format(
"storage_name_type cannot be found for column {} while in {} evaluate",
column_id, expr.expr_name());
LOG(ERROR) << err_msg;
return Status::InternalError(err_msg);
}
auto column_name = column_slot_ref->column_name();
bundle->iterators.emplace(column_name, iterator);
bundle->field_types.emplace(column_name, *storage_name_type);
bundle->column_ids.emplace_back(column_id);
} else if (child->is_literal()) {
auto* literal = assert_cast<VLiteral*>(child.get());
bundle->literal_args.emplace_back(literal->get_column_ptr(), literal->get_data_type(),
literal->expr_name());
} else {
LOG(WARNING) << "VSearchExpr: Unsupported child node type encountered";
return Status::InvalidArgument("search expression child type unsupported");
}
}
return Status::OK();
}
} // namespace
VSearchExpr::VSearchExpr(const TExprNode& node) : VExpr(node) {
if (node.__isset.search_param) {
_search_param = node.search_param;
_original_dsl = _search_param.original_dsl;
}
LOG(INFO) << "VSearchExpr constructor: dsl='" << _original_dsl
<< "', num_children=" << node.num_children
<< ", has_search_param=" << node.__isset.search_param
<< ", children_size=" << _children.size();
for (size_t i = 0; i < _children.size(); i++) {
LOG(INFO) << "VSearchExpr constructor: child[" << i
<< "] expr_name=" << _children[i]->expr_name();
}
}
const std::string& VSearchExpr::expr_name() const {
static const std::string name = "VSearchExpr";
return name;
}
Status VSearchExpr::execute(VExprContext* context, Block* block, int* result_column_id) {
if (fast_execute(context, block, result_column_id)) {
return Status::OK();
}
return Status::InternalError("SearchExpr should not be executed without inverted index");
}
Status VSearchExpr::evaluate_inverted_index(VExprContext* context, uint32_t segment_num_rows) {
LOG(INFO) << "VSearchExpr::evaluate_inverted_index called with DSL: " << _original_dsl;
if (_search_param.original_dsl.empty()) {
return Status::InvalidArgument("search DSL is empty");
}
auto index_context = context->get_inverted_index_context();
if (!index_context) {
LOG(WARNING) << "VSearchExpr: No inverted index context available";
return Status::OK();
}
SearchInputBundle bundle;
RETURN_IF_ERROR(collect_search_inputs(*this, context, &bundle));
if (bundle.iterators.empty()) {
LOG(WARNING) << "VSearchExpr: No indexed columns available for evaluation";
return Status::OK();
}
auto function = std::make_shared<FunctionSearch>();
auto result_bitmap = InvertedIndexResultBitmap();
auto status = function->evaluate_inverted_index_with_search_param(
_search_param, bundle.field_types, bundle.iterators, segment_num_rows, result_bitmap);
if (!status.ok()) {
LOG(WARNING) << "VSearchExpr: Function evaluation failed: " << status.to_string();
return status;
}
index_context->set_inverted_index_result_for_expr(this, result_bitmap);
for (int column_id : bundle.column_ids) {
index_context->set_true_for_inverted_index_status(this, column_id);
}
const auto& data_bitmap = result_bitmap.get_data_bitmap();
const uint64_t match_count = data_bitmap ? data_bitmap->cardinality() : 0;
if (match_count > 0) {
LOG(INFO) << "VSearchExpr: Found " << match_count
<< " matching rows for DSL: " << _search_param.original_dsl;
} else {
LOG(INFO) << "VSearchExpr: No matches found for DSL: " << _search_param.original_dsl;
}
return Status::OK();
}
} // namespace doris::vectorized