blob: 0f82b5225e666eff04efd088f1379cd0af6095cf [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 "storage/index/inverted/inverted_index_writer.h"
#include "storage/index/inverted/analyzer/analyzer.h"
#include "storage/index/inverted/inverted_index_common.h"
#include "storage/index/inverted/inverted_index_fs_directory.h"
#include "storage/key_coder.h"
#include "storage/tablet/tablet_schema.h"
#include "util/faststring.h"
namespace doris::segment_v2 {
const int32_t MAX_FIELD_LEN = 0x7FFFFFFFL;
const int32_t MERGE_FACTOR = 100000000;
const int32_t MAX_LEAF_COUNT = 1024;
const float MAXMBSortInHeap = 512.0 * 8;
const int DIMS = 1;
template <FieldType field_type>
InvertedIndexColumnWriter<field_type>::InvertedIndexColumnWriter(const std::string& field_name,
IndexFileWriter* index_file_writer,
const TabletIndex* index_meta,
const bool single_field)
: _single_field(single_field),
_index_meta(index_meta),
_index_file_writer(index_file_writer) {
_should_analyzer =
inverted_index::InvertedIndexAnalyzer::should_analyzer(_index_meta->properties());
_value_key_coder = get_key_coder(field_type);
_field_name = StringUtil::string_to_wstring(field_name);
}
template <FieldType field_type>
InvertedIndexColumnWriter<field_type>::~InvertedIndexColumnWriter() {
if (_index_writer != nullptr) {
close_on_error();
}
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::init() {
try {
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::init_field_type_not_supported", {
return Status::Error<doris::ErrorCode::INVERTED_INDEX_NOT_SUPPORTED>(
"Field type not supported");
})
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::init_inverted_index_writer_init_error",
{ _CLTHROWA(CL_ERR_IO, "debug point: init index error"); })
if constexpr (field_is_slice_type(field_type)) {
return init_fulltext_index();
} else if constexpr (field_is_numeric_type(field_type)) {
return init_bkd_index();
}
return Status::Error<doris::ErrorCode::INVERTED_INDEX_NOT_SUPPORTED>(
"Field type not supported");
} catch (const CLuceneError& e) {
LOG(WARNING) << "Inverted index writer init error occurred: " << e.what();
return Status::Error<doris::ErrorCode::INVERTED_INDEX_CLUCENE_ERROR>(
"Inverted index writer init error occurred: {}", e.what());
}
}
template <FieldType field_type>
void InvertedIndexColumnWriter<field_type>::close_on_error() {
try {
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::close_on_error_throw_exception",
{ _CLTHROWA(CL_ERR_IO, "debug point: close on error"); })
// delete directory must be done before index_writer close
// because index_writer will close the directory
if (_dir) {
_dir->deleteDirectory();
}
if (_index_writer) {
_index_writer->close();
}
} catch (CLuceneError& e) {
LOG(ERROR) << "InvertedIndexWriter close_on_error failure: " << e.what();
}
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::init_bkd_index() {
size_t value_length = sizeof(CppType);
// NOTE: initialize with 0, set to max_row_id when finished.
int32_t max_doc = 0;
int32_t total_point_count = std::numeric_limits<std::int32_t>::max();
_bkd_writer = std::make_shared<lucene::util::bkd::bkd_writer>(
max_doc, DIMS, DIMS, value_length, MAX_LEAF_COUNT, MAXMBSortInHeap, total_point_count,
true, config::max_depth_in_bkd_tree);
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::init_bkd_index_throw_error",
{ _CLTHROWA(CL_ERR_IllegalArgument, "debug point: create bkd_writer error"); })
return open_index_directory();
}
template <FieldType field_type>
Result<ReaderPtr> InvertedIndexColumnWriter<field_type>::create_char_string_reader(
CharFilterMap& char_filter_map) {
try {
return inverted_index::InvertedIndexAnalyzer::create_reader(char_filter_map);
} catch (CLuceneError& e) {
return ResultError(Status::Error<doris::ErrorCode::INVERTED_INDEX_CLUCENE_ERROR>(
"inverted index create string reader failed: {}", e.what()));
}
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::open_index_directory() {
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::open_index_directory_error", {
return Status::Error<ErrorCode::INTERNAL_ERROR>("debug point: open_index_directory_error");
})
_dir = DORIS_TRY(_index_file_writer->open(_index_meta));
return Status::OK();
}
template <FieldType field_type>
std::unique_ptr<lucene::index::IndexWriter>
InvertedIndexColumnWriter<field_type>::create_index_writer() {
bool create_index = true;
bool close_dir_on_shutdown = true;
auto index_writer = std::make_unique<lucene::index::IndexWriter>(
_dir.get(), _analyzer.get(), create_index, close_dir_on_shutdown);
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::create_index_writer_setRAMBufferSizeMB_error",
{ index_writer->setRAMBufferSizeMB(-100); })
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::create_index_writer_setMaxBufferedDocs_error",
{ index_writer->setMaxBufferedDocs(1); })
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::create_index_writer_setMergeFactor_error",
{ index_writer->setMergeFactor(1); })
index_writer->setRAMBufferSizeMB(static_cast<float>(config::inverted_index_ram_buffer_size));
index_writer->setMaxBufferedDocs(config::inverted_index_max_buffered_docs);
index_writer->setMaxFieldLength(MAX_FIELD_LEN);
index_writer->setMergeFactor(MERGE_FACTOR);
index_writer->setUseCompoundFile(false);
index_writer->setEnableCorrectTermWrite(config::enable_inverted_index_correct_term_write);
index_writer->setSimilarity(_similarity.get());
return index_writer;
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::create_field(lucene::document::Field** field) {
int field_config =
int(lucene::document::Field::STORE_NO) | int(lucene::document::Field::INDEX_NONORMS);
field_config |= _should_analyzer ? int32_t(lucene::document::Field::INDEX_TOKENIZED)
: int32_t(lucene::document::Field::INDEX_UNTOKENIZED);
*field = new lucene::document::Field(_field_name.c_str(), field_config);
(*field)->setOmitTermFreqAndPositions(
!(get_parser_phrase_support_string_from_properties(_index_meta->properties()) ==
INVERTED_INDEX_PARSER_PHRASE_SUPPORT_YES));
if (_should_analyzer) {
(*field)->setOmitNorms(false);
}
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::always_omit_norms",
{ (*field)->setOmitNorms(false); });
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::create_field_v3", {
if (_index_file_writer->get_storage_format() != InvertedIndexStorageFormatPB::V3) {
return Status::Error<doris::ErrorCode::INVERTED_INDEX_CLUCENE_ERROR>(
"debug point: InvertedIndexColumnWriter::create_field_v3 error");
}
})
if (_index_file_writer->get_storage_format() >= InvertedIndexStorageFormatPB::V3) {
(*field)->setIndexVersion(IndexVersion::kV4);
// Only effective in v3
std::string dict_compression =
get_parser_dict_compression_from_properties(_index_meta->properties());
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::create_field_dic_compression", {
if (dict_compression != INVERTED_INDEX_PARSER_TRUE) {
return Status::Error<doris::ErrorCode::INVERTED_INDEX_CLUCENE_ERROR>(
"debug point: "
"InvertedIndexColumnWriter::create_field_dic_compression error");
}
})
if (dict_compression == INVERTED_INDEX_PARSER_TRUE) {
(*field)->updateFlag(FlagBits::DICT_COMPRESS);
}
}
return Status::OK();
}
template <FieldType field_type>
Result<std::shared_ptr<lucene::analysis::Analyzer>>
InvertedIndexColumnWriter<field_type>::create_analyzer(
const InvertedIndexAnalyzerConfig& analyzer_config) {
try {
return inverted_index::InvertedIndexAnalyzer::create_analyzer(&analyzer_config);
} catch (CLuceneError& e) {
return ResultError(Status::Error<doris::ErrorCode::INVERTED_INDEX_ANALYZER_ERROR>(
"inverted index create analyzer failed: {}", e.what()));
} catch (Exception& e) {
return ResultError(Status::Error<doris::ErrorCode::INVERTED_INDEX_ANALYZER_ERROR>(
"inverted index create analyzer failed: {}", e.what()));
}
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::init_fulltext_index() {
_analyzer_config.analyzer_name = get_analyzer_name_from_properties(_index_meta->properties());
_analyzer_config.parser_type = get_inverted_index_parser_type_from_string(
get_parser_string_from_properties(_index_meta->properties()));
_analyzer_config.parser_mode =
get_parser_mode_string_from_properties(_index_meta->properties());
_analyzer_config.char_filter_map =
get_parser_char_filter_map_from_properties(_index_meta->properties());
_analyzer_config.lower_case =
get_parser_lowercase_from_properties<true>(_index_meta->properties());
_analyzer_config.stop_words = get_parser_stopwords_from_properties(_index_meta->properties());
RETURN_IF_ERROR(open_index_directory());
_char_string_reader = DORIS_TRY(create_char_string_reader(_analyzer_config.char_filter_map));
if (_should_analyzer) {
_analyzer = DORIS_TRY(create_analyzer(_analyzer_config));
}
_similarity = std::make_unique<lucene::search::LengthSimilarity>();
_index_writer = create_index_writer();
_doc = std::make_unique<lucene::document::Document>();
if (_single_field) {
RETURN_IF_ERROR(create_field(&_field));
_doc->add(*_field);
} else {
// array's inverted index do need create field first
_doc->setNeedResetFieldData(true);
}
auto ignore_above_value =
get_parser_ignore_above_value_from_properties(_index_meta->properties());
_ignore_above = std::stoi(ignore_above_value);
return Status::OK();
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::add_document() {
DBUG_EXECUTE_IF("inverted_index_writer.add_document", { return Status::OK(); });
try {
_index_writer->addDocument(_doc.get());
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::add_document_throw_error",
{ _CLTHROWA(CL_ERR_IO, "debug point: add_document io error"); })
} catch (const CLuceneError& e) {
close_on_error();
return Status::Error<ErrorCode::INVERTED_INDEX_CLUCENE_ERROR>(
"CLuceneError add_document: {}", e.what());
}
return Status::OK();
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::add_null_document() {
try {
_index_writer->addNullDocument(_doc.get());
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::add_null_document_throw_error",
{ _CLTHROWA(CL_ERR_IO, "debug point: add_null_document io error"); })
} catch (const CLuceneError& e) {
close_on_error();
return Status::Error<ErrorCode::INVERTED_INDEX_CLUCENE_ERROR>(
"CLuceneError add_null_document: {}", e.what());
}
return Status::OK();
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::add_nulls(uint32_t count) {
_null_bitmap.addRange(_rid, _rid + count);
_rid += count;
if constexpr (field_is_slice_type(field_type)) {
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::add_nulls_field_nullptr", { _field = nullptr; })
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::add_nulls_index_writer_nullptr",
{ _index_writer = nullptr; })
if (_field == nullptr || _index_writer == nullptr) {
LOG(ERROR) << "field or index writer is null in inverted index writer.";
return Status::InternalError("field or index writer is null in inverted index writer");
}
for (int i = 0; i < count; ++i) {
RETURN_IF_ERROR(add_null_document());
}
}
return Status::OK();
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::add_array_nulls(const uint8_t* null_map,
size_t num_rows) {
DCHECK(_rid >= num_rows);
if (num_rows == 0 || null_map == nullptr) {
return Status::OK();
}
std::vector<uint32_t> null_indices;
null_indices.reserve(num_rows / 8);
// because _rid is the row id in block, not segment, and we add data before we add nulls,
// so we need to subtract num_rows to get the row id in segment
for (size_t i = 0; i < num_rows; i++) {
if (null_map[i] == 1) {
null_indices.push_back(cast_set<uint32_t>(_rid - num_rows + i));
}
}
if (!null_indices.empty()) {
_null_bitmap.addMany(null_indices.size(), null_indices.data());
}
return Status::OK();
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::new_inverted_index_field(const char* field_value_data,
size_t field_value_size) {
try {
if (_should_analyzer) {
new_char_token_stream(field_value_data, field_value_size, _field);
} else {
new_field_char_value(field_value_data, field_value_size, _field);
}
} catch (const CLuceneError& e) {
return Status::Error<ErrorCode::INVERTED_INDEX_CLUCENE_ERROR>(
"CLuceneError create new index field error: {}", e.what());
}
return Status::OK();
}
template <FieldType field_type>
void InvertedIndexColumnWriter<field_type>::new_char_token_stream(const char* s, size_t len,
lucene::document::Field* field) {
_char_string_reader->init(s, cast_set<int32_t>(len), false);
DBUG_EXECUTE_IF(
"InvertedIndexColumnWriter::new_char_token_stream__char_string_reader_init_"
"error",
{
_CLTHROWA(CL_ERR_UnsupportedOperation,
"UnsupportedOperationException: CLStream::init");
})
auto* stream = _analyzer->reusableTokenStream(field->name(), _char_string_reader);
field->setValue(stream);
}
template <FieldType field_type>
void InvertedIndexColumnWriter<field_type>::new_field_value(const char* s, size_t len,
lucene::document::Field* field) {
auto* field_value = lucene::util::Misc::_charToWide(s, len);
field->setValue(field_value, false);
// setValue did not duplicate value, so we don't have to delete
//_CLDELETE_ARRAY(field_value)
}
template <FieldType field_type>
void InvertedIndexColumnWriter<field_type>::new_field_char_value(const char* s, size_t len,
lucene::document::Field* field) {
field->setValue((char*)s, len);
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::add_values(const std::string fn, const void* values,
size_t count) {
if constexpr (field_is_slice_type(field_type)) {
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::add_values_field_is_nullptr",
{ _field = nullptr; })
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::add_values_index_writer_is_nullptr",
{ _index_writer = nullptr; })
if (_field == nullptr || _index_writer == nullptr) {
LOG(ERROR) << "field or index writer is null in inverted index writer.";
return Status::InternalError("field or index writer is null in inverted index writer");
}
const auto* v = (Slice*)values;
for (size_t i = 0; i < count; ++i) {
// only ignore_above UNTOKENIZED strings and empty strings not tokenized
if ((!_should_analyzer && v->get_size() > _ignore_above) ||
(_should_analyzer && v->empty())) {
RETURN_IF_ERROR(add_null_document());
} else {
RETURN_IF_ERROR(new_inverted_index_field(v->get_data(), v->get_size()));
RETURN_IF_ERROR(add_document());
}
++v;
_rid++;
}
} else if constexpr (field_is_numeric_type(field_type)) {
RETURN_IF_ERROR(add_numeric_values(values, count));
}
return Status::OK();
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::add_array_values(size_t field_size,
const void* value_ptr,
const uint8_t* nested_null_map,
const uint8_t* offsets_ptr,
size_t count) {
if (count == 0) {
// no values to add inverted index
return Status::OK();
}
const auto* offsets = reinterpret_cast<const uint64_t*>(offsets_ptr);
if constexpr (field_is_slice_type(field_type)) {
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::add_array_values_index_writer_is_nullptr",
{ _index_writer = nullptr; })
if (_index_writer == nullptr) {
LOG(ERROR) << "index writer is null in inverted index writer.";
return Status::InternalError("index writer is null in inverted index writer");
}
size_t start_off = 0;
std::vector<ReaderPtr> keep_readers;
for (size_t i = 0; i < count; ++i) {
// nullmap & value ptr-array may not from offsets[i] because olap_convertor make offsets accumulate from _base_offset which may not is 0, but nullmap & value in this segment is from 0, we only need
// every single array row element size to go through the nullmap & value ptr-array, and also can go through the every row in array to keep with _rid++
auto array_elem_size = offsets[i + 1] - offsets[i];
// TODO(Amory).later we use object pool to avoid field creation
std::unique_ptr<lucene::document::Field> new_field;
CL_NS(analysis)::TokenStream* ts = nullptr;
for (auto j = start_off; j < start_off + array_elem_size; ++j) {
if (nested_null_map && nested_null_map[j] == 1) {
continue;
}
auto* v = (Slice*)((const uint8_t*)value_ptr + j * field_size);
if ((!_should_analyzer && v->get_size() > _ignore_above) ||
(_should_analyzer && v->empty())) {
// is here a null value?
// TODO. Maybe here has performance problem for large size string.
continue;
} else {
// now we temp create field . later make a pool
lucene::document::Field* tmp_field = nullptr;
Status st = create_field(&tmp_field);
new_field.reset(tmp_field);
DBUG_EXECUTE_IF(
"InvertedIndexColumnWriter::add_array_values_create_field_"
"error",
{
st = Status::Error<ErrorCode::INTERNAL_ERROR>(
"debug point: add_array_values_create_field_error");
})
if (st != Status::OK()) {
LOG(ERROR) << "create field "
<< std::string(_field_name.begin(), _field_name.end())
<< " error:" << st;
return st;
}
if (_should_analyzer) {
// in this case stream need to delete after add_document, because the
// stream can not reuse for different field
bool own_token_stream = true;
ReaderPtr char_string_reader = DORIS_TRY(
create_char_string_reader(_analyzer_config.char_filter_map));
char_string_reader->init(v->get_data(), cast_set<int32_t>(v->get_size()),
false);
ts = _analyzer->tokenStream(new_field->name(), char_string_reader);
new_field->setValue(ts, own_token_stream);
keep_readers.emplace_back(std::move(char_string_reader));
} else {
new_field_char_value(v->get_data(), v->get_size(), new_field.get());
}
// NOTE: new_field is managed by doc now, so we need to use release() to get the pointer
_doc->add(*new_field.release());
}
}
start_off += array_elem_size;
// here to make debug for array field with current doc which should has expected number of fields
DBUG_EXECUTE_IF("array_inverted_index.write_index", {
auto single_array_field_count =
DebugPoints::instance()->get_debug_param_or_default<int32_t>(
"array_inverted_index.write_index", "single_array_field_count", 0);
if (single_array_field_count < 0) {
return Status::Error<ErrorCode::INTERNAL_ERROR>(
"indexes count cannot be negative");
}
if (_doc->getFields()->size() != single_array_field_count) {
return Status::Error<ErrorCode::INTERNAL_ERROR>(
"array field has fields count {} not equal to expected {}",
_doc->getFields()->size(), single_array_field_count);
}
})
if (!_doc->getFields()->empty()) {
// if this array is null, we just ignore to write inverted index
RETURN_IF_ERROR(add_document());
_doc->clear();
} else {
// avoid to add doc which without any field which may make threadState init skip
// init fieldDataArray, then will make error with next doc with fields in
// resetCurrentFieldData
lucene::document::Field* tmp_field = nullptr;
Status st = create_field(&tmp_field);
new_field.reset(tmp_field);
DBUG_EXECUTE_IF("InvertedIndexColumnWriter::add_array_values_create_field_error_2",
{
st = Status::Error<ErrorCode::INTERNAL_ERROR>(
"debug point: add_array_values_create_field_error_2");
})
if (st != Status::OK()) {
LOG(ERROR) << "create field "
<< std::string(_field_name.begin(), _field_name.end())
<< " error:" << st;
return st;
}
_doc->add(*new_field.release());
RETURN_IF_ERROR(add_null_document());
_doc->clear();
}
_rid++;
keep_readers.clear();
}
} else if constexpr (field_is_numeric_type(field_type)) {
size_t start_off = 0;
for (int i = 0; i < count; ++i) {
auto array_elem_size = offsets[i + 1] - offsets[i];
for (size_t j = start_off; j < start_off + array_elem_size; ++j) {
if (nested_null_map && nested_null_map[j] == 1) {
continue;
}
const CppType* p = &reinterpret_cast<const CppType*>(value_ptr)[j];
RETURN_IF_ERROR(add_value(*p));
}
start_off += array_elem_size;
_row_ids_seen_for_bkd++;
_rid++;
}
}
return Status::OK();
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::add_numeric_values(const void* values, size_t count) {
auto p = reinterpret_cast<const CppType*>(values);
for (size_t i = 0; i < count; ++i) {
RETURN_IF_ERROR(add_value(*p));
_rid++;
p++;
_row_ids_seen_for_bkd++;
}
return Status::OK();
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::add_value(const CppType& value) {
try {
std::string new_value;
uint32_t value_length = sizeof(CppType);
DBUG_EXECUTE_IF(
"InvertedIndexColumnWriter::add_value_bkd_writer_add_throw_"
"error",
{ _CLTHROWA(CL_ERR_IllegalArgument, ("packedValue should be length=xxx")); });
_value_key_coder->full_encode_ascending(&value, &new_value);
_bkd_writer->add((const uint8_t*)new_value.c_str(), value_length, _rid);
} catch (const CLuceneError& e) {
return Status::Error<ErrorCode::INVERTED_INDEX_CLUCENE_ERROR>("CLuceneError add_value: {}",
e.what());
}
return Status::OK();
}
template <FieldType field_type>
int64_t InvertedIndexColumnWriter<field_type>::size() const {
//TODO: get memory size of inverted index
return 0;
}
template <FieldType field_type>
void InvertedIndexColumnWriter<field_type>::write_null_bitmap(
lucene::store::IndexOutput* null_bitmap_out) {
// write null_bitmap file
_null_bitmap.runOptimize();
size_t size = _null_bitmap.getSizeInBytes(false);
if (size > 0) {
faststring buf;
buf.resize(size);
_null_bitmap.write(reinterpret_cast<char*>(buf.data()), false);
null_bitmap_out->writeBytes(buf.data(), cast_set<int32_t>(size));
}
}
template <FieldType field_type>
Status InvertedIndexColumnWriter<field_type>::finish() {
if (_dir != nullptr) {
std::unique_ptr<lucene::store::IndexOutput> null_bitmap_out = nullptr;
std::unique_ptr<lucene::store::IndexOutput> data_out = nullptr;
std::unique_ptr<lucene::store::IndexOutput> index_out = nullptr;
std::unique_ptr<lucene::store::IndexOutput> meta_out = nullptr;
ErrorContext error_context;
try {
// write bkd file
if constexpr (field_is_numeric_type(field_type)) {
_bkd_writer->max_doc_ = _rid;
_bkd_writer->docs_seen_ = _row_ids_seen_for_bkd;
null_bitmap_out = std::unique_ptr<lucene::store::IndexOutput>(_dir->createOutput(
InvertedIndexDescriptor::get_temporary_null_bitmap_file_name()));
data_out = std::unique_ptr<lucene::store::IndexOutput>(_dir->createOutput(
InvertedIndexDescriptor::get_temporary_bkd_index_data_file_name()));
meta_out = std::unique_ptr<lucene::store::IndexOutput>(_dir->createOutput(
InvertedIndexDescriptor::get_temporary_bkd_index_meta_file_name()));
index_out = std::unique_ptr<lucene::store::IndexOutput>(_dir->createOutput(
InvertedIndexDescriptor::get_temporary_bkd_index_file_name()));
write_null_bitmap(null_bitmap_out.get());
DBUG_EXECUTE_IF("InvertedIndexWriter._set_bkd_data_out_nullptr",
{ data_out = nullptr; });
if (data_out != nullptr && meta_out != nullptr && index_out != nullptr) {
_bkd_writer->meta_finish(meta_out.get(),
_bkd_writer->finish(data_out.get(), index_out.get()),
int(field_type));
} else {
LOG(WARNING) << "Inverted index writer create output error "
"occurred: nullptr";
_CLTHROWA(CL_ERR_IO, "Create output error with nullptr");
}
} else if constexpr (field_is_slice_type(field_type)) {
null_bitmap_out = std::unique_ptr<lucene::store::IndexOutput>(_dir->createOutput(
InvertedIndexDescriptor::get_temporary_null_bitmap_file_name()));
write_null_bitmap(null_bitmap_out.get());
DBUG_EXECUTE_IF(
"InvertedIndexWriter._throw_clucene_error_in_fulltext_"
"writer_close",
{
_CLTHROWA(CL_ERR_IO,
"debug point: test throw error in fulltext "
"index writer");
});
}
} catch (CLuceneError& e) {
error_context.eptr = std::current_exception();
error_context.err_msg.append("Inverted index writer finish error occurred: ");
error_context.err_msg.append(e.what());
LOG(ERROR) << error_context.err_msg;
}
FINALLY({
FINALLY_CLOSE(null_bitmap_out);
FINALLY_CLOSE(meta_out);
FINALLY_CLOSE(data_out);
FINALLY_CLOSE(index_out);
if constexpr (field_is_numeric_type(field_type)) {
FINALLY_CLOSE(_dir);
} else if constexpr (field_is_slice_type(field_type)) {
FINALLY_CLOSE(_index_writer);
// After closing the _index_writer, it needs to be reset to null to prevent issues of not closing it or closing it multiple times.
_index_writer.reset();
}
})
return Status::OK();
}
LOG(WARNING) << "Inverted index writer finish error occurred: dir is nullptr";
return Status::Error<doris::ErrorCode::INVERTED_INDEX_CLUCENE_ERROR>(
"Inverted index writer finish error occurred: dir is nullptr");
}
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_CHAR>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_VARCHAR>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_STRING>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_TINYINT>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_SMALLINT>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_INT>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_UNSIGNED_INT>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_BIGINT>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_LARGEINT>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DATE>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DATETIME>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DECIMAL>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DATEV2>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DATETIMEV2>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DECIMAL32>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DECIMAL64>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DECIMAL128I>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DECIMAL256>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_BOOL>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_IPV4>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_IPV6>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_FLOAT>;
template class InvertedIndexColumnWriter<FieldType::OLAP_FIELD_TYPE_DOUBLE>;
} // namespace doris::segment_v2