blob: 9004e7f14769841b9d8e08d288acbe30f14c0104 [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_reader.h"
#include <CLucene.h>
#include <gen_cpp/olap_file.pb.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <cstring>
#include <map>
#include <memory>
#include <roaring/roaring.hh>
#include <string>
#include <vector>
#include "core/field.h"
#include "core/value/vdatetime_value.h"
#include "runtime/runtime_state.h"
#include "storage/index/index_file_reader.h"
#include "storage/index/index_file_writer.h"
#include "storage/index/inverted/inverted_index_desc.h"
#include "storage/index/inverted/inverted_index_iterator.h"
#include "storage/index/inverted/inverted_index_writer.h"
#include "storage/key_coder.h"
#include "storage/tablet/tablet_schema.h"
#include "storage/tablet/tablet_schema_helper.h"
#include "util/slice.h"
namespace doris::segment_v2 {
class InvertedIndexReaderTest : public testing::Test {
public:
const std::string kTestDir = "./ut_dir/inverted_index_reader_test";
void SetUp() override {
auto st = io::global_local_filesystem()->delete_directory(kTestDir);
ASSERT_TRUE(st.ok()) << st;
st = io::global_local_filesystem()->create_directory(kTestDir);
ASSERT_TRUE(st.ok()) << st;
std::vector<StorePath> paths;
paths.emplace_back(kTestDir, 1024);
auto tmp_file_dirs = std::make_unique<segment_v2::TmpFileDirs>(paths);
st = tmp_file_dirs->init();
if (!st.ok()) {
std::cout << "init tmp file dirs error:" << st.to_string() << std::endl;
return;
}
ExecEnv::GetInstance()->set_tmp_file_dir(std::move(tmp_file_dirs));
// Initialize cache
int64_t inverted_index_cache_limit = 1024 * 1024 * 1024;
_inverted_index_searcher_cache = std::unique_ptr<segment_v2::InvertedIndexSearcherCache>(
InvertedIndexSearcherCache::create_global_instance(inverted_index_cache_limit, 1));
_inverted_index_query_cache = std::unique_ptr<segment_v2::InvertedIndexQueryCache>(
InvertedIndexQueryCache::create_global_cache(inverted_index_cache_limit, 1));
ExecEnv::GetInstance()->set_inverted_index_searcher_cache(
_inverted_index_searcher_cache.get());
ExecEnv::GetInstance()->_inverted_index_query_cache = _inverted_index_query_cache.get();
}
void TearDown() override {
ASSERT_TRUE(io::global_local_filesystem()->delete_directory(kTestDir).ok());
}
// Create table schema
TabletSchemaSPtr create_schema(KeysType keys_type = DUP_KEYS) {
TabletSchemaSPtr tablet_schema = std::make_shared<TabletSchema>();
TabletSchemaPB tablet_schema_pb;
tablet_schema_pb.set_keys_type(keys_type);
tablet_schema->init_from_pb(tablet_schema_pb);
// Add INT type key column
TabletColumn column_1;
column_1.set_name("c1");
column_1.set_unique_id(0);
column_1.set_type(FieldType::OLAP_FIELD_TYPE_INT);
column_1.set_length(4);
column_1.set_index_length(4);
column_1.set_is_key(true);
column_1.set_is_nullable(true);
tablet_schema->append_column(column_1);
// Add VARCHAR type value column
TabletColumn column_2;
column_2.set_name("c2");
column_2.set_unique_id(1);
column_2.set_type(FieldType::OLAP_FIELD_TYPE_VARCHAR);
column_2.set_length(65535);
column_2.set_is_key(false);
column_2.set_is_nullable(false);
tablet_schema->append_column(column_2);
return tablet_schema;
}
std::string local_segment_path(std::string base, std::string_view rowset_id, int64_t seg_id) {
return fmt::format("{}/{}_{}.dat", base, rowset_id, seg_id);
}
// Create string inverted index and write data
void prepare_string_index(
std::string_view rowset_id, int seg_id, std::vector<Slice>& values,
TabletIndex* idx_meta, std::string* index_path_prefix,
InvertedIndexStorageFormatPB format = InvertedIndexStorageFormatPB::V2) {
auto tablet_schema = create_schema();
*index_path_prefix = InvertedIndexDescriptor::get_index_file_path_prefix(
local_segment_path(kTestDir, rowset_id, seg_id));
std::string index_path =
InvertedIndexDescriptor::get_index_file_path_v2(*index_path_prefix);
io::FileWriterPtr file_writer;
io::FileWriterOptions opts;
auto fs = io::global_local_filesystem();
Status sts = fs->create_file(index_path, &file_writer, &opts);
ASSERT_TRUE(sts.ok()) << sts;
auto index_file_writer =
std::make_unique<IndexFileWriter>(fs, *index_path_prefix, std::string {rowset_id},
seg_id, format, std::move(file_writer));
// Get c2 column descriptor
const TabletColumn& column = tablet_schema->column(1);
ASSERT_NE(&column, nullptr);
const TabletColumn* field = &(column);
ASSERT_NE(field, nullptr);
// Create column writer
std::unique_ptr<IndexColumnWriter> column_writer;
auto status =
IndexColumnWriter::create(field, &column_writer, index_file_writer.get(), idx_meta);
EXPECT_TRUE(status.ok()) << status;
// Write string values
status = column_writer->add_values("c2", values.data(), values.size());
EXPECT_TRUE(status.ok()) << status;
// Finish and close
status = column_writer->finish();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->begin_close();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->finish_close();
EXPECT_TRUE(status.ok()) << status;
}
// Create inverted index with NULL values
void prepare_null_index(std::string_view rowset_id, int seg_id, TabletIndex* idx_meta,
std::string* index_path_prefix) {
auto tablet_schema = create_schema();
// Create index metadata
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(1); // c2 column ID
idx_meta->init_from_pb(*index_meta_pb.get());
*index_path_prefix = InvertedIndexDescriptor::get_index_file_path_prefix(
local_segment_path(kTestDir, rowset_id, seg_id));
std::string index_path =
InvertedIndexDescriptor::get_index_file_path_v2(*index_path_prefix);
io::FileWriterPtr file_writer;
io::FileWriterOptions opts;
auto fs = io::global_local_filesystem();
Status sts = fs->create_file(index_path, &file_writer, &opts);
ASSERT_TRUE(sts.ok()) << sts;
auto index_file_writer = std::make_unique<IndexFileWriter>(
fs, *index_path_prefix, std::string {rowset_id}, seg_id,
InvertedIndexStorageFormatPB::V2, std::move(file_writer));
// Get c2 column descriptor
const TabletColumn& column = tablet_schema->column(1);
ASSERT_NE(&column, nullptr);
const TabletColumn* field = &(column);
ASSERT_NE(field, nullptr);
// Create column writer
std::unique_ptr<IndexColumnWriter> column_writer;
auto status =
IndexColumnWriter::create(field, &column_writer, index_file_writer.get(), idx_meta);
EXPECT_TRUE(status.ok()) << status;
// Add NULL values
status = column_writer->add_nulls(3);
EXPECT_TRUE(status.ok()) << status;
// Add some regular values
std::vector<Slice> values = {Slice("apple"), Slice("banana")};
status = column_writer->add_values("c2", values.data(), values.size());
EXPECT_TRUE(status.ok()) << status;
// Add more NULL values
status = column_writer->add_nulls(2);
EXPECT_TRUE(status.ok()) << status;
// Finish and close
status = column_writer->finish();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->begin_close();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->finish_close();
EXPECT_TRUE(status.ok()) << status;
}
// Create BKD index
void prepare_bkd_index(std::string_view rowset_id, int seg_id, std::vector<int32_t>& values,
TabletIndex* idx_meta, std::string* index_path_prefix) {
auto tablet_schema = create_schema();
// Create index metadata
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(0); // c1 column ID
// Set BKD index properties
auto* properties = index_meta_pb->mutable_properties();
(*properties)["type"] = "bkd";
idx_meta->init_from_pb(*index_meta_pb.get());
*index_path_prefix = InvertedIndexDescriptor::get_index_file_path_prefix(
local_segment_path(kTestDir, rowset_id, seg_id));
std::string index_path =
InvertedIndexDescriptor::get_index_file_path_v2(*index_path_prefix);
io::FileWriterPtr file_writer;
io::FileWriterOptions opts;
auto fs = io::global_local_filesystem();
Status sts = fs->create_file(index_path, &file_writer, &opts);
ASSERT_TRUE(sts.ok()) << sts;
auto index_file_writer = std::make_unique<IndexFileWriter>(
fs, *index_path_prefix, std::string {rowset_id}, seg_id,
InvertedIndexStorageFormatPB::V2, std::move(file_writer));
// Get c1 column descriptor
const TabletColumn& column = tablet_schema->column(0);
ASSERT_NE(&column, nullptr);
const TabletColumn* field = &(column);
ASSERT_NE(field, nullptr);
// Create column writer
std::unique_ptr<IndexColumnWriter> column_writer;
auto status =
IndexColumnWriter::create(field, &column_writer, index_file_writer.get(), idx_meta);
EXPECT_TRUE(status.ok()) << status;
// Add integer values
status = column_writer->add_values("c1", values.data(), values.size());
EXPECT_TRUE(status.ok()) << status;
// Finish and close
status = column_writer->finish();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->begin_close();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->finish_close();
EXPECT_TRUE(status.ok()) << status;
}
// Test string inverted index reading
void test_string_index_read() {
std::string_view rowset_id = "test_read_rowset_1";
int seg_id = 0;
// Prepare data
std::vector<Slice> values = {Slice("apple"), Slice("banana"), Slice("cherry"),
Slice("apple"), // Duplicate value to test frequency
Slice("date")};
TabletIndex idx_meta;
// Create index metadata
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(1); // c2 column ID
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix,
InvertedIndexStorageFormatPB::V2);
// Create reader
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
runtime_state.set_query_options(query_options);
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
auto status = reader->init();
EXPECT_EQ(status, Status::OK());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
// Test query
io::IOContext io_ctx;
std::string field_name = "1"; // c2 column unique_id
// Test EQUAL query
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
StringRef str_ref(values[0].data, values[0].size); // "apple"
auto context = std::make_shared<segment_v2::IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
Field qp_335 = Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto query_status = str_reader->query(context, field_name, qp_335,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 2) << "Should find 2 documents matching 'apple'";
EXPECT_TRUE(bitmap->contains(0)) << "Document 0 should match 'apple'";
EXPECT_TRUE(bitmap->contains(3)) << "Document 3 should match 'apple'";
// Test non-existent value
bitmap = std::make_shared<roaring::Roaring>();
std::string not_exist = "orange";
StringRef not_exist_ref(not_exist.c_str(), not_exist.length());
Field qp_348 = Field::create_field<TYPE_STRING>(
std::string(not_exist_ref.data, not_exist_ref.size));
query_status = str_reader->query(context, field_name, qp_348,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 0) << "Should not find any document matching 'orange'";
}
// Test NULL value handling
void test_null_bitmap_read() {
std::string_view rowset_id = "test_read_rowset_2";
int seg_id = 0;
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_null_index(rowset_id, seg_id, &idx_meta, &index_path_prefix);
// Create reader
OlapReaderStatistics stats;
RuntimeState runtime_state;
io::IOContext io_ctx;
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
auto status = reader->init();
EXPECT_EQ(status, Status::OK());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
auto context = std::make_shared<segment_v2::IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
// Read NULL bitmap
InvertedIndexQueryCacheHandle cache_handle;
status = str_reader->read_null_bitmap(context, &cache_handle, nullptr);
EXPECT_TRUE(status.ok()) << status;
// Get NULL bitmap
std::shared_ptr<roaring::Roaring> null_bitmap = cache_handle.get_bitmap();
EXPECT_NE(null_bitmap, nullptr);
// Verify expected values in NULL bitmap
EXPECT_EQ(null_bitmap->cardinality(), 5) << "Should have 5 NULL documents";
std::vector<int> expected_nulls = {0, 1, 2, 5, 6};
for (int doc_id : expected_nulls) {
EXPECT_TRUE(null_bitmap->contains(doc_id))
<< "Document " << doc_id << " should be NULL";
}
}
// Test BKD index query
void test_bkd_index_read() {
std::string_view rowset_id = "test_read_rowset_3";
int seg_id = 0;
// Prepare data
std::vector<int32_t> values = {42, 100, 42, 200, 300};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
// Create reader
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
runtime_state.set_query_options(query_options);
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
auto status = reader->init();
EXPECT_EQ(status, Status::OK());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
io::IOContext io_ctx;
std::string field_name = "0"; // c1 column unique_id
// Test EQUAL query
int32_t query_value = 42;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
auto context = std::make_shared<segment_v2::IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
Field qp_441 = Field::create_field<TYPE_INT>(query_value);
auto query_status = bkd_reader->query(context, field_name, qp_441,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 2) << "Should find 2 documents matching value 42";
EXPECT_TRUE(bitmap->contains(0)) << "Document 0 should match value 42";
EXPECT_TRUE(bitmap->contains(2)) << "Document 2 should match value 42";
// Test LESS_THAN query
bitmap = std::make_shared<roaring::Roaring>();
int32_t less_than_value = 100;
Field qp_453 = Field::create_field<TYPE_INT>(less_than_value);
query_status = bkd_reader->query(context, field_name, qp_453,
InvertedIndexQueryType::LESS_THAN_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 2) << "Should find 2 documents with values less than 100";
EXPECT_TRUE(bitmap->contains(0)) << "Document 0 should have value less than 100";
EXPECT_TRUE(bitmap->contains(2)) << "Document 2 should have value less than 100";
// Test GREATER_THAN query
bitmap = std::make_shared<roaring::Roaring>();
int32_t greater_than_value = 100;
Field qp_465 = Field::create_field<TYPE_INT>(greater_than_value);
query_status = bkd_reader->query(context, field_name, qp_465,
InvertedIndexQueryType::GREATER_THAN_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 2)
<< "Should find 2 documents with values greater than 100";
EXPECT_TRUE(bitmap->contains(3)) << "Document 3 should have value greater than 100";
EXPECT_TRUE(bitmap->contains(4)) << "Document 4 should have value greater than 100";
}
// Test query cache
void test_query_cache() {
std::string_view rowset_id = "test_read_rowset_4";
int seg_id = 0;
// Prepare data
std::vector<Slice> values = {Slice("apple"), Slice("banana"), Slice("cherry")};
TabletIndex idx_meta;
// Create index metadata
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(1); // c2 column ID
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
// Create reader
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_query_cache = true;
query_options.enable_inverted_index_searcher_cache = true;
runtime_state.set_query_options(query_options);
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
auto status = reader->init();
EXPECT_EQ(status, Status::OK());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
io::IOContext io_ctx;
std::string field_name = "1"; // c2 column unique_id
// First query, should be cache miss
std::shared_ptr<roaring::Roaring> bitmap1 = std::make_shared<roaring::Roaring>();
StringRef str_ref(values[0].data, values[0].size); // "apple"
auto context = std::make_shared<segment_v2::IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
Field qp_524 = Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto query_status = str_reader->query(context, field_name, qp_524,
InvertedIndexQueryType::EQUAL_QUERY, bitmap1);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(stats.inverted_index_query_cache_miss, 1) << "First query should be cache miss";
EXPECT_EQ(bitmap1->cardinality(), 1) << "Should find 1 document matching 'apple'";
// Second query with same value, should be cache hit
std::shared_ptr<roaring::Roaring> bitmap2 = std::make_shared<roaring::Roaring>();
Field qp_534 = Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
query_status = str_reader->query(context, field_name, qp_534,
InvertedIndexQueryType::EQUAL_QUERY, bitmap2);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(stats.inverted_index_query_cache_hit, 1) << "Second query should be cache hit";
EXPECT_EQ(bitmap2->cardinality(), 1) << "Should find 1 document matching 'apple'";
}
// Test searcher cache
void test_searcher_cache() {
std::string_view rowset_id = "test_read_rowset_5";
int seg_id = 0;
// Prepare data
std::vector<Slice> values = {Slice("apple"), Slice("banana"), Slice("cherry")};
TabletIndex idx_meta;
// Create index metadata
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(1); // c2 column ID
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix,
InvertedIndexStorageFormatPB::V2);
// Create reader
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_query_cache = false;
query_options.enable_inverted_index_searcher_cache = true;
runtime_state.set_query_options(query_options);
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
auto status = reader->init();
EXPECT_EQ(status, Status::OK());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
io::IOContext io_ctx;
std::string field_name = "1"; // c2 column unique_id
// First query, should be searcher cache miss
std::shared_ptr<roaring::Roaring> bitmap1 = std::make_shared<roaring::Roaring>();
StringRef str_ref(values[0].data, values[0].size); // "apple"
auto context = std::make_shared<segment_v2::IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
Field qp_592 = Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto query_status = str_reader->query(context, field_name, qp_592,
InvertedIndexQueryType::EQUAL_QUERY, bitmap1);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(stats.inverted_index_searcher_cache_miss, 1)
<< "First query should be searcher cache miss";
// Query with different value, should be searcher cache hit
std::shared_ptr<roaring::Roaring> bitmap2 = std::make_shared<roaring::Roaring>();
StringRef str_ref2(values[1].data, values[1].size); // "banana"
Field qp_603 = Field::create_field<TYPE_STRING>(std::string(str_ref2.data, str_ref2.size));
query_status = str_reader->query(context, field_name, qp_603,
InvertedIndexQueryType::EQUAL_QUERY, bitmap2);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(stats.inverted_index_searcher_cache_hit, 1)
<< "Second query should be searcher cache hit";
}
void test_inverted_index_cache_matrix() {
std::string_view rowset_id = "test_cache_matrix";
int seg_id = 0;
std::vector<Slice> values = {Slice("images"), Slice("english"), Slice("other"),
Slice("unique")};
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_cache_matrix");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(1);
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix,
InvertedIndexStorageFormatPB::V2);
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
ASSERT_TRUE(reader->init().ok());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
ASSERT_NE(str_reader, nullptr);
io::IOContext io_ctx;
std::string field_name = "1";
const std::string kImages = "images";
const std::string kEnglish = "english";
const std::string kOther = "other";
const std::string kUnique = "unique";
auto run_match = [&](bool enable_query_cache, bool enable_searcher_cache,
const std::string& term, OlapReaderStatistics* stats) {
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_query_cache = enable_query_cache;
query_options.enable_inverted_index_searcher_cache = enable_searcher_cache;
runtime_state.set_query_options(query_options);
auto context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = stats;
context->runtime_state = &runtime_state;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
StringRef term_ref(term.data(), term.size());
Field qp_660 =
Field::create_field<TYPE_STRING>(std::string(term_ref.data, term_ref.size));
auto status = str_reader->query(context, field_name, qp_660,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok()) << status;
EXPECT_EQ(1, bitmap->cardinality());
};
// Warm both caches with two different keys so subsequent checks can rely on cache hits.
{
OlapReaderStatistics warm_stats;
run_match(true, true, kImages, &warm_stats);
EXPECT_EQ(1, warm_stats.inverted_index_query_cache_miss);
EXPECT_EQ(1, warm_stats.inverted_index_searcher_cache_miss);
}
{
OlapReaderStatistics warm_stats;
run_match(true, true, kEnglish, &warm_stats);
EXPECT_EQ(1, warm_stats.inverted_index_query_cache_miss);
EXPECT_EQ(0, warm_stats.inverted_index_searcher_cache_miss);
EXPECT_EQ(1, warm_stats.inverted_index_searcher_cache_hit);
}
// Query cache hit / searcher cache not accessed (query cache returns early).
{
OlapReaderStatistics stats;
run_match(true, true, kImages, &stats);
EXPECT_EQ(1, stats.inverted_index_query_cache_hit);
EXPECT_EQ(0, stats.inverted_index_query_cache_miss);
// When query cache hits, searcher cache is not accessed, so no hit/miss
EXPECT_EQ(0, stats.inverted_index_searcher_cache_hit);
EXPECT_EQ(0, stats.inverted_index_searcher_cache_miss);
}
// Query cache disabled (miss) while searcher cache should still hit.
{
OlapReaderStatistics stats;
run_match(false, true, kImages, &stats);
EXPECT_EQ(1, stats.inverted_index_query_cache_miss);
EXPECT_EQ(1, stats.inverted_index_searcher_cache_hit);
EXPECT_EQ(0, stats.inverted_index_searcher_cache_miss);
}
// Query cache enabled while searcher cache disabled using a new term -> both should miss.
{
OlapReaderStatistics stats;
run_match(true, false, kOther, &stats);
EXPECT_EQ(1, stats.inverted_index_query_cache_miss);
EXPECT_EQ(0, stats.inverted_index_query_cache_hit);
EXPECT_EQ(0, stats.inverted_index_searcher_cache_hit);
EXPECT_EQ(1, stats.inverted_index_searcher_cache_miss);
}
// Both caches disabled should report misses.
{
OlapReaderStatistics stats;
run_match(false, false, kUnique, &stats);
EXPECT_EQ(1, stats.inverted_index_query_cache_miss);
EXPECT_EQ(0, stats.inverted_index_query_cache_hit);
EXPECT_EQ(0, stats.inverted_index_searcher_cache_hit);
EXPECT_EQ(1, stats.inverted_index_searcher_cache_miss);
}
}
// Test string index with large document set (>512 docs)
void test_string_index_large_docset() {
std::string_view rowset_id = "test_read_rowset_6";
int seg_id = 0;
// Prepare data with 1000 documents
std::vector<Slice> values;
values.reserve(1000);
// Add 600 documents with term "common"
for (int i = 0; i < 600; i++) {
values.emplace_back("common");
}
// Add 200 documents with term "apple"
for (int i = 0; i < 200; i++) {
values.emplace_back("apple");
}
// Add 200 documents with term "banana"
for (int i = 0; i < 200; i++) {
values.emplace_back("banana");
}
TabletIndex idx_meta;
// Create index metadata
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(1); // c2 column ID
index_meta_pb->mutable_properties()->insert({"parser", "english"});
index_meta_pb->mutable_properties()->insert({"lower_case", "true"});
index_meta_pb->mutable_properties()->insert({"support_phrase", "true"});
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix,
InvertedIndexStorageFormatPB::V2);
// Create reader
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
runtime_state.set_query_options(query_options);
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
auto status = reader->init();
EXPECT_EQ(status, Status::OK());
auto str_reader = FullTextIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
io::IOContext io_ctx;
std::string field_name = "1"; // c2 column unique_id
// Test query for "common_term" which has >512 documents
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query_term = "common";
StringRef str_ref(query_term.c_str(), query_term.length());
auto context = std::make_shared<segment_v2::IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
Field qp_791 = Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto query_status = str_reader->query(context, field_name, qp_791,
InvertedIndexQueryType::MATCH_PHRASE_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 600) << "Should find 600 documents matching 'common'";
// Verify first and last document IDs
EXPECT_TRUE(bitmap->contains(0)) << "First document should match 'common'";
EXPECT_TRUE(bitmap->contains(599)) << "Last document should match 'common'";
// Test query for "apple"
bitmap = std::make_shared<roaring::Roaring>();
query_term = "apple";
StringRef str_ref_a(query_term.c_str(), query_term.length());
Field qp_806 =
Field::create_field<TYPE_STRING>(std::string(str_ref_a.data, str_ref_a.size));
query_status = str_reader->query(context, field_name, qp_806,
InvertedIndexQueryType::MATCH_PHRASE_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 200) << "Should find 200 documents matching 'apple'";
EXPECT_TRUE(bitmap->contains(600)) << "First document of apple should be at position 600";
EXPECT_TRUE(bitmap->contains(799)) << "Last document of apple should be at position 799";
}
// Test string index with large document set using V3 format
void test_string_index_large_docset_v3() {
std::string_view rowset_id = "test_read_rowset_6_v3";
int seg_id = 0;
// Prepare data with 1000 documents
std::vector<Slice> values;
values.reserve(1000);
// Add 600 documents with term "common_term"
for (int i = 0; i < 600; i++) {
values.emplace_back("common_term");
}
// Add 200 documents with term "term_a"
for (int i = 0; i < 200; i++) {
values.emplace_back("term_a");
}
// Add 200 documents with term "term_b"
for (int i = 0; i < 200; i++) {
values.emplace_back("term_b");
}
{
TabletIndex idx_meta;
// Create index metadata
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(1); // c2 column ID
index_meta_pb->mutable_properties()->insert({"parser", "english"});
index_meta_pb->mutable_properties()->insert({"lower_case", "true"});
index_meta_pb->mutable_properties()->insert({"support_phrase", "true"});
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix,
InvertedIndexStorageFormatPB::V3);
// Create V3 format reader
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
runtime_state.set_query_options(query_options);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V3);
auto status = reader->init();
EXPECT_EQ(status, Status::OK());
auto str_reader = FullTextIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
io::IOContext io_ctx;
std::string field_name = "1"; // c2 column unique_id
// Test query for "common_term" which has >512 documents with V3 format
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query_term = "common_term";
StringRef str_ref(query_term.c_str(), query_term.length());
auto context = std::make_shared<segment_v2::IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
Field qp_887 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto query_status =
str_reader->query(context, field_name, qp_887,
InvertedIndexQueryType::MATCH_PHRASE_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 600)
<< "V3: Should find 600 documents matching 'common_term'";
// Verify first and last document IDs
EXPECT_TRUE(bitmap->contains(0)) << "V3: First document should match 'common_term'";
EXPECT_TRUE(bitmap->contains(599)) << "V3: Last document should match 'common_term'";
// Test query for "term_a" with V3 format
bitmap = std::make_shared<roaring::Roaring>();
query_term = "term_a";
StringRef str_ref_a(query_term.c_str(), query_term.length());
Field qp_903 =
Field::create_field<TYPE_STRING>(std::string(str_ref_a.data, str_ref_a.size));
query_status = str_reader->query(context, field_name, qp_903,
InvertedIndexQueryType::MATCH_PHRASE_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 200)
<< "V3: Should find 200 documents matching 'term_a'";
EXPECT_TRUE(bitmap->contains(600))
<< "V3: First document of term_a should be at position 600";
EXPECT_TRUE(bitmap->contains(799))
<< "V3: Last document of term_a should be at position 799";
// Test query for "noexist" with V3 format
bitmap = std::make_shared<roaring::Roaring>();
query_term = "noexist";
StringRef str_ref_no_term(query_term.c_str(), query_term.length());
Field qp_919 = Field::create_field<TYPE_STRING>(
std::string(str_ref_no_term.data, str_ref_no_term.size));
query_status = str_reader->query(context, field_name, qp_919,
InvertedIndexQueryType::MATCH_ANY_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 0) << "V3: Should find 0 documents matching 'noexist'";
}
{
TabletIndex idx_meta;
// Create index metadata
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(1); // c2 column ID
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix,
InvertedIndexStorageFormatPB::V3);
// Create V3 format reader
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
runtime_state.set_query_options(query_options);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V3);
auto status = reader->init();
EXPECT_EQ(status, Status::OK());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
io::IOContext io_ctx;
std::string field_name = "1"; // c2 column unique_id
// Test query for "common_term" which has >512 documents with V3 format
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query_term = "common_term";
StringRef str_ref(query_term.c_str(), query_term.length());
auto context = std::make_shared<segment_v2::IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
Field qp_968 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto query_status = str_reader->query(context, field_name, qp_968,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 600)
<< "V3: Should find 600 documents matching 'common_term'";
// Verify first and last document IDs
EXPECT_TRUE(bitmap->contains(0)) << "V3: First document should match 'common_term'";
EXPECT_TRUE(bitmap->contains(599)) << "V3: Last document should match 'common_term'";
// Test query for "term_a" with V3 format
bitmap = std::make_shared<roaring::Roaring>();
query_term = "term_a";
StringRef str_ref_a(query_term.c_str(), query_term.length());
Field qp_984 =
Field::create_field<TYPE_STRING>(std::string(str_ref_a.data, str_ref_a.size));
query_status = str_reader->query(context, field_name, qp_984,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 200)
<< "V3: Should find 200 documents matching 'term_a'";
EXPECT_TRUE(bitmap->contains(600))
<< "V3: First document of term_a should be at position 600";
EXPECT_TRUE(bitmap->contains(799))
<< "V3: Last document of term_a should be at position 799";
// Test query for "noexist" with V3 format
bitmap = std::make_shared<roaring::Roaring>();
query_term = "noexist";
StringRef str_ref_no_term(query_term.c_str(), query_term.length());
Field qp_1000 = Field::create_field<TYPE_STRING>(
std::string(str_ref_no_term.data, str_ref_no_term.size));
query_status = str_reader->query(context, field_name, qp_1000,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(query_status.ok()) << query_status;
EXPECT_EQ(bitmap->cardinality(), 0) << "V3: Should find 0 documents matching 'noexist'";
}
}
// Helper function to check CPU architecture
bool is_arm_architecture() {
#if defined(__aarch64__)
return true;
#else
return false;
#endif
}
// Helper function to check AVX2 support
bool has_avx2_support() {
#if defined(USE_AVX2) && defined(__x86_64__)
unsigned int eax, ebx, ecx, edx;
__asm__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "0"(7), "c"(0));
return (ebx & (1 << 5)) != 0; // Check AVX2 bit
#else
return false;
#endif
}
// Helper function to test index reading with inline validation
void test_read_index_file(
const TabletIndex& idx_meta, const std::string& data_dir, const std::string& index_file,
const std::string& field_name, const std::string& query_term,
InvertedIndexStorageFormatPB storage_format, bool enable_compatible_read,
uint64_t expected_cardinality, // Added expected cardinality parameter
const std::vector<uint32_t>& expected_doc_ids) { // Added expected doc IDs parameter
// Get the index file path
std::string index_path_prefix = data_dir + "/" + index_file;
// Create reader
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
query_options.inverted_index_compatible_read = enable_compatible_read;
runtime_state.set_query_options(query_options);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix, storage_format);
auto status = reader->init();
ASSERT_TRUE(status.ok()) << "Failed to initialize IndexFileReader for " << index_file
<< ": " << status.to_string();
auto index_reader = FullTextIndexReader::create_shared(&idx_meta, reader);
ASSERT_NE(index_reader, nullptr)
<< "Failed to create FullTextIndexReader for " << index_file;
io::IOContext io_ctx;
// Test queries
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
StringRef str_ref(query_term.c_str(), query_term.length());
auto context = std::make_shared<segment_v2::IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
Field qp_1067 = Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto query_status = index_reader->query(context, field_name, qp_1067,
InvertedIndexQueryType::MATCH_PHRASE_QUERY, bitmap);
ASSERT_TRUE(query_status.ok()) << "Query failed for term '" << query_term << "' in file "
<< index_file << ": " << query_status.to_string();
// Perform validation inline
ASSERT_NE(bitmap, nullptr)
<< "Bitmap is null after successful query for file: " << index_file;
EXPECT_EQ(bitmap->cardinality(), expected_cardinality)
<< "File: " << index_file << " - Incorrect cardinality for term '" << query_term
<< "'";
//std::cout << "bitmap: " << bitmap->toString() << std::endl;
for (uint32_t doc_id : expected_doc_ids) {
EXPECT_TRUE(bitmap->contains(doc_id))
<< "File: " << index_file << " - Bitmap should contain doc ID " << doc_id
<< " for term '" << query_term << "'";
}
}
// Test reading existing large document set index file
void test_compatible_read_cross_platform() {
std::string data_dir = "./be/test/storage/test_data";
// Helper lambda to create TabletIndex easily
auto create_test_index_meta = [](int64_t index_id, const std::string& index_name,
int64_t col_unique_id) {
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(index_id);
index_meta_pb->set_index_name(index_name);
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(col_unique_id);
index_meta_pb->mutable_properties()->insert({"parser", "english"});
index_meta_pb->mutable_properties()->insert({"lower_case", "true"});
index_meta_pb->mutable_properties()->insert({"support_phrase", "true"});
TabletIndex idx_meta;
idx_meta.init_from_pb(*index_meta_pb.get());
return idx_meta;
};
// Default metadata, query parameters, and expected results
std::string default_index_name = "test";
std::string default_query_term = "gif";
uint64_t expected_gif_cardinality = 27296;
std::vector<uint32_t> expected_gif_doc_ids = {0, 19, 22, 23, 24, 26, 1000, 10278, 44702};
if (is_arm_architecture()) {
// Test ARM architecture cases
std::cout << "Testing on ARM architecture" << std::endl;
{
TabletIndex meta_arm_old_v2 =
create_test_index_meta(1744016478578, "request_idx", 2);
std::string field_name_avx2 = "2";
default_query_term = "gif";
expected_gif_cardinality = 37284;
expected_gif_doc_ids = {0, 19, 110, 1000, 2581, 7197, 9091, 16711, 29676, 44702};
test_read_index_file(meta_arm_old_v2, data_dir, "arm_old_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2, false,
expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 359;
expected_gif_doc_ids = {
25, 63, 66, 135, 214, 276, 287, 321, 653, 819, 968,
1038, 1115, 1210, 1305, 1394, 1650, 1690, 1761, 1934, 1935, 2101,
2114, 2544, 2815, 2912, 3028, 3104, 3475, 3953, 3991, 4052, 4097,
4424, 4430, 4458, 4504, 4571, 4629, 4704, 4711, 4838, 5021, 5322,
5362, 5414, 5461, 5524, 5681, 5828, 5877, 6031, 6123, 6249, 6298,
6575, 6626, 6637, 6692, 6708, 6765, 6926, 6953, 7061, 7089, 7144,
7147, 7184, 7342, 7461, 7615, 7703, 7818, 8002, 8014, 8280, 8369,
8398, 8440, 8554, 8675, 8682, 8780, 9064, 9379, 9448, 9455, 9639,
10036, 10124, 10164, 10224, 10246, 10568, 10736, 10750, 10914, 10930, 10944,
10970, 11149, 11434, 11435, 11534, 11862, 11961, 12187, 12247, 12344, 12479,
12632, 12923, 13015, 13018, 13122, 13277, 13357, 13459, 13466, 13597, 13792,
13857, 13952, 14096, 14127, 14211, 14221, 14344, 14563, 14567, 14588, 14606,
14692, 14868, 14880, 14990, 15085, 15101, 15211, 15218, 15439, 15530, 15564,
15676, 15695, 15727, 15754, 15846, 15895, 15904, 15983, 16004, 16299, 16423,
16476, 16530, 16954, 17045, 17202, 17393, 17592, 17693, 17829, 17852, 18018,
18224, 18335, 18881, 18942, 19162, 19387, 19401, 19418, 19434, 19525, 19710,
19805, 20054, 20126, 20127, 20407, 20572, 20742, 20929, 21023, 21024, 21248,
21267, 21354, 21452, 21704, 21810, 21831, 21847, 21900, 22202, 22328, 22599,
22629, 22671, 22761, 22762, 22824, 23139, 23478, 23784, 23797, 23884, 23886,
23983, 24128, 24137, 24176, 24253, 24434, 24484, 24518, 24538, 24655, 24849,
24853, 24865, 24888, 25163, 25256, 25274, 25307, 25613, 25816, 26225, 26323,
26459, 26461, 26476, 26580, 26598, 26800, 26932, 26962, 27202, 27499, 27506,
27768, 27923, 28049, 28133, 28305, 28468, 28535, 28670, 28717, 28782, 29154,
29692, 29742, 30112, 30125, 30289, 30353, 30437, 30734, 30741, 30848, 30933,
31332, 31399, 31581, 31841, 31867, 32025, 32446, 32463, 32712, 32947, 33038,
33210, 33325, 33563, 33572, 33757, 33947, 33975, 34016, 34041, 34210, 34627,
34684, 34732, 35064, 35684, 35787, 35809, 35811, 35996, 36272, 36389, 36418,
36420, 36568, 36847, 36956, 37022, 37189, 37200, 37401, 37484, 37581, 37852,
37939, 38156, 38269, 38785, 38874, 39072, 39081, 39094, 39157, 39187, 39308,
39562, 39676, 39690, 39814, 39848, 40134, 40350, 40352, 40684, 41143, 41249,
41416, 41463, 41738, 41840, 41875, 42028, 42077, 42104, 42439, 42467, 42528,
42784, 42793, 42970, 43020, 43418, 43430, 43571, 43809, 43811, 44040, 44057,
44081, 44168, 44288, 44329, 44608, 44624, 44690};
test_read_index_file(meta_arm_old_v2, data_dir, "arm_old_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2, false,
expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_arm_old_v1 =
create_test_index_meta(1744016478651, "request_idx", 2);
std::string field_name_avx2 = "request";
default_query_term = "gif";
expected_gif_cardinality = 40962;
expected_gif_doc_ids = {0, 21, 110, 1000, 2581, 7196, 9091, 16712, 26132, 44702};
test_read_index_file(meta_arm_old_v1, data_dir, "arm_old", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1, false,
expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 402;
expected_gif_doc_ids = {
36, 41, 242, 628, 716, 741, 884, 902, 1025, 1129, 1349,
1401, 1871, 1873, 2074, 2184, 2420, 2815, 3138, 3164, 3189, 3302,
3308, 3347, 3430, 3475, 3645, 3772, 3803, 3921, 4036, 4080, 4127,
4419, 4424, 4450, 4526, 4546, 4608, 4668, 4701, 5223, 5274, 5366,
5438, 5670, 6109, 6176, 6386, 6412, 6466, 6554, 6594, 6761, 6941,
6957, 7076, 7173, 7178, 7208, 7263, 7370, 7489, 7726, 7800, 8293,
8309, 8469, 8588, 8759, 8914, 9242, 9254, 9334, 9354, 9422, 9476,
9515, 9545, 9709, 9714, 9741, 9982, 9995, 10145, 10284, 10384, 10464,
10508, 10641, 10720, 10771, 10810, 10935, 11097, 11367, 11525, 11554, 11574,
11660, 11857, 11930, 12025, 12078, 12203, 12237, 12245, 12297, 12432, 12466,
12601, 12745, 12893, 12928, 13127, 13157, 13173, 13336, 13458, 13517, 13553,
13681, 13747, 13893, 13935, 14108, 14191, 14265, 14408, 14439, 14468, 14528,
14565, 14587, 14618, 14642, 14993, 15010, 15260, 15358, 15453, 15539, 15557,
15586, 15594, 15728, 15893, 15904, 16156, 16304, 16408, 16532, 16789, 16974,
17015, 17294, 17330, 17347, 17733, 17773, 17981, 17992, 18015, 18209, 18211,
18278, 18566, 18603, 18643, 18912, 19327, 19419, 19538, 19700, 19714, 19872,
19873, 19895, 19971, 20118, 20379, 20515, 20526, 20781, 20967, 21108, 21163,
21179, 21431, 21474, 21595, 21749, 21822, 21848, 21999, 22314, 22476, 22539,
22677, 23070, 23071, 23491, 23841, 23986, 24017, 24109, 24139, 24196, 24301,
24355, 24742, 24965, 24970, 24987, 25254, 25268, 25287, 25331, 26050, 26133,
26238, 26364, 26388, 26435, 26804, 26844, 26849, 26934, 27190, 27294, 27441,
27467, 27679, 27702, 27762, 27772, 27821, 27844, 27860, 27912, 28068, 28115,
28301, 28304, 28379, 28440, 28816, 28885, 28948, 28966, 29348, 29484, 29509,
29902, 29908, 29917, 29951, 30127, 30181, 30693, 30779, 30861, 30903, 31061,
31358, 31646, 31658, 31713, 31782, 31815, 31905, 31967, 32019, 32333, 32376,
32394, 32452, 32635, 32709, 32973, 33505, 33506, 33602, 33693, 33751, 33793,
33942, 33993, 34106, 34413, 34508, 34526, 34798, 34974, 34999, 35033, 35106,
35159, 35200, 35288, 35305, 35355, 35373, 35522, 35583, 35602, 35716, 35956,
36022, 36035, 36264, 36315, 36359, 36525, 36601, 36616, 36627, 36677, 36939,
36970, 37050, 37139, 37218, 37287, 37445, 37467, 37502, 37521, 37552, 37635,
37705, 37737, 37786, 37855, 38242, 38410, 38790, 38881, 39036, 39051, 39103,
39123, 39165, 39195, 39373, 39425, 39464, 39476, 39499, 39627, 39657, 39754,
39804, 40029, 40510, 40651, 40660, 40745, 40974, 41163, 41275, 41515, 41847,
41931, 42030, 42174, 42385, 42448, 42462, 43183, 43243, 43279, 43417, 43645,
43698, 44144, 44425, 44430, 44625, 44739, 44849, 44993, 45335, 45343, 45561,
45594, 45734, 45978, 46070, 46162, 46378, 46449, 46704, 46833, 47257, 47268,
47548, 47984, 47990, 48101, 48545, 48661};
test_read_index_file(meta_arm_old_v1, data_dir, "arm_old", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1, false,
expected_gif_cardinality, expected_gif_doc_ids);
{
TabletIndex meta_x86_old_v2 = create_test_index_meta(10083, "request_idx", 2);
std::string field_name_avx2 = "2";
default_query_term = "gif";
expected_gif_cardinality = 37343;
expected_gif_doc_ids = {0, 19, 110, 1000, 2581,
7196, 9090, 16711, 10278, 44702};
test_read_index_file(meta_x86_old_v2, data_dir, "x86_old_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2, true,
expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 346;
expected_gif_doc_ids = {
3, 222, 502, 649, 671, 814, 1101, 1110, 1286, 1329,
1350, 1409, 1478, 1598, 1621, 1627, 1686, 1895, 2218, 2304,
2429, 2654, 2735, 2798, 2799, 2828, 2966, 3050, 3083, 3261,
3296, 3574, 3625, 3653, 4053, 4128, 4192, 4200, 4594, 4623,
4747, 5284, 5371, 5379, 5467, 5567, 5694, 5714, 5723, 5903,
5954, 6120, 6187, 6226, 6451, 6664, 6723, 6748, 6958, 7319,
7933, 7947, 8041, 8156, 8203, 8205, 8568, 8626, 8777, 8923,
8999, 9088, 9193, 9239, 9282, 9358, 9386, 9531, 9589, 9599,
9864, 10006, 10229, 10370, 10523, 10751, 10854, 10864, 10883, 11045,
11077, 11134, 11149, 11252, 11258, 11260, 11432, 11488, 11578, 11599,
11765, 11826, 11929, 12124, 12154, 12277, 12339, 12410, 12432, 12500,
12612, 12618, 12654, 12872, 12929, 12987, 13173, 13293, 13306, 13397,
13559, 13800, 14017, 14180, 14195, 14283, 14385, 14481, 14659, 14728,
14738, 15150, 15574, 15586, 15774, 15914, 15968, 16093, 16131, 16155,
16337, 16340, 16391, 16420, 16577, 16632, 16836, 16874, 16883, 16896,
16954, 17060, 17241, 17302, 17359, 17601, 17985, 18017, 18043, 18084,
18334, 18539, 18637, 18831, 18864, 19068, 19075, 19140, 19445, 19487,
19495, 19559, 19648, 19656, 19770, 19880, 20284, 20311, 20358, 20439,
21103, 21252, 21382, 21429, 21678, 21765, 21773, 21779, 21877, 22067,
22318, 22607, 22713, 22719, 22929, 23074, 23148, 23209, 23500, 23611,
23614, 23709, 23761, 23952, 23999, 24120, 24217, 24503, 24656, 24675,
24842, 24924, 24970, 25144, 25582, 25767, 25923, 26184, 26206, 26344,
26376, 26529, 26682, 26686, 26803, 26896, 26921, 26951, 26982, 27033,
27075, 27163, 27166, 27299, 27567, 27682, 28010, 28173, 28368, 28423,
28440, 28590, 28801, 28990, 28994, 29138, 29256, 29300, 29657, 29769,
30018, 30086, 30154, 30189, 30382, 30385, 30445, 30456, 30489, 30545,
30908, 30931, 31009, 31267, 31297, 31336, 31696, 31728, 31735, 31943,
32155, 32244, 32342, 32431, 32569, 32733, 32799, 32817, 32903, 33078,
33552, 34064, 34604, 34705, 35186, 35256, 35284, 35295, 35494, 35745,
35943, 36051, 36343, 36430, 36452, 36666, 36697, 36763, 36822, 36890,
37511, 37547, 37706, 38256, 38581, 38911, 38931, 38955, 38998, 39131,
39135, 39255, 39312, 39394, 39459, 39635, 39707, 40190, 40215, 40708,
41063, 41264, 41361, 41593, 41699, 41864, 42190, 42363, 42444, 42873,
42983, 43314, 43587, 43693, 43880, 43908, 43909, 43925, 43978, 43986,
44071, 44183, 44340, 44398, 44466, 44498};
test_read_index_file(meta_x86_old_v2, data_dir, "x86_old_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2, true,
expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_x86_old_v1 = create_test_index_meta(10248, "request_idx", 2);
std::string field_name_avx2 = "request";
default_query_term = "gif";
expected_gif_cardinality = 40893;
expected_gif_doc_ids = {0, 19, 110, 1001, 2581,
7196, 9090, 16711, 10278, 44701};
test_read_index_file(meta_x86_old_v1, data_dir, "x86_old", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1, true,
expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 356;
expected_gif_doc_ids = {
622, 754, 1021, 1186, 1403, 1506, 1655, 1661, 1833, 2287,
2356, 2425, 2849, 3198, 3350, 3365, 3416, 3423, 3499, 3541,
3609, 3682, 3936, 4117, 4198, 4589, 4591, 4808, 4959, 5282,
5332, 5495, 5560, 5624, 5773, 5831, 6138, 6180, 6361, 6372,
6621, 6777, 6878, 6911, 6983, 7048, 7148, 7207, 7273, 7274,
7385, 7545, 7735, 7904, 7912, 8150, 8215, 8238, 8363, 8598,
8672, 8765, 8877, 9188, 9264, 9761, 9864, 9866, 9946, 10022,
10139, 10143, 10146, 10184, 10291, 10304, 10308, 10332, 10371, 10695,
10707, 11056, 11095, 11111, 11505, 11752, 11860, 11989, 12119, 12156,
12655, 12764, 12792, 13055, 13636, 13824, 13902, 13912, 14061, 14152,
14315, 14355, 14618, 14712, 14788, 15050, 15057, 15110, 15122, 15249,
15267, 15281, 15735, 15848, 15939, 16117, 16327, 16331, 16597, 16739,
16868, 17092, 17458, 17553, 17602, 17664, 17781, 18061, 18353, 18397,
18468, 18717, 18726, 19131, 19209, 19402, 19551, 19812, 20128, 20146,
20232, 20322, 20407, 20431, 20436, 20466, 20757, 20960, 20994, 21197,
21254, 21487, 21561, 21602, 21662, 21710, 21754, 21826, 21965, 22091,
22200, 22203, 22291, 22317, 22561, 22584, 22606, 22950, 23140, 23315,
23442, 23858, 24026, 24322, 24581, 24617, 24655, 24756, 24974, 25191,
25246, 25287, 25406, 25599, 25830, 26020, 26109, 26149, 26402, 26431,
26451, 26458, 26495, 26766, 26777, 26848, 26966, 27053, 27089, 27177,
27519, 27595, 27693, 28294, 28719, 28755, 29073, 29323, 29472, 29496,
29604, 29761, 29772, 29953, 30030, 30083, 30139, 30210, 30719, 30774,
30868, 30897, 31200, 31347, 31811, 31880, 31903, 32040, 32048, 32225,
32335, 32357, 32517, 32579, 32679, 32821, 33294, 33393, 33509, 33675,
33802, 34390, 34441, 34474, 34547, 34557, 35057, 35262, 35327, 35348,
35455, 35482, 35668, 35811, 35845, 35953, 36098, 36151, 36602, 36711,
36946, 37036, 37220, 37291, 37436, 37721, 37747, 37864, 37890, 37923,
38045, 38588, 38654, 38730, 38930, 39169, 39814, 40401, 40689, 40762,
40822, 41249, 41399, 41419, 41572, 41736, 41768, 41946, 41989, 42077,
42079, 42225, 42360, 42524, 42576, 42595, 42691, 42784, 42892, 42930,
43210, 43299, 43348, 43468, 43510, 43622, 43795, 43824, 43893, 43972,
43975, 43998, 44008, 44023, 44031, 44049, 44139, 44518, 44555, 44597,
44815, 44879, 45014, 45020, 45054, 45084, 45100, 45464, 45471, 45505,
45580, 45593, 45686, 45991, 46019, 46021, 46107, 46138, 46197, 46209,
46551, 46658, 46988, 47027, 47046, 47071, 47106, 47190, 47225, 47439,
47465, 47531, 47602, 47660, 48453, 48575};
test_read_index_file(meta_x86_old_v1, data_dir, "x86_old", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1, true,
expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_x86_new_v1 =
create_test_index_meta(1744025019684, "request_idx", 2);
std::string field_name_avx2 = "request";
default_query_term = "gif";
expected_gif_cardinality = 37337;
expected_gif_doc_ids = {0, 19, 110, 1001, 2581,
7196, 9090, 16711, 10279, 44701};
test_read_index_file(meta_x86_new_v1, data_dir, "x86_new", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1,
false, expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 368;
expected_gif_doc_ids = {
294, 678, 835, 852, 998, 1204, 1237, 1553, 1648, 1674,
1859, 1944, 2024, 2043, 2319, 2383, 2476, 2955, 3064, 3281,
3292, 3324, 3341, 3389, 3424, 3713, 3715, 3731, 3794, 3801,
3824, 3892, 4089, 4174, 4302, 4436, 4459, 4509, 4697, 4726,
4891, 4931, 4975, 5008, 5020, 5154, 5200, 5288, 5375, 5458,
5624, 5728, 5844, 5864, 6306, 6452, 6461, 6619, 6632, 6755,
7021, 7093, 7400, 7414, 7422, 7484, 7752, 7758, 7785, 7900,
7992, 8013, 8019, 8075, 8076, 8118, 8119, 8123, 8126, 8248,
8345, 8557, 8772, 8900, 8946, 8966, 8974, 9583, 9597, 9613,
9782, 9869, 10033, 10162, 10271, 10297, 10439, 10520, 10558, 10591,
10651, 10807, 10810, 10864, 10906, 11293, 11499, 11511, 11572, 11574,
11665, 11697, 11722, 11729, 11801, 11845, 11868, 12031, 12251, 12289,
12323, 12337, 12576, 12804, 12938, 13349, 13459, 13509, 13558, 13938,
13951, 13989, 14006, 14237, 14362, 14365, 14508, 14560, 14658, 14666,
14954, 15155, 15216, 15314, 15430, 15532, 15567, 15689, 15848, 15978,
15983, 15985, 16119, 16174, 16193, 16506, 16543, 17048, 17078, 17190,
17351, 17412, 17444, 17475, 17761, 17950, 17996, 18195, 18275, 18405,
18637, 18780, 19245, 19445, 19604, 19744, 19763, 20284, 20308, 20530,
20762, 20782, 20792, 20818, 20867, 20959, 21104, 21207, 21255, 21280,
21339, 21514, 21870, 21966, 22231, 22275, 22391, 22478, 22509, 22637,
22942, 22984, 23121, 23269, 23362, 23572, 23589, 23832, 23919, 24043,
24078, 24126, 24244, 24364, 24405, 24454, 24782, 24794, 24833, 24949,
24980, 24989, 25034, 25166, 25358, 25443, 25553, 25600, 25634, 25900,
26054, 26105, 26196, 26218, 26241, 26532, 26637, 26918, 27179, 27207,
27258, 27463, 27604, 27614, 27624, 27669, 27837, 27841, 28025, 28172,
28181, 28214, 28391, 28554, 28785, 28812, 28893, 29063, 29665, 29810,
29900, 30236, 30256, 30313, 30357, 30447, 30945, 30965, 30997, 31012,
31033, 31302, 31309, 31806, 31821, 31904, 32080, 32128, 32330, 32359,
32426, 32430, 32507, 32580, 32588, 32711, 32767, 32835, 32841, 32903,
33094, 33226, 33313, 33371, 33615, 33742, 33808, 34480, 34571, 34874,
34989, 35189, 35234, 35241, 35258, 35742, 35793, 36207, 36208, 36214,
36735, 36915, 37041, 37286, 37391, 37433, 37454, 37480, 37493, 37504,
37695, 37761, 37769, 38027, 38038, 38113, 38285, 38343, 38596, 38625,
38758, 38874, 38944, 39045, 39346, 39390, 39432, 39670, 40012, 40068,
40342, 40826, 41087, 41206, 41502, 41700, 42215, 42251, 42373, 42413,
42475, 42482, 42490, 42506, 42594, 42656, 42665, 43075, 43147, 43366,
43488, 43499, 43609, 43889, 43925, 44040, 44180, 44568};
test_read_index_file(meta_x86_new_v1, data_dir, "x86_new", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1,
false, expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_x86_new_v2 =
create_test_index_meta(1744025019611, "request_idx", 2);
std::string field_name_avx2 = "2";
default_query_term = "gif";
expected_gif_cardinality = 37170;
expected_gif_doc_ids = {0, 18, 110, 1000, 2581,
7196, 9090, 16711, 10276, 44702};
test_read_index_file(meta_x86_new_v2, data_dir, "x86_new_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2, true,
expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 356;
expected_gif_doc_ids = {
260, 329, 334, 347, 459, 471, 568, 676, 689, 718,
760, 1267, 1421, 1477, 2363, 2523, 2571, 2725, 2941, 3125,
3148, 3306, 3459, 3808, 3856, 3933, 4022, 4076, 4386, 4815,
4818, 4898, 4938, 4970, 4975, 5192, 5302, 5320, 5417, 5470,
5752, 5875, 6007, 6143, 6425, 6597, 6639, 6761, 6961, 6977,
6983, 7045, 7179, 7214, 7350, 7393, 7436, 7485, 7518, 7592,
7739, 7856, 7921, 7957, 8006, 8116, 8411, 8664, 8716, 8728,
8747, 8809, 8883, 8907, 8931, 8995, 9089, 9393, 9611, 9746,
9787, 9963, 10080, 10230, 10348, 10464, 10494, 10547, 10552, 10666,
10813, 10847, 10989, 11134, 11298, 11531, 11605, 11654, 11720, 11791,
11835, 11994, 12012, 12068, 12232, 12272, 12336, 12438, 12537, 12646,
12738, 12768, 12923, 12925, 13173, 13186, 13187, 13251, 13503, 13830,
13973, 14121, 14291, 14378, 14380, 14389, 14453, 14495, 14508, 14620,
14686, 14872, 15241, 15275, 15491, 15564, 15652, 15951, 15966, 16287,
16289, 16531, 16681, 16914, 16919, 17079, 17382, 17393, 17860, 17961,
18158, 18191, 18578, 18692, 18741, 18987, 19038, 19117, 19271, 19641,
19723, 20253, 20259, 20473, 20766, 20863, 21419, 21424, 21908, 22325,
22327, 22449, 22701, 22852, 22867, 22906, 22912, 22958, 23175, 23203,
23332, 23461, 23493, 23746, 23921, 24257, 24328, 24411, 24479, 24747,
24816, 25462, 25492, 25528, 25872, 25944, 26164, 26414, 26463, 26688,
26779, 27033, 27283, 27303, 27858, 27948, 28248, 28372, 28402, 28460,
28478, 28897, 29019, 29053, 29140, 29216, 29299, 29393, 29414, 29575,
29789, 29803, 29805, 29934, 30270, 30278, 30291, 30301, 30433, 30493,
30698, 30723, 30737, 30751, 31015, 31167, 31447, 32136, 32138, 32296,
32318, 32374, 32585, 32747, 32815, 32964, 33060, 33144, 33159, 33315,
33342, 33543, 33753, 33767, 33990, 34176, 34375, 34422, 34455, 34538,
34563, 34708, 34738, 35050, 35130, 35137, 35220, 35422, 35484, 35487,
35603, 35697, 35717, 35986, 36114, 36116, 36230, 36288, 36332, 36469,
36520, 36572, 36727, 36959, 37099, 37152, 37400, 37473, 37712, 37838,
37920, 38264, 38354, 38431, 38646, 38692, 38757, 38888, 38909, 38945,
39078, 39103, 39125, 39138, 39155, 39274, 39412, 39553, 39577, 39583,
39653, 39706, 39895, 39934, 39978, 40023, 40154, 40250, 40259, 40310,
40357, 40376, 40457, 40643, 40665, 40881, 40990, 41368, 41379, 41519,
41578, 41641, 41680, 42260, 42357, 42391, 42461, 42561, 42575, 42781,
42810, 42844, 43026, 43028, 43046, 43145, 43386, 43388, 43576, 43667,
43798, 43983, 44280, 44453, 44591, 44634};
test_read_index_file(meta_x86_new_v2, data_dir, "x86_new_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2, true,
expected_gif_cardinality, expected_gif_doc_ids);
}
}
} else {
// Test x86 architecture cases
std::cout << "Testing on x86 architecture" << std::endl;
if (has_avx2_support()) {
std::cout << "Testing with AVX2 support" << std::endl;
{
TabletIndex meta_arm_old_v2 =
create_test_index_meta(1744016478578, "request_idx", 2);
std::string field_name_avx2 = "2";
default_query_term = "gif";
expected_gif_cardinality = 37284;
expected_gif_doc_ids = {0, 19, 110, 1000, 2581,
7197, 9091, 16711, 29676, 44702};
test_read_index_file(meta_arm_old_v2, data_dir, "arm_old_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2, true,
expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 359;
expected_gif_doc_ids = {
25, 63, 66, 135, 214, 276, 287, 321, 653, 819,
968, 1038, 1115, 1210, 1305, 1394, 1650, 1690, 1761, 1934,
1935, 2101, 2114, 2544, 2815, 2912, 3028, 3104, 3475, 3953,
3991, 4052, 4097, 4424, 4430, 4458, 4504, 4571, 4629, 4704,
4711, 4838, 5021, 5322, 5362, 5414, 5461, 5524, 5681, 5828,
5877, 6031, 6123, 6249, 6298, 6575, 6626, 6637, 6692, 6708,
6765, 6926, 6953, 7061, 7089, 7144, 7147, 7184, 7342, 7461,
7615, 7703, 7818, 8002, 8014, 8280, 8369, 8398, 8440, 8554,
8675, 8682, 8780, 9064, 9379, 9448, 9455, 9639, 10036, 10124,
10164, 10224, 10246, 10568, 10736, 10750, 10914, 10930, 10944, 10970,
11149, 11434, 11435, 11534, 11862, 11961, 12187, 12247, 12344, 12479,
12632, 12923, 13015, 13018, 13122, 13277, 13357, 13459, 13466, 13597,
13792, 13857, 13952, 14096, 14127, 14211, 14221, 14344, 14563, 14567,
14588, 14606, 14692, 14868, 14880, 14990, 15085, 15101, 15211, 15218,
15439, 15530, 15564, 15676, 15695, 15727, 15754, 15846, 15895, 15904,
15983, 16004, 16299, 16423, 16476, 16530, 16954, 17045, 17202, 17393,
17592, 17693, 17829, 17852, 18018, 18224, 18335, 18881, 18942, 19162,
19387, 19401, 19418, 19434, 19525, 19710, 19805, 20054, 20126, 20127,
20407, 20572, 20742, 20929, 21023, 21024, 21248, 21267, 21354, 21452,
21704, 21810, 21831, 21847, 21900, 22202, 22328, 22599, 22629, 22671,
22761, 22762, 22824, 23139, 23478, 23784, 23797, 23884, 23886, 23983,
24128, 24137, 24176, 24253, 24434, 24484, 24518, 24538, 24655, 24849,
24853, 24865, 24888, 25163, 25256, 25274, 25307, 25613, 25816, 26225,
26323, 26459, 26461, 26476, 26580, 26598, 26800, 26932, 26962, 27202,
27499, 27506, 27768, 27923, 28049, 28133, 28305, 28468, 28535, 28670,
28717, 28782, 29154, 29692, 29742, 30112, 30125, 30289, 30353, 30437,
30734, 30741, 30848, 30933, 31332, 31399, 31581, 31841, 31867, 32025,
32446, 32463, 32712, 32947, 33038, 33210, 33325, 33563, 33572, 33757,
33947, 33975, 34016, 34041, 34210, 34627, 34684, 34732, 35064, 35684,
35787, 35809, 35811, 35996, 36272, 36389, 36418, 36420, 36568, 36847,
36956, 37022, 37189, 37200, 37401, 37484, 37581, 37852, 37939, 38156,
38269, 38785, 38874, 39072, 39081, 39094, 39157, 39187, 39308, 39562,
39676, 39690, 39814, 39848, 40134, 40350, 40352, 40684, 41143, 41249,
41416, 41463, 41738, 41840, 41875, 42028, 42077, 42104, 42439, 42467,
42528, 42784, 42793, 42970, 43020, 43418, 43430, 43571, 43809, 43811,
44040, 44057, 44081, 44168, 44288, 44329, 44608, 44624, 44690};
test_read_index_file(meta_arm_old_v2, data_dir, "arm_old_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2, true,
expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_arm_old_v1 =
create_test_index_meta(1744016478651, "request_idx", 2);
std::string field_name_avx2 = "request";
default_query_term = "gif";
expected_gif_cardinality = 40962;
expected_gif_doc_ids = {0, 21, 110, 1000, 2581,
7196, 9091, 16712, 26132, 44702};
test_read_index_file(meta_arm_old_v1, data_dir, "arm_old", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1, true,
expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 402;
expected_gif_doc_ids = {
36, 41, 242, 628, 716, 741, 884, 902, 1025, 1129,
1349, 1401, 1871, 1873, 2074, 2184, 2420, 2815, 3138, 3164,
3189, 3302, 3308, 3347, 3430, 3475, 3645, 3772, 3803, 3921,
4036, 4080, 4127, 4419, 4424, 4450, 4526, 4546, 4608, 4668,
4701, 5223, 5274, 5366, 5438, 5670, 6109, 6176, 6386, 6412,
6466, 6554, 6594, 6761, 6941, 6957, 7076, 7173, 7178, 7208,
7263, 7370, 7489, 7726, 7800, 8293, 8309, 8469, 8588, 8759,
8914, 9242, 9254, 9334, 9354, 9422, 9476, 9515, 9545, 9709,
9714, 9741, 9982, 9995, 10145, 10284, 10384, 10464, 10508, 10641,
10720, 10771, 10810, 10935, 11097, 11367, 11525, 11554, 11574, 11660,
11857, 11930, 12025, 12078, 12203, 12237, 12245, 12297, 12432, 12466,
12601, 12745, 12893, 12928, 13127, 13157, 13173, 13336, 13458, 13517,
13553, 13681, 13747, 13893, 13935, 14108, 14191, 14265, 14408, 14439,
14468, 14528, 14565, 14587, 14618, 14642, 14993, 15010, 15260, 15358,
15453, 15539, 15557, 15586, 15594, 15728, 15893, 15904, 16156, 16304,
16408, 16532, 16789, 16974, 17015, 17294, 17330, 17347, 17733, 17773,
17981, 17992, 18015, 18209, 18211, 18278, 18566, 18603, 18643, 18912,
19327, 19419, 19538, 19700, 19714, 19872, 19873, 19895, 19971, 20118,
20379, 20515, 20526, 20781, 20967, 21108, 21163, 21179, 21431, 21474,
21595, 21749, 21822, 21848, 21999, 22314, 22476, 22539, 22677, 23070,
23071, 23491, 23841, 23986, 24017, 24109, 24139, 24196, 24301, 24355,
24742, 24965, 24970, 24987, 25254, 25268, 25287, 25331, 26050, 26133,
26238, 26364, 26388, 26435, 26804, 26844, 26849, 26934, 27190, 27294,
27441, 27467, 27679, 27702, 27762, 27772, 27821, 27844, 27860, 27912,
28068, 28115, 28301, 28304, 28379, 28440, 28816, 28885, 28948, 28966,
29348, 29484, 29509, 29902, 29908, 29917, 29951, 30127, 30181, 30693,
30779, 30861, 30903, 31061, 31358, 31646, 31658, 31713, 31782, 31815,
31905, 31967, 32019, 32333, 32376, 32394, 32452, 32635, 32709, 32973,
33505, 33506, 33602, 33693, 33751, 33793, 33942, 33993, 34106, 34413,
34508, 34526, 34798, 34974, 34999, 35033, 35106, 35159, 35200, 35288,
35305, 35355, 35373, 35522, 35583, 35602, 35716, 35956, 36022, 36035,
36264, 36315, 36359, 36525, 36601, 36616, 36627, 36677, 36939, 36970,
37050, 37139, 37218, 37287, 37445, 37467, 37502, 37521, 37552, 37635,
37705, 37737, 37786, 37855, 38242, 38410, 38790, 38881, 39036, 39051,
39103, 39123, 39165, 39195, 39373, 39425, 39464, 39476, 39499, 39627,
39657, 39754, 39804, 40029, 40510, 40651, 40660, 40745, 40974, 41163,
41275, 41515, 41847, 41931, 42030, 42174, 42385, 42448, 42462, 43183,
43243, 43279, 43417, 43645, 43698, 44144, 44425, 44430, 44625, 44739,
44849, 44993, 45335, 45343, 45561, 45594, 45734, 45978, 46070, 46162,
46378, 46449, 46704, 46833, 47257, 47268, 47548, 47984, 47990, 48101,
48545, 48661};
test_read_index_file(meta_arm_old_v1, data_dir, "arm_old", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1, true,
expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_arm_new_v2 =
create_test_index_meta(1744017919311, "request_idx", 2);
std::string field_name_avx2 = "2";
default_query_term = "gif";
expected_gif_cardinality = 37170;
expected_gif_doc_ids = {0, 18, 110, 1000, 2581,
7196, 9090, 16711, 10276, 44702};
test_read_index_file(meta_arm_new_v2, data_dir, "arm_new_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2,
false, expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 356;
expected_gif_doc_ids = {
260, 329, 334, 347, 459, 471, 568, 676, 689, 718,
760, 1267, 1421, 1477, 2363, 2523, 2571, 2725, 2941, 3125,
3148, 3306, 3459, 3808, 3856, 3933, 4022, 4076, 4386, 4815,
4818, 4898, 4938, 4970, 4975, 5192, 5302, 5320, 5417, 5470,
5752, 5875, 6007, 6143, 6425, 6597, 6639, 6761, 6961, 6977,
6983, 7045, 7179, 7214, 7350, 7393, 7436, 7485, 7518, 7592,
7739, 7856, 7921, 7957, 8006, 8116, 8411, 8664, 8716, 8728,
8747, 8809, 8883, 8907, 8931, 8995, 9089, 9393, 9611, 9746,
9787, 9963, 10080, 10230, 10348, 10464, 10494, 10547, 10552, 10666,
10813, 10847, 10989, 11134, 11298, 11531, 11605, 11654, 11720, 11791,
11835, 11994, 12012, 12068, 12232, 12272, 12336, 12438, 12537, 12646,
12738, 12768, 12923, 12925, 13173, 13186, 13187, 13251, 13503, 13830,
13973, 14121, 14291, 14378, 14380, 14389, 14453, 14495, 14508, 14620,
14686, 14872, 15241, 15275, 15491, 15564, 15652, 15951, 15966, 16287,
16289, 16531, 16681, 16914, 16919, 17079, 17382, 17393, 17860, 17961,
18158, 18191, 18578, 18692, 18741, 18987, 19038, 19117, 19271, 19641,
19723, 20253, 20259, 20473, 20766, 20863, 21419, 21424, 21908, 22325,
22327, 22449, 22701, 22852, 22867, 22906, 22912, 22958, 23175, 23203,
23332, 23461, 23493, 23746, 23921, 24257, 24328, 24411, 24479, 24747,
24816, 25462, 25492, 25528, 25872, 25944, 26164, 26414, 26463, 26688,
26779, 27033, 27283, 27303, 27858, 27948, 28248, 28372, 28402, 28460,
28478, 28897, 29019, 29053, 29140, 29216, 29299, 29393, 29414, 29575,
29789, 29803, 29805, 29934, 30270, 30278, 30291, 30301, 30433, 30493,
30698, 30723, 30737, 30751, 31015, 31167, 31447, 32136, 32138, 32296,
32318, 32374, 32585, 32747, 32815, 32964, 33060, 33144, 33159, 33315,
33342, 33543, 33753, 33767, 33990, 34176, 34375, 34422, 34455, 34538,
34563, 34708, 34738, 35050, 35130, 35137, 35220, 35422, 35484, 35487,
35603, 35697, 35717, 35986, 36114, 36116, 36230, 36288, 36332, 36469,
36520, 36572, 36727, 36959, 37099, 37152, 37400, 37473, 37712, 37838,
37920, 38264, 38354, 38431, 38646, 38692, 38757, 38888, 38909, 38945,
39078, 39103, 39125, 39138, 39155, 39274, 39412, 39553, 39577, 39583,
39653, 39706, 39895, 39934, 39978, 40023, 40154, 40250, 40259, 40310,
40357, 40376, 40457, 40643, 40665, 40881, 40990, 41368, 41379, 41519,
41578, 41641, 41680, 42260, 42357, 42391, 42461, 42561, 42575, 42781,
42810, 42844, 43026, 43028, 43046, 43145, 43386, 43388, 43576, 43667,
43798, 43983, 44280, 44453, 44591, 44634};
test_read_index_file(meta_arm_new_v2, data_dir, "arm_new_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2,
false, expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_arm_new_v1 =
create_test_index_meta(1744017919441, "request_idx", 2);
std::string field_name_avx2 = "request";
default_query_term = "gif";
expected_gif_cardinality = 37343;
expected_gif_doc_ids = {0, 21, 110, 1000, 2580,
7195, 9091, 16711, 26131, 44702};
test_read_index_file(meta_arm_new_v1, data_dir, "arm_new", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1,
false, expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 346;
expected_gif_doc_ids = {
3, 222, 502, 649, 671, 814, 1101, 1110, 1286, 1329,
1350, 1409, 1478, 1598, 1621, 1627, 1686, 1895, 2218, 2304,
2429, 2654, 2735, 2798, 2799, 2828, 2966, 3050, 3083, 3261,
3296, 3574, 3625, 3653, 4053, 4128, 4192, 4200, 4594, 4623,
4747, 5284, 5371, 5379, 5467, 5567, 5694, 5714, 5723, 5903,
5954, 6120, 6187, 6226, 6451, 6664, 6723, 6748, 6958, 7319,
7933, 7947, 8041, 8156, 8203, 8205, 8568, 8626, 8777, 8923,
8999, 9088, 9193, 9239, 9282, 9358, 9386, 9531, 9589, 9599,
9864, 10006, 10229, 10370, 10523, 10751, 10854, 10864, 10883, 11045,
11077, 11134, 11149, 11252, 11258, 11260, 11432, 11488, 11578, 11599,
11765, 11826, 11929, 12124, 12154, 12277, 12339, 12410, 12432, 12500,
12612, 12618, 12654, 12872, 12929, 12987, 13173, 13293, 13306, 13397,
13559, 13800, 14017, 14180, 14195, 14283, 14385, 14481, 14659, 14728,
14738, 15150, 15574, 15586, 15774, 15914, 15968, 16093, 16131, 16155,
16337, 16340, 16391, 16420, 16577, 16632, 16836, 16874, 16883, 16896,
16954, 17060, 17241, 17302, 17359, 17601, 17985, 18017, 18043, 18084,
18334, 18539, 18637, 18831, 18864, 19068, 19075, 19140, 19445, 19487,
19495, 19559, 19648, 19656, 19770, 19880, 20284, 20311, 20358, 20439,
21103, 21252, 21382, 21429, 21678, 21765, 21773, 21779, 21877, 22067,
22318, 22607, 22713, 22719, 22929, 23074, 23148, 23209, 23500, 23611,
23614, 23709, 23761, 23952, 23999, 24120, 24217, 24503, 24656, 24675,
24842, 24924, 24970, 25144, 25582, 25767, 25923, 26184, 26206, 26344,
26376, 26529, 26682, 26686, 26803, 26896, 26921, 26951, 26982, 27033,
27075, 27163, 27166, 27299, 27567, 27682, 28010, 28173, 28368, 28423,
28440, 28590, 28801, 28990, 28994, 29138, 29256, 29300, 29657, 29769,
30018, 30086, 30154, 30189, 30382, 30385, 30445, 30456, 30489, 30545,
30908, 30931, 31009, 31267, 31297, 31336, 31696, 31728, 31735, 31943,
32155, 32244, 32342, 32431, 32569, 32733, 32799, 32817, 32903, 33078,
33552, 34064, 34604, 34705, 35186, 35256, 35284, 35295, 35494, 35745,
35943, 36051, 36343, 36430, 36452, 36666, 36697, 36763, 36822, 36890,
37511, 37547, 37706, 38256, 38581, 38911, 38931, 38955, 38998, 39131,
39135, 39255, 39312, 39394, 39459, 39635, 39707, 40190, 40215, 40708,
41063, 41264, 41361, 41593, 41699, 41864, 42190, 42363, 42444, 42873,
42983, 43314, 43587, 43693, 43880, 43908, 43909, 43925, 43978, 43986,
44071, 44183, 44340, 44398, 44466, 44498};
test_read_index_file(meta_arm_new_v1, data_dir, "arm_new", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1,
false, expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_x86_old_v2 = create_test_index_meta(10083, "request_idx", 2);
std::string field_name_avx2 = "2";
default_query_term = "gif";
expected_gif_cardinality = 37343;
expected_gif_doc_ids = {0, 19, 110, 1000, 2581,
7196, 9090, 16711, 10278, 44702};
test_read_index_file(meta_x86_old_v2, data_dir, "x86_old_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2,
false, expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 346;
expected_gif_doc_ids = {
3, 222, 502, 649, 671, 814, 1101, 1110, 1286, 1329,
1350, 1409, 1478, 1598, 1621, 1627, 1686, 1895, 2218, 2304,
2429, 2654, 2735, 2798, 2799, 2828, 2966, 3050, 3083, 3261,
3296, 3574, 3625, 3653, 4053, 4128, 4192, 4200, 4594, 4623,
4747, 5284, 5371, 5379, 5467, 5567, 5694, 5714, 5723, 5903,
5954, 6120, 6187, 6226, 6451, 6664, 6723, 6748, 6958, 7319,
7933, 7947, 8041, 8156, 8203, 8205, 8568, 8626, 8777, 8923,
8999, 9088, 9193, 9239, 9282, 9358, 9386, 9531, 9589, 9599,
9864, 10006, 10229, 10370, 10523, 10751, 10854, 10864, 10883, 11045,
11077, 11134, 11149, 11252, 11258, 11260, 11432, 11488, 11578, 11599,
11765, 11826, 11929, 12124, 12154, 12277, 12339, 12410, 12432, 12500,
12612, 12618, 12654, 12872, 12929, 12987, 13173, 13293, 13306, 13397,
13559, 13800, 14017, 14180, 14195, 14283, 14385, 14481, 14659, 14728,
14738, 15150, 15574, 15586, 15774, 15914, 15968, 16093, 16131, 16155,
16337, 16340, 16391, 16420, 16577, 16632, 16836, 16874, 16883, 16896,
16954, 17060, 17241, 17302, 17359, 17601, 17985, 18017, 18043, 18084,
18334, 18539, 18637, 18831, 18864, 19068, 19075, 19140, 19445, 19487,
19495, 19559, 19648, 19656, 19770, 19880, 20284, 20311, 20358, 20439,
21103, 21252, 21382, 21429, 21678, 21765, 21773, 21779, 21877, 22067,
22318, 22607, 22713, 22719, 22929, 23074, 23148, 23209, 23500, 23611,
23614, 23709, 23761, 23952, 23999, 24120, 24217, 24503, 24656, 24675,
24842, 24924, 24970, 25144, 25582, 25767, 25923, 26184, 26206, 26344,
26376, 26529, 26682, 26686, 26803, 26896, 26921, 26951, 26982, 27033,
27075, 27163, 27166, 27299, 27567, 27682, 28010, 28173, 28368, 28423,
28440, 28590, 28801, 28990, 28994, 29138, 29256, 29300, 29657, 29769,
30018, 30086, 30154, 30189, 30382, 30385, 30445, 30456, 30489, 30545,
30908, 30931, 31009, 31267, 31297, 31336, 31696, 31728, 31735, 31943,
32155, 32244, 32342, 32431, 32569, 32733, 32799, 32817, 32903, 33078,
33552, 34064, 34604, 34705, 35186, 35256, 35284, 35295, 35494, 35745,
35943, 36051, 36343, 36430, 36452, 36666, 36697, 36763, 36822, 36890,
37511, 37547, 37706, 38256, 38581, 38911, 38931, 38955, 38998, 39131,
39135, 39255, 39312, 39394, 39459, 39635, 39707, 40190, 40215, 40708,
41063, 41264, 41361, 41593, 41699, 41864, 42190, 42363, 42444, 42873,
42983, 43314, 43587, 43693, 43880, 43908, 43909, 43925, 43978, 43986,
44071, 44183, 44340, 44398, 44466, 44498};
test_read_index_file(meta_x86_old_v2, data_dir, "x86_old_v2", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V2,
false, expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_x86_old_v1 = create_test_index_meta(10248, "request_idx", 2);
std::string field_name_avx2 = "request";
default_query_term = "gif";
expected_gif_cardinality = 40893;
expected_gif_doc_ids = {0, 19, 110, 1001, 2581,
7196, 9090, 16711, 10278, 44701};
test_read_index_file(meta_x86_old_v1, data_dir, "x86_old", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1,
false, expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 356;
expected_gif_doc_ids = {
622, 754, 1021, 1186, 1403, 1506, 1655, 1661, 1833, 2287,
2356, 2425, 2849, 3198, 3350, 3365, 3416, 3423, 3499, 3541,
3609, 3682, 3936, 4117, 4198, 4589, 4591, 4808, 4959, 5282,
5332, 5495, 5560, 5624, 5773, 5831, 6138, 6180, 6361, 6372,
6621, 6777, 6878, 6911, 6983, 7048, 7148, 7207, 7273, 7274,
7385, 7545, 7735, 7904, 7912, 8150, 8215, 8238, 8363, 8598,
8672, 8765, 8877, 9188, 9264, 9761, 9864, 9866, 9946, 10022,
10139, 10143, 10146, 10184, 10291, 10304, 10308, 10332, 10371, 10695,
10707, 11056, 11095, 11111, 11505, 11752, 11860, 11989, 12119, 12156,
12655, 12764, 12792, 13055, 13636, 13824, 13902, 13912, 14061, 14152,
14315, 14355, 14618, 14712, 14788, 15050, 15057, 15110, 15122, 15249,
15267, 15281, 15735, 15848, 15939, 16117, 16327, 16331, 16597, 16739,
16868, 17092, 17458, 17553, 17602, 17664, 17781, 18061, 18353, 18397,
18468, 18717, 18726, 19131, 19209, 19402, 19551, 19812, 20128, 20146,
20232, 20322, 20407, 20431, 20436, 20466, 20757, 20960, 20994, 21197,
21254, 21487, 21561, 21602, 21662, 21710, 21754, 21826, 21965, 22091,
22200, 22203, 22291, 22317, 22561, 22584, 22606, 22950, 23140, 23315,
23442, 23858, 24026, 24322, 24581, 24617, 24655, 24756, 24974, 25191,
25246, 25287, 25406, 25599, 25830, 26020, 26109, 26149, 26402, 26431,
26451, 26458, 26495, 26766, 26777, 26848, 26966, 27053, 27089, 27177,
27519, 27595, 27693, 28294, 28719, 28755, 29073, 29323, 29472, 29496,
29604, 29761, 29772, 29953, 30030, 30083, 30139, 30210, 30719, 30774,
30868, 30897, 31200, 31347, 31811, 31880, 31903, 32040, 32048, 32225,
32335, 32357, 32517, 32579, 32679, 32821, 33294, 33393, 33509, 33675,
33802, 34390, 34441, 34474, 34547, 34557, 35057, 35262, 35327, 35348,
35455, 35482, 35668, 35811, 35845, 35953, 36098, 36151, 36602, 36711,
36946, 37036, 37220, 37291, 37436, 37721, 37747, 37864, 37890, 37923,
38045, 38588, 38654, 38730, 38930, 39169, 39814, 40401, 40689, 40762,
40822, 41249, 41399, 41419, 41572, 41736, 41768, 41946, 41989, 42077,
42079, 42225, 42360, 42524, 42576, 42595, 42691, 42784, 42892, 42930,
43210, 43299, 43348, 43468, 43510, 43622, 43795, 43824, 43893, 43972,
43975, 43998, 44008, 44023, 44031, 44049, 44139, 44518, 44555, 44597,
44815, 44879, 45014, 45020, 45054, 45084, 45100, 45464, 45471, 45505,
45580, 45593, 45686, 45991, 46019, 46021, 46107, 46138, 46197, 46209,
46551, 46658, 46988, 47027, 47046, 47071, 47106, 47190, 47225, 47439,
47465, 47531, 47602, 47660, 48453, 48575};
test_read_index_file(meta_x86_old_v1, data_dir, "x86_old", field_name_avx2,
default_query_term, InvertedIndexStorageFormatPB::V1,
false, expected_gif_cardinality, expected_gif_doc_ids);
}
} else {
std::cout << "Testing with SSE support" << std::endl;
{
TabletIndex meta_x86_old_noavx2_v2 =
create_test_index_meta(1744076789957, "request_idx", 2);
std::string field_name_avx2 = "2";
default_query_term = "gif";
expected_gif_cardinality = 37203;
expected_gif_doc_ids = {0, 19, 110, 1000, 2582,
7196, 9090, 16711, 10279, 44703};
test_read_index_file(meta_x86_old_noavx2_v2, data_dir, "x86_noavx2_old_v2",
field_name_avx2, default_query_term,
InvertedIndexStorageFormatPB::V2, false,
expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 395;
expected_gif_doc_ids = {
267, 285, 462, 515, 578, 710, 778, 805, 807, 834,
958, 1166, 1231, 1266, 1339, 1487, 1523, 1524, 1555, 1622,
1632, 1676, 1742, 1762, 1798, 2068, 2074, 2220, 2559, 2594,
2600, 2646, 3101, 3426, 3491, 3827, 4085, 4192, 4358, 4590,
4776, 4789, 5191, 5236, 5339, 5378, 5578, 5630, 5711, 5742,
5747, 5884, 5932, 6061, 6157, 6187, 6387, 6404, 6488, 6583,
6808, 6905, 6969, 7033, 7059, 7582, 7630, 7651, 7820, 8045,
8161, 8244, 8382, 8472, 8476, 8545, 8628, 8700, 9047, 9129,
9191, 9197, 9265, 9660, 9808, 9998, 10185, 10324, 10431, 10441,
10507, 10569, 10611, 10693, 10761, 10965, 10996, 11113, 11348, 11370,
11578, 11592, 11694, 11969, 12104, 12521, 12718, 12871, 12907, 12911,
13018, 13113, 13126, 13136, 13140, 13304, 13381, 13568, 13606, 13637,
13720, 13727, 13871, 13883, 13931, 14075, 14179, 14210, 14367, 14464,
14475, 14526, 14723, 14835, 14884, 15070, 15163, 15283, 15309, 15373,
15420, 15495, 15531, 15635, 15704, 15752, 15760, 15768, 15777, 15827,
15855, 15977, 16048, 16284, 16305, 16348, 16387, 16519, 16637, 16641,
16954, 17080, 17318, 17409, 17435, 17491, 17550, 17587, 17872, 18021,
18248, 18272, 18395, 18541, 18569, 19100, 19170, 19331, 19383, 19529,
19571, 19581, 19594, 19630, 19635, 19714, 19970, 20272, 20317, 20432,
20689, 20798, 20896, 20936, 21327, 21357, 22049, 22076, 22108, 22125,
22181, 22185, 22262, 22327, 22411, 22514, 22531, 22553, 22774, 22824,
22929, 22995, 23026, 23069, 23146, 23193, 23194, 23411, 23430, 23515,
23561, 23616, 23680, 23898, 24104, 24200, 24235, 24287, 24358, 24417,
24483, 24678, 24758, 24764, 24824, 24926, 25202, 25257, 25576, 25598,
25816, 25910, 26015, 26277, 26479, 26787, 26857, 26941, 27140, 27216,
27282, 27528, 27554, 27725, 27974, 28087, 28136, 28228, 28441, 28491,
28618, 28628, 28733, 28758, 28793, 28896, 29143, 29150, 29279, 29617,
29632, 29854, 30086, 30364, 30371, 30868, 31034, 31139, 31421, 31502,
31538, 31968, 31989, 32220, 32264, 32363, 32393, 32490, 32576, 32671,
32741, 32867, 32874, 33115, 33503, 33970, 34192, 34258, 34366, 34418,
34550, 34648, 34667, 34738, 34829, 35184, 35279, 35314, 35510, 35645,
35684, 35708, 35725, 35768, 35895, 36227, 36247, 36307, 36361, 36456,
36586, 36638, 36656, 36716, 36856, 36907, 37088, 37217, 37321, 37374,
37397, 37448, 37481, 37572, 37769, 37911, 37925, 37973, 37988, 38020,
38108, 38134, 38248, 38429, 38615, 38814, 38827, 38877, 39080, 39167,
39218, 39593, 39932, 39946, 40143, 40303, 40339, 40405, 40592, 40719,
40791, 41101, 41194, 41206, 41358, 41455, 41470, 41560, 42374, 42597,
42718, 42728, 42800, 42826, 42902, 43085, 43130, 43203, 43301, 43448,
43556, 43604, 43606, 43656, 43781, 44029, 44043, 44129, 44203, 44273,
44323, 44412, 44590, 44619, 44659};
test_read_index_file(meta_x86_old_noavx2_v2, data_dir, "x86_noavx2_old_v2",
field_name_avx2, default_query_term,
InvertedIndexStorageFormatPB::V2, false,
expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_x86_old_noavx2_v1 =
create_test_index_meta(1744076790030, "request_idx", 2);
std::string field_name_avx2 = "request";
default_query_term = "gif";
expected_gif_cardinality = 40657;
expected_gif_doc_ids = {0, 19, 110, 1001, 2581,
7197, 9090, 16711, 10278, 44701};
test_read_index_file(meta_x86_old_noavx2_v1, data_dir, "x86_noavx2_old",
field_name_avx2, default_query_term,
InvertedIndexStorageFormatPB::V1, false,
expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 407;
expected_gif_doc_ids = {
401, 452, 511, 584, 661, 916, 1019, 1149, 1212, 1285,
1498, 1877, 1998, 2048, 2065, 2123, 2266, 2332, 2436, 2711,
2743, 2851, 2927, 2959, 3129, 3330, 3433, 3536, 3745, 3808,
3825, 4472, 4523, 4641, 4780, 4788, 4799, 5032, 5043, 5077,
5368, 5532, 5638, 5794, 5837, 6179, 6744, 6756, 7057, 7093,
7100, 7143, 7269, 7277, 7429, 7431, 7484, 7531, 8032, 8275,
8303, 8327, 8423, 8944, 9043, 9075, 9170, 9317, 9636, 9683,
9687, 9755, 10054, 10062, 10152, 10208, 10471, 10747, 10771, 10815,
10861, 10976, 11012, 11014, 11099, 11110, 11251, 11261, 11266, 11293,
11436, 11474, 11752, 11783, 11800, 11851, 11960, 12028, 12068, 12199,
12404, 12422, 12605, 12814, 12889, 13104, 13414, 13505, 13572, 13839,
14099, 14212, 14245, 14248, 14260, 14364, 14396, 14478, 14486, 14542,
14627, 14674, 14797, 14853, 14875, 14945, 14984, 15254, 15273, 15591,
15600, 15621, 15650, 15794, 15987, 16046, 16112, 16119, 16170, 16173,
16325, 16461, 16474, 16525, 16656, 16758, 16963, 17068, 17262, 17329,
17507, 17511, 17535, 17630, 17897, 17966, 18075, 18163, 18209, 18297,
18378, 18380, 18419, 18533, 18587, 18681, 18927, 19108, 19283, 19350,
19370, 19493, 19516, 19612, 19792, 20045, 20107, 20111, 20211, 20266,
20322, 20325, 20384, 20986, 21035, 21193, 21201, 21578, 21589, 21604,
21686, 21800, 21816, 21983, 22007, 22185, 22230, 22338, 22482, 22526,
22540, 22563, 22575, 22726, 22855, 23032, 23087, 23149, 23182, 23890,
24070, 24192, 24239, 24368, 24521, 24562, 24567, 24625, 24685, 24797,
24898, 24971, 25006, 25007, 25229, 25425, 25753, 25777, 25877, 25921,
26328, 26455, 26537, 26587, 26677, 26881, 27086, 27431, 27491, 27537,
27640, 27748, 27829, 27919, 28104, 28170, 28235, 28449, 28468, 28574,
28834, 28942, 29092, 29102, 29184, 29215, 29237, 29318, 29622, 29974,
30071, 30192, 30218, 30302, 30353, 30711, 30869, 31070, 31133, 31193,
31210, 31273, 31391, 31516, 31704, 31746, 31792, 31807, 32046, 32054,
32297, 32484, 32513, 32676, 33028, 33173, 33463, 33554, 33620, 33652,
33741, 33967, 34082, 34092, 34294, 34321, 34338, 34362, 34641, 35035,
35039, 35149, 35270, 35322, 35349, 35586, 35627, 35820, 35832, 35920,
36505, 36518, 36589, 36597, 36755, 36772, 36774, 36871, 37211, 37405,
37564, 37843, 37927, 37935, 38171, 38416, 38520, 38586, 38685, 38821,
38906, 38944, 39001, 39124, 39153, 39276, 39421, 39426, 39609, 39612,
39734, 39836, 39999, 40108, 40136, 40226, 40307, 40349, 40403, 40491,
40993, 41189, 41448, 41487, 41666, 41691, 41716, 41733, 41924, 42006,
42070, 42317, 42451, 42588, 42800, 42903, 42934, 43217, 43221, 43544,
43586, 43945, 44030, 44068, 44334, 44355, 44650, 44676, 44722, 44738,
44915, 45060, 45493, 45650, 45708, 45740, 45800, 46172, 46485, 46674,
46680, 46763, 46898, 47021, 47092, 47214, 47321, 47758, 47761, 47913,
48121, 48167, 48184, 48271, 48383, 48431, 48560};
test_read_index_file(meta_x86_old_noavx2_v1, data_dir, "x86_noavx2_old",
field_name_avx2, default_query_term,
InvertedIndexStorageFormatPB::V1, false,
expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_x86_new_noavx2_v2 =
create_test_index_meta(1744093412497, "request_idx", 2);
std::string field_name_avx2 = "2";
default_query_term = "gif";
expected_gif_cardinality = 37409;
expected_gif_doc_ids = {2, 19, 110, 1001, 2583,
7196, 9090, 16710, 10278, 44702};
test_read_index_file(meta_x86_new_noavx2_v2, data_dir, "x86_noavx2_new_v2",
field_name_avx2, default_query_term,
InvertedIndexStorageFormatPB::V2, false,
expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 368;
expected_gif_doc_ids = {
20, 206, 632, 742, 799, 1080, 1217, 1764, 1770, 2401,
2415, 2425, 2560, 2587, 2852, 2876, 3235, 3336, 3763, 4051,
4101, 4330, 4361, 4393, 4405, 4743, 4812, 4815, 4897, 4958,
5088, 5180, 5250, 5326, 5379, 5428, 5497, 5514, 5626, 6041,
6068, 6107, 6354, 6576, 6779, 6784, 6964, 6988, 7005, 7123,
7172, 7459, 7575, 7863, 7920, 7923, 7939, 7957, 7977, 8550,
8654, 8683, 8790, 8921, 8992, 9088, 9101, 9235, 9348, 9469,
9486, 9670, 9759, 9823, 9833, 9857, 10187, 10477, 10760, 10955,
11056, 11266, 11289, 11343, 11357, 11439, 11447, 11508, 11608, 11719,
11797, 11843, 11937, 11939, 12126, 12173, 12228, 12321, 12364, 12504,
12749, 12821, 12858, 13031, 13108, 13126, 13214, 13235, 13314, 13360,
13374, 13385, 13455, 13596, 13707, 13771, 13810, 14305, 14444, 14617,
14679, 14865, 15301, 15332, 15341, 15696, 15807, 15839, 15883, 15946,
16015, 16156, 16304, 16412, 16607, 16709, 16797, 17290, 17563, 17570,
18091, 18218, 18220, 18258, 18465, 18628, 18644, 18652, 18653, 18729,
18737, 19053, 19138, 19155, 19208, 19209, 19245, 19384, 19587, 19947,
20008, 20151, 20178, 20468, 20623, 20667, 20796, 20924, 21019, 21194,
21471, 21493, 21540, 21622, 21675, 21746, 21991, 22184, 22490, 22627,
23004, 23005, 23122, 23197, 23279, 23322, 23733, 23788, 23857, 23898,
23924, 24359, 24574, 24635, 24759, 24804, 25009, 25083, 25181, 25349,
25503, 25900, 26135, 26306, 26755, 26838, 26870, 26880, 26927, 27000,
27063, 27226, 27391, 27418, 27458, 27536, 27544, 27595, 27660, 27854,
27875, 27901, 27947, 28064, 28201, 28211, 28240, 28270, 28349, 28408,
28456, 28696, 28829, 28886, 28944, 28967, 29107, 29215, 29782, 29907,
30382, 30434, 30491, 30515, 30539, 30777, 30896, 30935, 31041, 31161,
31244, 31521, 31625, 31669, 31800, 31819, 32308, 32327, 32483, 32690,
32709, 33087, 33222, 33272, 33370, 33522, 33677, 33699, 34086, 34280,
34303, 34372, 34492, 34564, 34602, 34668, 34738, 34854, 34871, 35154,
35228, 35474, 35637, 35658, 35671, 35672, 35775, 35896, 35913, 36024,
36220, 36259, 36394, 36437, 36671, 36833, 37023, 37073, 37095, 37136,
37171, 37262, 37369, 37528, 37583, 37697, 37710, 37842, 37955, 38073,
38080, 38091, 38100, 38187, 38214, 38283, 38430, 38485, 38578, 38592,
38910, 39157, 39254, 39387, 39388, 39570, 39642, 39664, 39732, 39814,
39817, 39865, 40071, 40096, 40113, 40495, 40529, 40596, 40676, 40711,
40850, 41156, 41160, 41236, 41809, 41822, 41895, 41912, 41961, 41991,
42037, 42271, 42333, 42556, 42614, 42682, 42897, 43041, 43429, 43530,
43597, 43646, 43754, 44312, 44334, 44438, 44489, 44513};
test_read_index_file(meta_x86_new_noavx2_v2, data_dir, "x86_noavx2_new_v2",
field_name_avx2, default_query_term,
InvertedIndexStorageFormatPB::V2, true,
expected_gif_cardinality, expected_gif_doc_ids);
}
{
TabletIndex meta_x86_new_noavx2_v1 =
create_test_index_meta(1744093412581, "request_idx", 2);
std::string field_name_avx2 = "request";
default_query_term = "gif";
expected_gif_cardinality = 37272;
expected_gif_doc_ids = {0, 19, 110, 1001, 2581,
7197, 9090, 16711, 10278, 44701};
test_read_index_file(meta_x86_new_noavx2_v1, data_dir, "x86_noavx2_new",
field_name_avx2, default_query_term,
InvertedIndexStorageFormatPB::V1, false,
expected_gif_cardinality, expected_gif_doc_ids);
default_query_term = "/english/index.html";
expected_gif_cardinality = 326;
expected_gif_doc_ids = {
50, 117, 237, 623, 1102, 1172, 1358, 1612, 1725, 1932,
2074, 2233, 2395, 2618, 2871, 2977, 2985, 3305, 3375, 3385,
3518, 3713, 3761, 3810, 3879, 3917, 4059, 4081, 4114, 4121,
4292, 4306, 4509, 4565, 4566, 4700, 4711, 4831, 4832, 5024,
5029, 5184, 5324, 5432, 5618, 5753, 5803, 5844, 6558, 6594,
6876, 6901, 7273, 7429, 7498, 7504, 7624, 7681, 7842, 7883,
7971, 7983, 8349, 8530, 8597, 8632, 8687, 8807, 8847, 8865,
8886, 9303, 9315, 9319, 9428, 9509, 9601, 9799, 9909, 10101,
10177, 10203, 10228, 10553, 10666, 10693, 10780, 10814, 10824, 11046,
11118, 11265, 11409, 11463, 11611, 11730, 11767, 12041, 12096, 12119,
12294, 12475, 12496, 12634, 12759, 12987, 13181, 13276, 13373, 13566,
13830, 14001, 14383, 14425, 14613, 14846, 15002, 15039, 15072, 15817,
15950, 16092, 16109, 16334, 16442, 16531, 16635, 17023, 17030, 17661,
17726, 17856, 18208, 18210, 18261, 18414, 18420, 18582, 18645, 19045,
19101, 19374, 19535, 19728, 19740, 19815, 19861, 19938, 19955, 19991,
20512, 20908, 21066, 21097, 21403, 21524, 21789, 22177, 22298, 22402,
22422, 22769, 22836, 22874, 22985, 23005, 23018, 23027, 23291, 23361,
23413, 23500, 23513, 23588, 23609, 23851, 23959, 24228, 24383, 24445,
24468, 24636, 24817, 24888, 25070, 25459, 25618, 25640, 26178, 26459,
26583, 26970, 27070, 27131, 27147, 27479, 27606, 27616, 27696, 27780,
27871, 27960, 28094, 28306, 28442, 28516, 28609, 28843, 29042, 29488,
29512, 29686, 29891, 29932, 29956, 30094, 30319, 30357, 30478, 30527,
30914, 31035, 31530, 31586, 31659, 31696, 32134, 32178, 32273, 32713,
32932, 33273, 33334, 33338, 33461, 33481, 33552, 33727, 33852, 33982,
34104, 34235, 34253, 34308, 34816, 35126, 35147, 35246, 35293, 35329,
35402, 35482, 35535, 35940, 35986, 36034, 36075, 36125, 36170, 36313,
36340, 36683, 36823, 37002, 37351, 37458, 37537, 37552, 37808, 37943,
37952, 37954, 38166, 38461, 38624, 38756, 38807, 38847, 39096, 39147,
39358, 39592, 40015, 40170, 40201, 40230, 40409, 40542, 40593, 40608,
40687, 40825, 40894, 40903, 41234, 41278, 41380, 41488, 41522, 41555,
41559, 41593, 41678, 41742, 41765, 41792, 42054, 42248, 42319, 42623,
42660, 42886, 42925, 43338, 43552, 43593, 43594, 43766, 43782, 43881,
44229, 44263, 44324, 44537, 44601, 44661};
test_read_index_file(meta_x86_new_noavx2_v1, data_dir, "x86_noavx2_new",
field_name_avx2, default_query_term,
InvertedIndexStorageFormatPB::V1, false,
expected_gif_cardinality, expected_gif_doc_ids);
}
}
}
}
class MockStringTypeInvertedIndexReader final : public StringTypeInvertedIndexReader {
public:
static std::shared_ptr<MockStringTypeInvertedIndexReader> create_shared(
const TabletIndex* idx_meta, std::shared_ptr<IndexFileReader>& file_reader) {
return std::shared_ptr<MockStringTypeInvertedIndexReader>(
new MockStringTypeInvertedIndexReader(idx_meta, file_reader));
}
protected:
Status handle_searcher_cache(const IndexQueryContextPtr& context,
InvertedIndexCacheHandle*) override {
CLuceneError err;
err.set(CL_ERR_IO, "mock handle_searcher_cache failure");
throw err;
}
private:
MockStringTypeInvertedIndexReader(const TabletIndex* idx_meta,
std::shared_ptr<IndexFileReader>& file_reader)
: StringTypeInvertedIndexReader(idx_meta, file_reader) {}
};
// Mock class for testing tokenized index query exceptions
class MockTokenizedStringTypeInvertedIndexReader final : public FullTextIndexReader {
public:
static std::shared_ptr<MockTokenizedStringTypeInvertedIndexReader> create_shared(
const TabletIndex* idx_meta, std::shared_ptr<IndexFileReader>& file_reader) {
return std::shared_ptr<MockTokenizedStringTypeInvertedIndexReader>(
new MockTokenizedStringTypeInvertedIndexReader(idx_meta, file_reader));
}
protected:
Status handle_searcher_cache(const IndexQueryContextPtr& context,
InvertedIndexCacheHandle*) override {
CLuceneError err;
err.set(CL_ERR_IO, "mock tokenized index searcher cache failure");
throw err;
}
private:
MockTokenizedStringTypeInvertedIndexReader(const TabletIndex* idx_meta,
std::shared_ptr<IndexFileReader>& file_reader)
: FullTextIndexReader(idx_meta, file_reader) {}
};
void test_cache_error_scenarios() {
std::string_view rowset_id = "test_handle_searcher_cache_exception";
int seg_id = 0;
std::vector<Slice> values = {Slice("apple"), Slice("banana")};
TabletIndex idx_meta;
{
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_mock_cache");
index_meta_pb->add_col_unique_id(1); // c2
idx_meta.init_from_pb(*index_meta_pb);
}
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
auto file_reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
ASSERT_TRUE(file_reader->init().ok());
auto mock_reader = MockStringTypeInvertedIndexReader::create_shared(&idx_meta, file_reader);
ASSERT_NE(mock_reader, nullptr);
io::IOContext io_ctx;
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions opts;
opts.enable_inverted_index_searcher_cache = true;
runtime_state.set_query_options(opts);
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string field_name = "1"; // c2 unique_id
StringRef query_val(values[0].data, values[0].size);
Field qp_2089 =
Field::create_field<TYPE_STRING>(std::string(query_val.data, query_val.size));
Status st = mock_reader->query(context, field_name, qp_2089,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_FALSE(st.ok());
EXPECT_EQ(st.code(), ErrorCode::INVERTED_INDEX_CLUCENE_ERROR);
}
void test_tokenized_index_query_error_scenarios() {
std::string_view rowset_id = "test_tokenized_index_query_exception";
int seg_id = 0;
std::vector<Slice> values = {Slice("Hello world this is a test"),
Slice("Apache Doris is a modern analytics database"),
Slice("Inverted index provides fast text search")};
TabletIndex idx_meta;
{
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(2);
index_meta_pb->set_index_name("test_tokenized_mock_cache");
index_meta_pb->add_col_unique_id(1); // c2
// Set tokenized index properties
auto* properties = index_meta_pb->mutable_properties();
(*properties)[INVERTED_INDEX_PARSER_KEY] = INVERTED_INDEX_PARSER_ENGLISH;
(*properties)[INVERTED_INDEX_PARSER_PHRASE_SUPPORT_KEY] =
INVERTED_INDEX_PARSER_PHRASE_SUPPORT_YES;
(*properties)[INVERTED_INDEX_PARSER_LOWERCASE_KEY] = INVERTED_INDEX_PARSER_TRUE;
idx_meta.init_from_pb(*index_meta_pb);
}
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
auto file_reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
ASSERT_TRUE(file_reader->init().ok());
auto mock_reader =
MockTokenizedStringTypeInvertedIndexReader::create_shared(&idx_meta, file_reader);
ASSERT_NE(mock_reader, nullptr);
io::IOContext io_ctx;
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions opts;
opts.enable_inverted_index_searcher_cache = true;
runtime_state.set_query_options(opts);
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string field_name = "1"; // c2 unique_id
// Test tokenized query with "world" which should be found in "Hello world this is a test"
std::string query_term = "world";
StringRef query_val(query_term.data(), query_term.size());
Field qp_2151 =
Field::create_field<TYPE_STRING>(std::string(query_val.data, query_val.size));
Status st = mock_reader->query(context, field_name, qp_2151,
InvertedIndexQueryType::MATCH_ANY_QUERY, bitmap);
EXPECT_FALSE(st.ok());
EXPECT_EQ(st.code(), ErrorCode::INVERTED_INDEX_CLUCENE_ERROR);
// Test phrase query
std::string phrase_query = "Apache Doris";
StringRef phrase_query_val(phrase_query.data(), phrase_query.size());
Field qp_2161 = Field::create_field<TYPE_STRING>(
std::string(phrase_query_val.data, phrase_query_val.size));
st = mock_reader->query(context, field_name, qp_2161,
InvertedIndexQueryType::MATCH_PHRASE_QUERY, bitmap);
EXPECT_FALSE(st.ok());
EXPECT_EQ(st.code(), ErrorCode::INVERTED_INDEX_CLUCENE_ERROR);
}
// Test InvertedIndexResultBitmap operations
void test_result_bitmap_operations() {
auto bitmap1 = std::make_shared<roaring::Roaring>();
bitmap1->add(1);
bitmap1->add(2);
bitmap1->add(3);
auto null_bitmap1 = std::make_shared<roaring::Roaring>();
null_bitmap1->add(4);
null_bitmap1->add(5);
auto bitmap2 = std::make_shared<roaring::Roaring>();
bitmap2->add(2);
bitmap2->add(3);
bitmap2->add(6);
auto null_bitmap2 = std::make_shared<roaring::Roaring>();
null_bitmap2->add(5);
null_bitmap2->add(7);
InvertedIndexResultBitmap result1(bitmap1, null_bitmap1);
InvertedIndexResultBitmap result2(bitmap2, null_bitmap2);
// Test copy constructor
InvertedIndexResultBitmap result3(result1);
EXPECT_EQ(result3.get_data_bitmap()->cardinality(), 3);
EXPECT_EQ(result3.get_null_bitmap()->cardinality(), 2);
// Test move constructor
InvertedIndexResultBitmap result4(std::move(result3));
EXPECT_EQ(result4.get_data_bitmap()->cardinality(), 3);
EXPECT_EQ(result4.get_null_bitmap()->cardinality(), 2);
// Test &= operator
result1 &= result2;
EXPECT_EQ(result1.get_data_bitmap()->cardinality(), 2); // {2, 3}
// Test |= operator
InvertedIndexResultBitmap result5(bitmap1, null_bitmap1);
InvertedIndexResultBitmap result6(bitmap2, null_bitmap2);
result5 |= result6;
EXPECT_GT(result5.get_data_bitmap()->cardinality(), 2);
// Test -= operator
InvertedIndexResultBitmap result7(bitmap1, null_bitmap1);
InvertedIndexResultBitmap result8(bitmap2, null_bitmap2);
result7 -= result8;
// Test mask_out_null
result7.mask_out_null();
// Test is_empty
InvertedIndexResultBitmap empty_result;
EXPECT_TRUE(empty_result.is_empty());
EXPECT_FALSE(result1.is_empty());
}
// Test string index with various parser configurations
void test_string_index_parser_configurations() {
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
runtime_state.set_query_options(query_options);
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
std::vector<Slice> values = {Slice("Apple"), Slice("BANANA"), Slice("Cherry"),
Slice("DATE"), Slice("elderberry"), Slice("FIG"),
Slice("grape")};
// Test case-insensitive parsing
{
std::string_view rowset_id = "test_case_insensitive";
int seg_id = 0;
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_case");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(1); // c2 column
index_meta_pb->mutable_properties()->insert({"parser", "english"});
index_meta_pb->mutable_properties()->insert({"lower_case", "true"});
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
// Test case-insensitive search
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query_lower = "apple"; // lowercase
StringRef str_ref(query_lower.c_str(), query_lower.length());
Field qp_2274 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto status = str_reader->query(context, "c2", qp_2274,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
EXPECT_GT(bitmap->cardinality(), 0) << "Should find 'Apple' with lowercase query";
}
// Test ignore_above functionality
{
std::string_view rowset_id = "test_ignore_above";
int seg_id = 1;
std::vector<Slice> long_values = {
Slice("short"),
Slice("this_is_a_very_long_string_that_exceeds_ignore_above_limit")};
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_ignore_above");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(1);
index_meta_pb->mutable_properties()->insert({"ignore_above", "10"});
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, long_values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
// Query with long string should trigger evaluate skipped
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string long_query = "this_is_a_very_long_string_that_exceeds_ignore_above_limit";
StringRef str_ref(long_query.c_str(), long_query.length());
Field qp_2314 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto status = str_reader->query(context, "c2", qp_2314,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.code(), ErrorCode::INVERTED_INDEX_EVALUATE_SKIPPED);
}
}
// Test fulltext index with comprehensive query types
void test_fulltext_comprehensive_queries() {
std::string_view rowset_id = "test_fulltext_comprehensive";
int seg_id = 0;
std::vector<Slice> values = {Slice("the quick brown fox jumps over the lazy dog"),
Slice("apache doris is a fast analytical database"),
Slice("inverted index provides fast text search capabilities"),
Slice("lucene clucene search engine implementation"),
Slice("phrase query matches exact word sequences"),
Slice("regular expression pattern matching"),
Slice("boolean queries combine multiple terms")};
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_fulltext_comprehensive");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(1); // c2 column
index_meta_pb->mutable_properties()->insert({"parser", "english"});
index_meta_pb->mutable_properties()->insert({"lower_case", "true"});
index_meta_pb->mutable_properties()->insert({"support_phrase", "true"});
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
query_options.inverted_index_max_expansions = 50;
runtime_state.set_query_options(query_options);
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto fulltext_reader = FullTextIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(fulltext_reader, nullptr);
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
// Test MATCH_ANY_QUERY
{
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query = "quick database";
StringRef query_ref(query.c_str(), query.length());
Field qp_2376 =
Field::create_field<TYPE_STRING>(std::string(query_ref.data, query_ref.size));
auto status = fulltext_reader->query(context, "c2", qp_2376,
InvertedIndexQueryType::MATCH_ANY_QUERY, bitmap);
EXPECT_TRUE(status.ok());
EXPECT_GT(bitmap->cardinality(), 0)
<< "Should find documents with 'quick' or 'database'";
}
// Test MATCH_ALL_QUERY
{
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query = "search fast";
StringRef query_ref(query.c_str(), query.length());
Field qp_2389 =
Field::create_field<TYPE_STRING>(std::string(query_ref.data, query_ref.size));
auto status = fulltext_reader->query(context, "c2", qp_2389,
InvertedIndexQueryType::MATCH_ALL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
// Test MATCH_PHRASE_QUERY
{
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query = "quick brown";
StringRef query_ref(query.c_str(), query.length());
Field qp =
Field::create_field<TYPE_STRING>(std::string(query_ref.data, query_ref.size));
auto status = fulltext_reader->query(
context, "c2", qp, InvertedIndexQueryType::MATCH_PHRASE_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
// Test MATCH_PHRASE_PREFIX_QUERY
{
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query = "sear";
StringRef query_ref(query.c_str(), query.length());
Field qp_2411 =
Field::create_field<TYPE_STRING>(std::string(query_ref.data, query_ref.size));
auto status = fulltext_reader->query(context, "c2", qp_2411,
InvertedIndexQueryType::MATCH_PHRASE_PREFIX_QUERY,
bitmap);
EXPECT_TRUE(status.ok());
}
// Test MATCH_REGEXP_QUERY
{
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query = "qu.*k";
StringRef query_ref(query.c_str(), query.length());
Field qp =
Field::create_field<TYPE_STRING>(std::string(query_ref.data, query_ref.size));
auto status = fulltext_reader->query(
context, "c2", qp, InvertedIndexQueryType::MATCH_REGEXP_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
}
// Test iterator comprehensive functionality
void test_iterator_comprehensive() {
std::string_view rowset_id = "test_iterator_comprehensive";
int seg_id = 0;
std::vector<Slice> values = {Slice("test1"), Slice("test2"), Slice("test3")};
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_iterator_comprehensive");
index_meta_pb->add_col_unique_id(1);
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.inverted_index_skip_threshold = 10; // 10% threshold
runtime_state.set_query_options(query_options);
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
// Test iterator creation
std::unique_ptr<IndexIterator> iterator;
auto status = str_reader->new_iterator(&iterator);
EXPECT_TRUE(status.ok());
EXPECT_NE(iterator, nullptr);
// Test iterator properties
auto inverted_index_reader = std::static_pointer_cast<InvertedIndexReader>(
iterator->get_reader(InvertedIndexReaderType::STRING_TYPE));
EXPECT_EQ(inverted_index_reader->type(), InvertedIndexReaderType::STRING_TYPE);
EXPECT_FALSE(inverted_index_reader->get_index_properties().empty());
EXPECT_TRUE(inverted_index_reader->has_null());
// Test skip_try parameter
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
StringRef str_ref("test1", 5);
InvertedIndexParam param;
param.column_name = "c2";
param.query_value =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
param.query_type = InvertedIndexQueryType::EQUAL_QUERY;
param.num_rows = 3;
param.roaring = bitmap;
param.skip_try = true;
status = iterator->read_from_index(&param);
EXPECT_TRUE(status.ok());
EXPECT_EQ(bitmap->cardinality(), 1);
// Test try_read functionality with non-BKD index (should succeed)
size_t count = 0;
auto* inverted_index_iterator = static_cast<InvertedIndexIterator*>(iterator.get());
inverted_index_iterator->set_context(context);
Field try_qp = Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
status = inverted_index_iterator->try_read_from_inverted_index(
std::static_pointer_cast<InvertedIndexReader>(inverted_index_reader), "c2", try_qp,
InvertedIndexQueryType::EQUAL_QUERY, &count);
EXPECT_TRUE(status.ok());
}
// Test error handling and edge cases
void test_error_handling() {
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
runtime_state.set_query_options(query_options);
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
// Test with invalid file path
{
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_invalid");
index_meta_pb->add_col_unique_id(0);
idx_meta.init_from_pb(*index_meta_pb.get());
std::string invalid_path = kTestDir + "/nonexistent_index";
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), invalid_path, InvertedIndexStorageFormatPB::V2);
auto status = reader->init();
EXPECT_FALSE(status.ok()) << "Should fail with nonexistent file";
}
// Test string index range query with TooManyClauses error
{
std::string_view rowset_id = "test_too_many_clauses";
int seg_id = 0;
std::vector<Slice> values;
std::vector<std::string> values_string;
// Create many values to potentially trigger TooManyClauses
for (int i = 0; i < 1000; ++i) {
values_string.emplace_back(std::to_string(i));
}
std::transform(values_string.begin(), values_string.end(), std::back_inserter(values),
[](const std::string& s) { return Slice(s.c_str(), s.size()); });
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_too_many_clauses");
index_meta_pb->add_col_unique_id(1);
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
// Test range query that might exceed clause limit
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query = "500";
StringRef str_ref(query.c_str(), query.length());
Field qp_2571 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto status = str_reader->query(context, "c2", qp_2571,
InvertedIndexQueryType::LESS_THAN_QUERY, bitmap);
// This might succeed or fail depending on the implementation limits
// The important thing is we handle the potential TooManyClauses error gracefully
}
// Test empty query terms
{
std::string_view rowset_id = "test_empty_terms";
int seg_id = 0;
std::vector<Slice> values = {Slice("test")};
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_empty_terms");
index_meta_pb->add_col_unique_id(1);
index_meta_pb->mutable_properties()->insert({"parser", "english"});
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto fulltext_reader = FullTextIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(fulltext_reader, nullptr);
// Test with empty string that produces no terms
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string empty_query = "";
StringRef str_ref(empty_query.c_str(), empty_query.length());
Field qp_2608 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto status = fulltext_reader->query(context, "c2", qp_2608,
InvertedIndexQueryType::MATCH_ANY_QUERY, bitmap);
// Should either succeed with empty result or fail gracefully
}
}
// Helper methods for new data types
void prepare_bkd_index_double(std::string_view rowset_id, int seg_id,
std::vector<double>& values, TabletIndex* idx_meta,
std::string* index_path_prefix) {
auto tablet_schema = create_schema();
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_double");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(0); // c1 column
idx_meta->init_from_pb(*index_meta_pb.get());
*index_path_prefix = InvertedIndexDescriptor::get_index_file_path_prefix(
local_segment_path(kTestDir, rowset_id, seg_id));
std::string index_path =
InvertedIndexDescriptor::get_index_file_path_v2(*index_path_prefix);
io::FileWriterPtr file_writer;
io::FileWriterOptions opts;
auto fs = io::global_local_filesystem();
Status sts = fs->create_file(index_path, &file_writer, &opts);
ASSERT_TRUE(sts.ok()) << sts;
auto index_file_writer = std::make_unique<IndexFileWriter>(
fs, *index_path_prefix, std::string {rowset_id}, seg_id,
InvertedIndexStorageFormatPB::V2, std::move(file_writer));
// Create a temporary schema with DOUBLE column for this test
TabletSchemaSPtr double_schema = std::make_shared<TabletSchema>();
TabletSchemaPB double_schema_pb;
double_schema_pb.set_keys_type(DUP_KEYS);
double_schema->init_from_pb(double_schema_pb);
TabletColumn double_column;
double_column.set_name("c1");
double_column.set_unique_id(0);
double_column.set_type(FieldType::OLAP_FIELD_TYPE_DOUBLE);
double_column.set_length(8);
double_column.set_index_length(8);
double_column.set_is_key(true);
double_column.set_is_nullable(true);
double_schema->append_column(double_column);
const TabletColumn& column = double_schema->column(0);
const TabletColumn* field = &(column);
ASSERT_NE(field, nullptr);
std::unique_ptr<IndexColumnWriter> column_writer;
auto status =
IndexColumnWriter::create(field, &column_writer, index_file_writer.get(), idx_meta);
EXPECT_TRUE(status.ok()) << status;
for (const auto& value : values) {
// Copy into a real element first: for std::vector<bool>, `value` is a
// proxy, so `auto`/`&value` would give a __bit_reference/__bit_iterator
// rather than a real pointer. Use the container's value_type.
typename std::decay_t<decltype(values)>::value_type v = value;
status = column_writer->add_values(column.name(), reinterpret_cast<const void*>(&v), 1);
EXPECT_TRUE(status.ok()) << status;
}
status = column_writer->finish();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->begin_close();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->finish_close();
EXPECT_TRUE(status.ok()) << status;
}
// Test error handling comprehensive
void test_error_handling_comprehensive() {
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
runtime_state.set_query_options(query_options);
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
// Test with invalid file path
{
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_invalid");
index_meta_pb->add_col_unique_id(0);
idx_meta.init_from_pb(*index_meta_pb.get());
std::string invalid_path = kTestDir + "/nonexistent_index";
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), invalid_path, InvertedIndexStorageFormatPB::V2);
auto status = reader->init();
EXPECT_FALSE(status.ok()) << "Should fail with nonexistent file";
}
// Test string index range query with TooManyClauses error
{
std::string_view rowset_id = "test_too_many_clauses";
int seg_id = 0;
std::vector<std::string> values_string;
std::vector<Slice> values;
// Create many values to potentially trigger TooManyClauses
for (int i = 0; i < 1000; ++i) {
values_string.emplace_back(std::to_string(i));
}
std::transform(values_string.begin(), values_string.end(), std::back_inserter(values),
[](const std::string& s) { return Slice(s.c_str(), s.size()); });
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_too_many_clauses");
index_meta_pb->add_col_unique_id(1);
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
// Test range query that might exceed clause limit
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query = "500";
StringRef str_ref(query.c_str(), query.length());
Field qp_2750 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto status = str_reader->query(context, "c2", qp_2750,
InvertedIndexQueryType::LESS_THAN_QUERY, bitmap);
// This might succeed or fail depending on the implementation limits
// The important thing is we handle the potential TooManyClauses error gracefully
}
// Test empty query terms
{
std::string_view rowset_id = "test_empty_terms";
int seg_id = 0;
std::vector<Slice> values = {Slice("test")};
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_empty_terms");
index_meta_pb->add_col_unique_id(1);
index_meta_pb->mutable_properties()->insert({"parser", "english"});
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto fulltext_reader = FullTextIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(fulltext_reader, nullptr);
// Test with empty string that produces no terms
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string empty_query;
StringRef str_ref(empty_query.c_str(), empty_query.length());
Field qp_2787 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto status = fulltext_reader->query(context, "c2", qp_2787,
InvertedIndexQueryType::MATCH_ANY_QUERY, bitmap);
// Should either succeed with empty result or fail gracefully
}
}
// Test specific error paths and edge cases based on uncovered lines
void test_uncovered_error_paths() {
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
runtime_state.set_query_options(query_options);
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
// Test MATCH_REGEXP_QUERY path that was uncovered
{
std::string_view rowset_id = "test_regexp_query";
int seg_id = 0;
std::vector<Slice> values = {Slice("test123"), Slice("example456"), Slice("demo789")};
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_regexp");
index_meta_pb->add_col_unique_id(1);
index_meta_pb->mutable_properties()->insert({"parser", "english"});
index_meta_pb->mutable_properties()->insert({"support_phrase", "true"});
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto fulltext_reader = FullTextIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(fulltext_reader, nullptr);
// Test MATCH_REGEXP_QUERY specifically
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string regexp_query = "test.*";
StringRef query_ref(regexp_query.c_str(), regexp_query.length());
Field qp =
Field::create_field<TYPE_STRING>(std::string(query_ref.data, query_ref.size));
auto status = fulltext_reader->query(
context, "c2", qp, InvertedIndexQueryType::MATCH_REGEXP_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
// Test StringType range queries that were uncovered
{
std::string_view rowset_id = "test_string_range";
int seg_id = 0;
std::vector<Slice> values = {Slice("apple"), Slice("banana"), Slice("cherry"),
Slice("date")};
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_string_range");
index_meta_pb->add_col_unique_id(1);
idx_meta.init_from_pb(*index_meta_pb.get());
std::string index_path_prefix;
prepare_string_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto str_reader = StringTypeInvertedIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(str_reader, nullptr);
// Test LESS_THAN_QUERY
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
std::string query = "cherry";
StringRef str_ref(query.c_str(), query.length());
Field qp_2874 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
auto status = str_reader->query(context, "c2", qp_2874,
InvertedIndexQueryType::LESS_THAN_QUERY, bitmap);
EXPECT_TRUE(status.ok());
// Test LESS_EQUAL_QUERY
bitmap = std::make_shared<roaring::Roaring>();
Field qp_2880 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
status = str_reader->query(context, "c2", qp_2880,
InvertedIndexQueryType::LESS_EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
// Test GREATER_THAN_QUERY
bitmap = std::make_shared<roaring::Roaring>();
Field qp_2886 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
status = str_reader->query(context, "c2", qp_2886,
InvertedIndexQueryType::GREATER_THAN_QUERY, bitmap);
EXPECT_TRUE(status.ok());
// Test GREATER_EQUAL_QUERY
bitmap = std::make_shared<roaring::Roaring>();
Field qp_2892 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
status = str_reader->query(context, "c2", qp_2892,
InvertedIndexQueryType::GREATER_EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
// Test MATCH_PHRASE_QUERY for StringType
bitmap = std::make_shared<roaring::Roaring>();
Field qp_2898 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
status = str_reader->query(context, "c2", qp_2898,
InvertedIndexQueryType::MATCH_PHRASE_QUERY, bitmap);
EXPECT_TRUE(status.ok());
// Test MATCH_PHRASE_PREFIX_QUERY for StringType
bitmap = std::make_shared<roaring::Roaring>();
Field qp_2904 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
status = str_reader->query(context, "c2", qp_2904,
InvertedIndexQueryType::MATCH_PHRASE_PREFIX_QUERY, bitmap);
EXPECT_TRUE(status.ok());
// Test MATCH_REGEXP_QUERY for StringType
bitmap = std::make_shared<roaring::Roaring>();
Field qp_2910 =
Field::create_field<TYPE_STRING>(std::string(str_ref.data, str_ref.size));
status = str_reader->query(context, "c2", qp_2910,
InvertedIndexQueryType::MATCH_REGEXP_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
}
// Generic BKD range-query verifier. Writes `values` into the BKD index
// for `column_name`, then runs EQUAL / LESS_THAN / LESS_EQUAL /
// GREATER_THAN / GREATER_EQUAL queries against `threshold`. Expected
// cardinalities are derived from the input `values` + `threshold` via
// std::count_if, so the caller doesn't have to keep them in sync.
//
// Locks in:
// * the typed-param interface (TypedInvertedIndexQueryParam<PT>)
// * the +/-infinity sentinels routed through type_limit<compute_t> +
// PrimitiveTypeConvertor<PT>
// * BKD's writer/reader/visitor agreement on KeyCoder-encoded bytes
template <PrimitiveType PT, typename T>
void verify_bkd_range_queries(int col_id, std::string_view rowset_id,
const std::string& column_name, std::vector<T> values,
T threshold) {
OlapReaderStatistics stats;
RuntimeState runtime_state;
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, /*seg_id=*/0, col_id, values, &idx_meta,
&index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
auto run_query = [&](InvertedIndexQueryType qt, T thr) {
using raw_t = typename PrimitiveTypeTraits<PT>::StorageFieldType;
Field qp = Field::create_field_from_olap_value<PT>(static_cast<raw_t>(thr));
auto bitmap = std::make_shared<roaring::Roaring>();
auto status = bkd_reader->query(context, column_name, qp, qt, bitmap);
EXPECT_TRUE(status.ok()) << column_name << ": " << status;
return bitmap->cardinality();
};
const auto expect_eq = std::count_if(values.begin(), values.end(),
[&](const T& v) { return v == threshold; });
const auto expect_lt = std::count_if(values.begin(), values.end(),
[&](const T& v) { return v < threshold; });
const auto expect_le = std::count_if(values.begin(), values.end(),
[&](const T& v) { return v <= threshold; });
const auto expect_gt = std::count_if(values.begin(), values.end(),
[&](const T& v) { return v > threshold; });
const auto expect_ge = std::count_if(values.begin(), values.end(),
[&](const T& v) { return v >= threshold; });
EXPECT_EQ(run_query(InvertedIndexQueryType::EQUAL_QUERY, threshold), expect_eq)
<< column_name << " EQUAL";
EXPECT_EQ(run_query(InvertedIndexQueryType::LESS_THAN_QUERY, threshold), expect_lt)
<< column_name << " LESS_THAN (relies on encode_min sentinel)";
EXPECT_EQ(run_query(InvertedIndexQueryType::LESS_EQUAL_QUERY, threshold), expect_le)
<< column_name << " LESS_EQUAL (relies on encode_min sentinel)";
EXPECT_EQ(run_query(InvertedIndexQueryType::GREATER_THAN_QUERY, threshold), expect_gt)
<< column_name << " GREATER_THAN (relies on encode_max sentinel)";
EXPECT_EQ(run_query(InvertedIndexQueryType::GREATER_EQUAL_QUERY, threshold), expect_ge)
<< column_name << " GREATER_EQUAL (relies on encode_max sentinel)";
}
// Per-type wrappers. col_id values match create_comprehensive_schema()
// (commented-out c_double/c_float shift later indices, hence date=4,
// datetime=5, decimal=6, bool=7, tinyint=8, smallint=9, largeint=10,
// datev2=12, datetimev2=13, timestamptz=14).
void test_bkd_range_int() {
// INT32 row counts: -1000 (loss), 0 (balance), 42, 100, 200, 300.
verify_bkd_range_queries<TYPE_INT, int32_t>(
/*col_id=*/0, "bkd_range_int", "c_int", {-1000, 0, 42, 100, 200, 300},
/*threshold=*/100);
}
void test_bkd_range_bigint() {
// INT64 nanosecond timestamps (relative epoch deltas).
verify_bkd_range_queries<TYPE_BIGINT, int64_t>(
/*col_id=*/1, "bkd_range_bigint", "c_bigint",
{-1'000'000LL, 0LL, 1'500LL, 1'000'000LL, 1'000'000'000LL, 100'000'000'000LL},
/*threshold=*/1'000'000LL);
}
void test_bkd_range_smallint() {
// INT16 range: -32768..32767, e.g. signed short port deltas.
verify_bkd_range_queries<TYPE_SMALLINT, int16_t>(
/*col_id=*/9, "bkd_range_smallint", "c_smallint",
{int16_t(-32768), int16_t(-1024), int16_t(-1), int16_t(0), int16_t(8080),
int16_t(32767)},
/*threshold=*/int16_t(0));
}
void test_bkd_range_tinyint() {
// INT8 range: -128..127, e.g. log-level / tinyint flags.
verify_bkd_range_queries<TYPE_TINYINT, int8_t>(
/*col_id=*/8, "bkd_range_tinyint", "c_tinyint",
{int8_t(-128), int8_t(-10), int8_t(-1), int8_t(0), int8_t(50), int8_t(127)},
/*threshold=*/int8_t(0));
}
void test_bkd_range_largeint() {
// INT128. Spans negative through ~10^12 to exercise the high half.
verify_bkd_range_queries<TYPE_LARGEINT, __int128_t>(
/*col_id=*/10, "bkd_range_largeint", "c_largeint",
{static_cast<__int128_t>(-1'000'000), static_cast<__int128_t>(-1),
static_cast<__int128_t>(0), static_cast<__int128_t>(1),
static_cast<__int128_t>(1'000'000), static_cast<__int128_t>(1'000'000'000'000LL)},
/*threshold=*/static_cast<__int128_t>(0));
}
void test_bkd_range_decimalv2() {
// Real DecimalV2 (DECIMAL(27,9)) literals: -100.0, 0.0, 42.5, 100.0, 200.0, 300.0
// (decimal12_t.fraction is scaled by 10^9).
verify_bkd_range_queries<TYPE_DECIMALV2, decimal12_t>(
/*col_id=*/6, "bkd_range_decimalv2", "c_decimal",
{decimal12_t {-100, 0}, decimal12_t {0, 0}, decimal12_t {42, 500'000'000},
decimal12_t {100, 0}, decimal12_t {200, 0}, decimal12_t {300, 0}},
/*threshold=*/decimal12_t {100, 0});
}
void test_bkd_range_date() {
// DATE in OLAP packed format `(year << 9) | (month << 5) | day`:
// 2020-01-01, 2021-06-15, 2023-03-10, 2024-12-31, 2026-08-08, 2030-01-01
auto pack_date = [](int y, int m, int d) -> uint24_t {
return uint24_t(static_cast<uint32_t>((y << 9) | (m << 5) | d));
};
verify_bkd_range_queries<TYPE_DATE, uint24_t>(
/*col_id=*/4, "bkd_range_date", "c_date",
{pack_date(2020, 1, 1), pack_date(2021, 6, 15), pack_date(2023, 3, 10),
pack_date(2024, 12, 31), pack_date(2026, 8, 8), pack_date(2030, 1, 1)},
/*threshold=*/pack_date(2024, 12, 31));
}
void test_bkd_range_datetime() {
// OLAP DATETIME packs as decimal YYYYMMDDhhmmss (see VecDateTimeValue::
// to_olap_datetime). TypedInvertedIndexQueryParam<TYPE_DATETIME>::storage_val
// is int64_t (conditional_t override) to line up with KeyCoder<DATETIME>'s
// signed view.
auto dt = [](int y, int mo, int d, int h, int mi, int s) -> int64_t {
return static_cast<int64_t>((static_cast<uint64_t>(y) * 10000 + mo * 100 + d) *
1000000ULL +
static_cast<uint64_t>(h) * 10000 + mi * 100 + s);
};
verify_bkd_range_queries<TYPE_DATETIME, int64_t>(
/*col_id=*/5, "bkd_range_datetime", "c_datetime",
{dt(2020, 1, 1, 12, 0, 0), dt(2021, 1, 1, 12, 0, 0), dt(2022, 6, 15, 15, 0, 0),
dt(2024, 3, 10, 9, 30, 0), dt(2025, 12, 25, 0, 0, 0), dt(2030, 1, 1, 12, 0, 0)},
/*threshold=*/dt(2024, 3, 10, 9, 30, 0));
}
void test_bkd_range_datev2() {
// DateV2 packed format: bits [0..4]=day, [5..8]=month, [9..23]=year.
auto pack_datev2 = [](int y, int m, int d) -> uint32_t {
return static_cast<uint32_t>((y << 9) | (m << 5) | d);
};
verify_bkd_range_queries<TYPE_DATEV2, uint32_t>(
/*col_id=*/12, "bkd_range_datev2", "c_datev2",
{pack_datev2(2020, 1, 1), pack_datev2(2021, 6, 15), pack_datev2(2023, 3, 10),
pack_datev2(2024, 12, 31), pack_datev2(2026, 8, 8), pack_datev2(2030, 1, 1)},
/*threshold=*/pack_datev2(2024, 12, 31));
}
// DateTimeV2 / TimestampTz packing per vdatetime_value.h:
// [date_v2 << 37] | [hour << 32] | [minute << 26] | [second << 20] | microsecond
// date_v2 = (year << 9) | (month << 5) | day
static uint64_t pack_dtv2(int y, int mo, int d, int h, int mi, int s, int us = 0) {
uint64_t date = (static_cast<uint64_t>(y) << 9) | (static_cast<uint64_t>(mo) << 5) | d;
return (date << 37) | (static_cast<uint64_t>(h) << 32) | (static_cast<uint64_t>(mi) << 26) |
(static_cast<uint64_t>(s) << 20) | us;
}
void test_bkd_range_datetimev2() {
verify_bkd_range_queries<TYPE_DATETIMEV2, uint64_t>(
/*col_id=*/13, "bkd_range_datetimev2", "c_datetimev2",
{pack_dtv2(2020, 1, 1, 12, 0, 0), pack_dtv2(2021, 6, 15, 15, 0, 0),
pack_dtv2(2023, 3, 10, 9, 30, 0), pack_dtv2(2024, 12, 31, 23, 59, 59),
pack_dtv2(2026, 8, 8, 8, 8, 8), pack_dtv2(2030, 1, 1, 12, 0, 0)},
/*threshold=*/pack_dtv2(2024, 12, 31, 23, 59, 59));
}
void test_bkd_range_timestamptz() {
// TimestampTzValue storage = uint64_t with the same DateTimeV2 packing
// (the TZ offset lives outside the BKD-indexed key).
verify_bkd_range_queries<TYPE_TIMESTAMPTZ, uint64_t>(
/*col_id=*/14, "bkd_range_timestamptz", "c_timestamptz",
{pack_dtv2(2020, 1, 1, 12, 0, 0), pack_dtv2(2021, 6, 15, 15, 0, 0),
pack_dtv2(2023, 3, 10, 9, 30, 0), pack_dtv2(2024, 12, 31, 23, 59, 59),
pack_dtv2(2026, 8, 8, 8, 8, 8), pack_dtv2(2030, 1, 1, 12, 0, 0)},
/*threshold=*/pack_dtv2(2024, 12, 31, 23, 59, 59));
}
void test_bkd_range_bool() {
// Storage = uint8_t. With duplicates {false,false,false,true,true,true}
// threshold=false means LT=0 / LE=3 / GT=3 / GE=6.
verify_bkd_range_queries<TYPE_BOOLEAN, uint8_t>(
/*col_id=*/7, "bkd_range_bool", "c_bool",
{uint8_t(0), uint8_t(0), uint8_t(0), uint8_t(1), uint8_t(1), uint8_t(1)},
/*threshold=*/uint8_t(0));
}
void test_bkd_range_float() {
// FLOAT real values: ~-100.5 (negative offset), -1.25, 0.0, π
// approximated, 100.25, 1234.5 (mid-positive).
verify_bkd_range_queries<TYPE_FLOAT, float>(
/*col_id=*/15, "bkd_range_float", "c_float",
{-100.5f, -1.25f, 0.0f, 3.14159f, 100.25f, 1234.5f},
/*threshold=*/3.14159f);
}
void test_bkd_range_double() {
// DOUBLE real values across magnitudes from -1e10 to +1e10, including
// negative scientific, π, and large positive.
verify_bkd_range_queries<TYPE_DOUBLE, double>(
/*col_id=*/16, "bkd_range_double", "c_double",
{-9.87654321e10, -1.5, 0.0, 3.14159265358979, 1.0e6, 1.0e10},
/*threshold=*/3.14159265358979);
}
void test_bkd_range_decimal32() {
// DECIMAL(9, 2). Storage = real_value × 10^2.
auto d = [](double v) { return static_cast<int32_t>(std::llround(v * 100)); };
verify_bkd_range_queries<TYPE_DECIMAL32, int32_t>(
/*col_id=*/17, "bkd_range_decimal32", "c_decimal32",
{d(-1.00), d(-0.01), d(0.00), d(1.23), d(9999.99), d(999999.99)},
/*threshold=*/d(1.23));
}
void test_bkd_range_decimal64() {
// DECIMAL(18, 4). Storage = real_value × 10^4.
auto d = [](double v) { return static_cast<int64_t>(std::llround(v * 10000)); };
verify_bkd_range_queries<TYPE_DECIMAL64, int64_t>(
/*col_id=*/18, "bkd_range_decimal64", "c_decimal64",
{d(-100.0), d(0.0), d(0.0123), d(12345.6789), d(99999999.9999), d(9999999999.9999)},
/*threshold=*/d(12345.6789));
}
void test_bkd_range_decimal128i() {
// DECIMAL(38, 10) stored as Int128. Values:
// -100.0000000000, -0.0000000001, 0, 1.2345678900,
// 12345.6789012345, 1e30 (ledger-scale).
verify_bkd_range_queries<TYPE_DECIMAL128I, __int128_t>(
/*col_id=*/19, "bkd_range_decimal128i", "c_decimal128i",
{static_cast<__int128_t>(-1'000'000'000'000LL), static_cast<__int128_t>(-1),
static_cast<__int128_t>(0), static_cast<__int128_t>(12'345'678'900LL),
static_cast<__int128_t>(123'456'789'012'345LL),
static_cast<__int128_t>(1'000'000'000'000'000LL) *
static_cast<__int128_t>(1'000'000'000'000'000LL)},
/*threshold=*/static_cast<__int128_t>(12'345'678'900LL));
}
void test_bkd_range_decimal256() {
// DECIMAL(76, 20) stored as wide::Int256. Use scaled integers spanning
// a representative range from -1e6 up to 10^18.
verify_bkd_range_queries<TYPE_DECIMAL256, wide::Int256>(
/*col_id=*/20, "bkd_range_decimal256", "c_decimal256",
{wide::Int256(-1'000'000), wide::Int256(-1), wide::Int256(0),
wide::Int256(123'456'789), wide::Int256(123'456'789'012'345LL),
wide::Int256(1'000'000'000'000'000'000LL)},
/*threshold=*/wide::Int256(123'456'789));
}
void test_bkd_range_ipv4() {
// Real IPv4 addresses. uint32_t encoding = (a<<24)|(b<<16)|(c<<8)|d:
// 0.0.0.1, 10.0.0.1, 127.0.0.1, 192.168.0.1, 192.168.0.254, 255.255.255.254
verify_bkd_range_queries<TYPE_IPV4, uint32_t>(
/*col_id=*/21, "bkd_range_ipv4", "c_ipv4",
{0x00000001U, 0x0A000001U, 0x7F000001U, 0xC0A80001U, 0xC0A800FEU, 0xFFFFFFFEU},
/*threshold=*/0xC0A80001U); // 192.168.0.1
}
void test_bkd_range_ipv6() {
// Real IPv6 addresses (uint128_t = 16-byte big-endian view):
// ::1 (loopback)
// ::ffff:7f00:0001 (IPv4-mapped 127.0.0.1)
// 2001:db8::1 (documentation prefix)
// 2001:db8:1::1
// fe80::1 (link-local)
// ffff:ffff:: (last valid)
auto ipv6 = [](uint64_t hi, uint64_t lo) -> uint128_t {
return (static_cast<uint128_t>(hi) << 64) | lo;
};
verify_bkd_range_queries<TYPE_IPV6, uint128_t>(
/*col_id=*/22, "bkd_range_ipv6", "c_ipv6",
{ipv6(0, 1), ipv6(0, 0x0000FFFF7F000001ULL), ipv6(0x20010DB800000000ULL, 1),
ipv6(0x20010DB800010000ULL, 1), ipv6(0xFE80000000000000ULL, 1),
ipv6(0xFFFFFFFF00000000ULL, 0)},
/*threshold=*/ipv6(0x20010DB800000000ULL, 1)); // 2001:db8::1
}
// Test BKD specific uncovered paths
void test_bkd_uncovered_paths() {
std::string_view rowset_id = "test_bkd_uncovered";
int seg_id = 0;
std::vector<int32_t> values = {1, 5, 10, 15, 20, 25, 30};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
runtime_state.set_query_options(query_options);
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
// Test all BKD query types systematically to cover visitor paths
std::vector<std::pair<InvertedIndexQueryType, int32_t>> test_cases = {
{InvertedIndexQueryType::LESS_THAN_QUERY, 15},
{InvertedIndexQueryType::LESS_EQUAL_QUERY, 15},
{InvertedIndexQueryType::GREATER_THAN_QUERY, 15},
{InvertedIndexQueryType::GREATER_EQUAL_QUERY, 15},
{InvertedIndexQueryType::EQUAL_QUERY, 15}};
for (auto& test_case : test_cases) {
// Test try_query path
size_t count = 0;
Field qp_2956 = Field::create_field<TYPE_INT>(test_case.second);
auto status = bkd_reader->try_query(context, "c1", qp_2956, test_case.first, &count);
EXPECT_TRUE(status.ok()) << "Try query type: " << static_cast<int>(test_case.first);
// Test actual query path
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_2962 = Field::create_field<TYPE_INT>(test_case.second);
status = bkd_reader->query(context, "c1", qp_2962, test_case.first, bitmap);
EXPECT_TRUE(status.ok()) << "Query type: " << static_cast<int>(test_case.first);
}
// Test boundary values to exercise different visitor logic paths
int32_t min_value = 0; // Less than minimum in data
int32_t max_value = 100; // Greater than maximum in data
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_2971 = Field::create_field<TYPE_INT>(min_value);
auto status = bkd_reader->query(context, "c1", qp_2971,
InvertedIndexQueryType::GREATER_THAN_QUERY, bitmap);
EXPECT_TRUE(status.ok());
bitmap = std::make_shared<roaring::Roaring>();
Field qp_2976 = Field::create_field<TYPE_INT>(max_value);
status = bkd_reader->query(context, "c1", qp_2976, InvertedIndexQueryType::LESS_THAN_QUERY,
bitmap);
EXPECT_TRUE(status.ok());
}
// Test InvertedIndexIterator uncovered paths
void test_iterator_uncovered_paths() {
std::string_view rowset_id = "test_iterator_uncovered";
int seg_id = 0;
std::vector<int32_t> values = {1, 2, 3, 4, 5};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index(rowset_id, seg_id, values, &idx_meta, &index_path_prefix);
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
query_options.inverted_index_skip_threshold = 1; // Very low threshold to trigger bypass
runtime_state.set_query_options(query_options);
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix, InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
std::unique_ptr<IndexIterator> iterator;
auto status = bkd_reader->new_iterator(&iterator);
EXPECT_TRUE(status.ok());
EXPECT_NE(iterator, nullptr);
auto* inverted_index_iterator = static_cast<InvertedIndexIterator*>(iterator.get());
inverted_index_iterator->set_context(context);
// Test the bypass path in read_from_inverted_index
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
int32_t query_value = 3;
// This should trigger the bypass logic due to low threshold
InvertedIndexParam param;
param.column_name = "c1";
param.query_value = Field::create_field<TYPE_INT>(query_value);
param.query_type = InvertedIndexQueryType::LESS_THAN_QUERY;
param.num_rows = 5;
param.roaring = bitmap;
param.skip_try = false;
status = inverted_index_iterator->read_from_index(&param);
// Expect bypass error due to threshold
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.code(), ErrorCode::INVERTED_INDEX_BYPASS);
// Test skip_try=true path
bitmap = std::make_shared<roaring::Roaring>();
InvertedIndexParam param1;
param1.column_name = "c1";
param1.query_value = Field::create_field<TYPE_INT>(query_value);
param1.query_type = InvertedIndexQueryType::EQUAL_QUERY;
param1.num_rows = 5;
param1.roaring = bitmap;
param1.skip_try = true;
status = inverted_index_iterator->read_from_index(&param1);
EXPECT_TRUE(status.ok());
// Test try_read_from_inverted_index with non-BKD compatible query
size_t count = 0;
Field try_qp = Field::create_field<TYPE_INT>(query_value);
status = inverted_index_iterator->try_read_from_inverted_index(
std::static_pointer_cast<InvertedIndexReader>(
iterator->get_reader(InvertedIndexReaderType::STRING_TYPE)),
"c1", try_qp, InvertedIndexQueryType::MATCH_ANY_QUERY, &count);
EXPECT_TRUE(status.ok()); // Should succeed but not do anything for non-BKD queries
}
// Create comprehensive schema for various data types (from InvertedIndexReaderComprehensiveTest)
TabletSchemaSPtr create_comprehensive_schema() {
TabletSchemaSPtr tablet_schema = std::make_shared<TabletSchema>();
TabletSchemaPB tablet_schema_pb;
tablet_schema_pb.set_keys_type(DUP_KEYS);
tablet_schema->init_from_pb(tablet_schema_pb);
// Add various primitive type columns for testing
std::vector<std::tuple<std::string, FieldType, int, bool>> columns = {
{"c_int", FieldType::OLAP_FIELD_TYPE_INT, 4, true},
{"c_bigint", FieldType::OLAP_FIELD_TYPE_BIGINT, 8, false},
{"c_varchar", FieldType::OLAP_FIELD_TYPE_VARCHAR, 255, false},
{"c_string", FieldType::OLAP_FIELD_TYPE_STRING, 65535, false},
//{"c_double", FieldType::OLAP_FIELD_TYPE_DOUBLE, 8, false},
//{"c_float", FieldType::OLAP_FIELD_TYPE_FLOAT, 4, false},
{"c_date", FieldType::OLAP_FIELD_TYPE_DATE, 3, false},
{"c_datetime", FieldType::OLAP_FIELD_TYPE_DATETIME, 8, false},
{"c_decimal", FieldType::OLAP_FIELD_TYPE_DECIMAL, 16, false},
{"c_bool", FieldType::OLAP_FIELD_TYPE_BOOL, 1, false},
{"c_tinyint", FieldType::OLAP_FIELD_TYPE_TINYINT, 1, false},
{"c_smallint", FieldType::OLAP_FIELD_TYPE_SMALLINT, 2, false},
{"c_largeint", FieldType::OLAP_FIELD_TYPE_LARGEINT, 16, false},
{"c_char", FieldType::OLAP_FIELD_TYPE_CHAR, 10, false},
{"c_datev2", FieldType::OLAP_FIELD_TYPE_DATEV2, 4, false},
{"c_datetimev2", FieldType::OLAP_FIELD_TYPE_DATETIMEV2, 8, false},
{"c_timestamptz", FieldType::OLAP_FIELD_TYPE_TIMESTAMPTZ, 8, false},
// Appended (col_id 15..) — keep new entries here so existing
// col_id references in older tests remain stable.
{"c_float", FieldType::OLAP_FIELD_TYPE_FLOAT, 4, false}, // 15
{"c_double", FieldType::OLAP_FIELD_TYPE_DOUBLE, 8, false}, // 16
{"c_decimal32", FieldType::OLAP_FIELD_TYPE_DECIMAL32, 4, false}, // 17
{"c_decimal64", FieldType::OLAP_FIELD_TYPE_DECIMAL64, 8, false}, // 18
{"c_decimal128i", FieldType::OLAP_FIELD_TYPE_DECIMAL128I, 16, false}, // 19
{"c_decimal256", FieldType::OLAP_FIELD_TYPE_DECIMAL256, 32, false}, // 20
{"c_ipv4", FieldType::OLAP_FIELD_TYPE_IPV4, 4, false}, // 21
{"c_ipv6", FieldType::OLAP_FIELD_TYPE_IPV6, 16, false}, // 22
};
for (size_t i = 0; i < columns.size(); ++i) {
TabletColumn column;
column.set_name(std::get<0>(columns[i]));
column.set_unique_id(i);
column.set_type(std::get<1>(columns[i]));
column.set_length(std::get<2>(columns[i]));
column.set_index_length(std::get<2>(columns[i]));
column.set_is_key(std::get<3>(columns[i]));
column.set_is_nullable(true);
tablet_schema->append_column(column);
}
return tablet_schema;
}
// Prepare BKD index for different numeric types (from InvertedIndexReaderComprehensiveTest)
template <typename T>
void prepare_bkd_index_typed(
std::string_view rowset_id, int seg_id, int col_id, std::vector<T>& values,
TabletIndex* idx_meta, std::string* index_path_prefix,
InvertedIndexStorageFormatPB format = InvertedIndexStorageFormatPB::V2) {
auto tablet_schema = create_comprehensive_schema();
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_bkd");
index_meta_pb->clear_col_unique_id();
index_meta_pb->add_col_unique_id(col_id);
idx_meta->init_from_pb(*index_meta_pb.get());
*index_path_prefix = InvertedIndexDescriptor::get_index_file_path_prefix(
local_segment_path(kTestDir, rowset_id, seg_id));
std::string index_path =
InvertedIndexDescriptor::get_index_file_path_v2(*index_path_prefix);
io::FileWriterPtr file_writer;
io::FileWriterOptions opts;
auto fs = io::global_local_filesystem();
Status sts = fs->create_file(index_path, &file_writer, &opts);
ASSERT_TRUE(sts.ok()) << sts;
auto index_file_writer =
std::make_unique<IndexFileWriter>(fs, *index_path_prefix, std::string {rowset_id},
seg_id, format, std::move(file_writer));
const TabletColumn& column = tablet_schema->column(col_id);
const TabletColumn* field = &(column);
ASSERT_NE(field, nullptr);
std::unique_ptr<IndexColumnWriter> column_writer;
auto status =
IndexColumnWriter::create(field, &column_writer, index_file_writer.get(), idx_meta);
EXPECT_TRUE(status.ok()) << status;
for (const auto& value : values) {
// Copy into a real element first: for std::vector<bool>, `value` is a
// proxy, so `auto`/`&value` would give a __bit_reference/__bit_iterator
// rather than a real pointer. Use the container's value_type.
typename std::decay_t<decltype(values)>::value_type v = value;
status = column_writer->add_values(column.name(), reinterpret_cast<const void*>(&v), 1);
EXPECT_TRUE(status.ok()) << status;
}
status = column_writer->finish();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->begin_close();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->finish_close();
EXPECT_TRUE(status.ok()) << status;
}
void test_bkd_various_data_types() {
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
runtime_state.set_query_options(query_options);
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
// Test INT type
{
std::string_view rowset_id = "test_bkd_int";
int seg_id = 0;
std::vector<int32_t> values = {-100, 0, 42, 100, 200, 300};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 0, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
std::vector<std::pair<InvertedIndexQueryType, int32_t>> test_cases = {
{InvertedIndexQueryType::EQUAL_QUERY, 42},
{InvertedIndexQueryType::LESS_THAN_QUERY, 100},
{InvertedIndexQueryType::LESS_EQUAL_QUERY, 100},
{InvertedIndexQueryType::GREATER_THAN_QUERY, 100},
{InvertedIndexQueryType::GREATER_EQUAL_QUERY, 100}};
for (auto& test_case : test_cases) {
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_3192 = Field::create_field<TYPE_INT>(test_case.second);
auto status = bkd_reader->query(context, "c_int", qp_3192, test_case.first, bitmap);
EXPECT_TRUE(status.ok()) << "Query type: " << static_cast<int>(test_case.first);
if (test_case.first == InvertedIndexQueryType::EQUAL_QUERY) {
EXPECT_EQ(bitmap->cardinality(), 1)
<< "Should find exactly one document for value 42";
}
}
for (auto& test_case : test_cases) {
size_t count = 0;
Field qp_3204 = Field::create_field<TYPE_INT>(test_case.second);
auto status =
bkd_reader->try_query(context, "c_int", qp_3204, test_case.first, &count);
EXPECT_TRUE(status.ok()) << "Try query type: " << static_cast<int>(test_case.first);
}
}
// Test BIGINT type
{
std::string_view rowset_id = "test_bkd_bigint";
int seg_id = 1;
std::vector<int64_t> values = {-1000000LL, 0LL, 1000000LL, 2000000LL};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 1, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
int64_t query_value = 1000000LL;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_3229 = Field::create_field<TYPE_BIGINT>(query_value);
auto status = bkd_reader->query(context, "c_bigint", qp_3229,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
EXPECT_EQ(bitmap->cardinality(), 1);
}
// Test TIMESTAMPTZ type (to cover TYPE_TIMESTAMPTZ case)
{
std::string_view rowset_id = "test_timestamptz_type";
int seg_id = 8;
std::vector<uint64_t> values = {20240201120000ULL, 20240201130000ULL,
20240201140000ULL};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 14, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
std::vector<std::pair<InvertedIndexQueryType, uint64_t>> test_cases = {
{InvertedIndexQueryType::EQUAL_QUERY, 20240201130000ULL},
{InvertedIndexQueryType::LESS_THAN_QUERY, 20240201130000ULL},
{InvertedIndexQueryType::LESS_EQUAL_QUERY, 20240201130000ULL},
{InvertedIndexQueryType::GREATER_THAN_QUERY, 20240201130000ULL},
{InvertedIndexQueryType::GREATER_EQUAL_QUERY, 20240201130000ULL}};
for (auto& test_case : test_cases) {
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_3262 =
Field::create_field_from_olap_value<TYPE_TIMESTAMPTZ>(test_case.second);
auto status = bkd_reader->query(context, "c_timestamptz", qp_3262, test_case.first,
bitmap);
EXPECT_TRUE(status.ok()) << "Query type: " << static_cast<int>(test_case.first);
if (test_case.first == InvertedIndexQueryType::EQUAL_QUERY) {
EXPECT_EQ(bitmap->cardinality(), 1)
<< "Should find exactly one document for value 42";
}
}
for (auto& test_case : test_cases) {
size_t count = 0;
Field qp_3274 =
Field::create_field_from_olap_value<TYPE_TIMESTAMPTZ>(test_case.second);
auto status = bkd_reader->try_query(context, "c_timestamptz", qp_3274,
test_case.first, &count);
EXPECT_TRUE(status.ok()) << "Try query type: " << static_cast<int>(test_case.first);
}
}
// Test DOUBLE type
/*{
std::string_view rowset_id = "test_bkd_double";
int seg_id = 2;
std::vector<double> values = {-3.14, 0.0, 2.71, 3.14, 100.5};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 4, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
double query_value = 3.14;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
auto status =
auto qp_3300 = TypedInvertedIndexQueryParam<TYPE_DOUBLE>::create_unique();
qp_3300->set_value(&stats);
bkd_reader->query(&io_ctx, qp_3300.get(), &runtime_state, "c_double", &query_value,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
EXPECT_EQ(bitmap->cardinality(), 1);
}
// Test FLOAT type
{
std::string_view rowset_id = "test_bkd_float";
int seg_id = 3;
std::vector<float> values = {-1.5f, 0.0f, 1.5f, 2.5f, 10.5f};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 5, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(
io::global_local_filesystem(), index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
float query_value = 1.5f;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
auto status =
auto qp_3326 = TypedInvertedIndexQueryParam<TYPE_FLOAT>::create_unique();
qp_3326->set_value(&stats);
bkd_reader->query(&io_ctx, qp_3326.get(), &runtime_state, "c_float", &query_value,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
EXPECT_EQ(bitmap->cardinality(), 1);
}*/
}
// Test additional data types to improve code coverage
void test_additional_data_types_coverage() {
OlapReaderStatistics stats;
RuntimeState runtime_state;
TQueryOptions query_options;
query_options.enable_inverted_index_searcher_cache = false;
runtime_state.set_query_options(query_options);
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
// Test DATE type (to cover TYPE_DATE case)
{
std::string_view rowset_id = "test_date_type";
int seg_id = 0;
std::vector<uint24_t> values = {20240101, 20240102, 20240103}; // DATE as uint32
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 4, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
uint32_t query_value = 20240102;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
// TYPE_DATE storage is uint24_t — narrow from the test's uint32_t.
typename PrimitiveTypeTraits<TYPE_DATE>::StorageFieldType date_storage(query_value);
Field qp_3366 = Field::create_field_from_olap_value<TYPE_DATE>(date_storage);
auto status = bkd_reader->query(context, "c_date", qp_3366,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
// Test DATETIME type (to cover TYPE_DATETIME case)
{
std::string_view rowset_id = "test_datetime_type";
int seg_id = 1;
std::vector<uint64_t> values = {20240101120000ULL, 20240101130000ULL,
20240101140000ULL};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 5, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
int64_t query_value = 20240101130000LL;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_3391 = Field::create_field_from_olap_value<TYPE_DATETIME>(
static_cast<uint64_t>(query_value));
auto status = bkd_reader->query(context, "c_datetime", qp_3391,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
// Test BOOL type (to cover TYPE_BOOL case)
{
std::string_view rowset_id = "test_bool_type";
int seg_id = 2;
std::vector<bool> values = {true, false, true, false};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 7, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
bool query_value = true;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
// TYPE_BOOLEAN storage is uint8_t.
uint8_t bool_storage = query_value ? 1 : 0;
Field qp_3415 = Field::create_field<TYPE_BOOLEAN>(bool_storage);
auto status = bkd_reader->query(context, "c_bool", qp_3415,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
// Test TINYINT type (to cover TYPE_TINYINT case)
{
std::string_view rowset_id = "test_tinyint_type";
int seg_id = 3;
std::vector<int8_t> values = {-128, 0, 1, 127};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 8, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
int8_t query_value = 1;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_3439 = Field::create_field<TYPE_TINYINT>(query_value);
auto status = bkd_reader->query(context, "c_tinyint", qp_3439,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
// Test SMALLINT type (to cover TYPE_SMALLINT case)
{
std::string_view rowset_id = "test_smallint_type";
int seg_id = 4;
std::vector<int16_t> values = {-32768, 0, 1000, 32767};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 9, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
int16_t query_value = 1000;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_3463 = Field::create_field<TYPE_SMALLINT>(query_value);
auto status = bkd_reader->query(context, "c_smallint", qp_3463,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
// Test LARGEINT type (to cover TYPE_LARGEINT case)
{
std::string_view rowset_id = "test_largeint_type";
int seg_id = 5;
std::vector<__int128> values = {-1000000000000000000LL, 0, 1000000000000000000LL};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 10, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
__int128 query_value = 0;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_3487 = Field::create_field<TYPE_LARGEINT>(query_value);
auto status = bkd_reader->query(context, "c_largeint", qp_3487,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
// Test DATEV2 type (to cover TYPE_DATEV2 case)
{
std::string_view rowset_id = "test_datev2_type";
int seg_id = 6;
std::vector<uint32_t> values = {20240201, 20240202, 20240203};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 12, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
uint32_t query_value = 20240202;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_3511 = Field::create_field<TYPE_DATEV2>(query_value);
auto status = bkd_reader->query(context, "c_datev2", qp_3511,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
// Test DATETIMEV2 type (to cover TYPE_DATETIMEV2 case)
{
std::string_view rowset_id = "test_datetimev2_type";
int seg_id = 7;
std::vector<uint64_t> values = {20240201120000ULL, 20240201130000ULL,
20240201140000ULL};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 13, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
uint64_t query_value = 20240201130000ULL;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_3536 = Field::create_field<TYPE_DATETIMEV2>(query_value);
auto status = bkd_reader->query(context, "c_datetimev2", qp_3536,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
// Test TIMESTAMPTZ type (to cover TYPE_TIMESTAMPTZ case)
{
std::string_view rowset_id = "test_timestamptz_type";
int seg_id = 8;
std::vector<uint64_t> values = {20240201120000ULL, 20240201130000ULL,
20240201140000ULL};
TabletIndex idx_meta;
std::string index_path_prefix;
prepare_bkd_index_typed(rowset_id, seg_id, 14, values, &idx_meta, &index_path_prefix);
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
index_path_prefix,
InvertedIndexStorageFormatPB::V2);
EXPECT_TRUE(reader->init().ok());
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
EXPECT_NE(bkd_reader, nullptr);
uint64_t query_value = 20240201130000ULL;
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_3561 = Field::create_field_from_olap_value<TYPE_TIMESTAMPTZ>(query_value);
auto status = bkd_reader->query(context, "c_timestamptz", qp_3561,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
EXPECT_TRUE(status.ok());
}
}
// Test unsupported data types to cover default case
void test_unsupported_data_types() {
// Create a schema with unsupported type for inverted index
TabletSchemaSPtr tablet_schema = std::make_shared<TabletSchema>();
TabletSchemaPB tablet_schema_pb;
tablet_schema_pb.set_keys_type(DUP_KEYS);
tablet_schema->init_from_pb(tablet_schema_pb);
// Add an unsupported type column (e.g., JSON type if it exists)
TabletColumn column;
column.set_name("c_unsupported");
column.set_unique_id(0);
column.set_type(FieldType::OLAP_FIELD_TYPE_JSONB); // Using JSONB instead of JSON
column.set_length(65535);
column.set_index_length(65535);
column.set_is_key(false);
column.set_is_nullable(true);
tablet_schema->append_column(column);
std::string rowset_id = "test_unsupported";
int seg_id = 0;
TabletIndex idx_meta;
auto index_meta_pb = std::make_unique<TabletIndexPB>();
index_meta_pb->set_index_type(IndexType::INVERTED);
index_meta_pb->set_index_id(1);
index_meta_pb->set_index_name("test_unsupported");
index_meta_pb->add_col_unique_id(0);
idx_meta.init_from_pb(*index_meta_pb.get());
auto index_path_prefix = std::string(InvertedIndexDescriptor::get_index_file_path_prefix(
local_segment_path(kTestDir, rowset_id, seg_id)));
std::string index_path = InvertedIndexDescriptor::get_index_file_path_v2(index_path_prefix);
io::FileWriterPtr file_writer;
io::FileWriterOptions opts;
auto fs = io::global_local_filesystem();
Status sts = fs->create_file(index_path, &file_writer, &opts);
ASSERT_TRUE(sts.ok()) << sts;
auto index_file_writer = std::make_unique<IndexFileWriter>(
fs, std::string(index_path_prefix), rowset_id, seg_id,
InvertedIndexStorageFormatPB::V2, std::move(file_writer));
const TabletColumn& test_column = tablet_schema->column(0);
const TabletColumn* field = &(test_column);
ASSERT_NE(field, nullptr);
std::unique_ptr<IndexColumnWriter> column_writer;
auto status = IndexColumnWriter::create(field, &column_writer, index_file_writer.get(),
&idx_meta);
// This should fail for unsupported types, demonstrating the default case
// If it succeeds, we can still test with invalid query parameters
if (status.ok()) {
status = column_writer->finish();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->begin_close();
EXPECT_TRUE(status.ok()) << status;
status = index_file_writer->finish_close();
EXPECT_TRUE(status.ok()) << status;
// Try to create reader and test unsupported query
auto reader = std::make_shared<IndexFileReader>(io::global_local_filesystem(),
std::string(index_path_prefix),
InvertedIndexStorageFormatPB::V2);
if (reader->init().ok()) {
auto bkd_reader = BkdIndexReader::create_shared(&idx_meta, reader);
if (bkd_reader != nullptr) {
OlapReaderStatistics stats;
RuntimeState runtime_state;
io::IOContext io_ctx;
IndexQueryContextPtr context = std::make_shared<IndexQueryContext>();
context->io_ctx = &io_ctx;
context->stats = &stats;
context->runtime_state = &runtime_state;
std::string query_value = "test";
std::shared_ptr<roaring::Roaring> bitmap = std::make_shared<roaring::Roaring>();
Field qp_unsupp = Field::create_field<TYPE_STRING>(query_value);
auto query_status =
bkd_reader->query(context, "c_unsupported", qp_unsupp,
InvertedIndexQueryType::EQUAL_QUERY, bitmap);
// This might fail due to unsupported type, which is what we want to test
}
}
}
}
private:
std::unique_ptr<InvertedIndexSearcherCache> _inverted_index_searcher_cache;
std::unique_ptr<InvertedIndexQueryCache> _inverted_index_query_cache;
};
// String index reading test
TEST_F(InvertedIndexReaderTest, StringIndexRead) {
test_string_index_read();
}
// NULL value bitmap test
TEST_F(InvertedIndexReaderTest, NullBitmapRead) {
test_null_bitmap_read();
}
// BKD index reading test
TEST_F(InvertedIndexReaderTest, BkdIndexRead) {
test_bkd_index_read();
}
// BKD half-bounded range query regression suite, one TEST_F per BKD-supported
// PrimitiveType. They all share `verify_bkd_range_queries`, which:
// - writes 6 sorted values into a fresh BKD index
// - asserts EQUAL / LESS_THAN / LESS_EQUAL / GREATER_THAN / GREATER_EQUAL
// cardinalities derived from the values via std::count_if.
//
// Locks in the typed-param interface, the +/-infinity sentinels routed
// through type_limit<compute_t> + PrimitiveTypeConvertor<PT>, and BKD
// writer/reader/visitor agreement.
TEST_F(InvertedIndexReaderTest, BkdRangeIntRangeQuery) {
test_bkd_range_int();
}
TEST_F(InvertedIndexReaderTest, BkdRangeBigIntRangeQuery) {
test_bkd_range_bigint();
}
TEST_F(InvertedIndexReaderTest, BkdRangeSmallIntRangeQuery) {
test_bkd_range_smallint();
}
TEST_F(InvertedIndexReaderTest, BkdRangeTinyIntRangeQuery) {
test_bkd_range_tinyint();
}
TEST_F(InvertedIndexReaderTest, BkdRangeLargeIntRangeQuery) {
test_bkd_range_largeint();
}
TEST_F(InvertedIndexReaderTest, BkdRangeDecimalV2RangeQuery) {
test_bkd_range_decimalv2();
}
TEST_F(InvertedIndexReaderTest, BkdRangeDateRangeQuery) {
test_bkd_range_date();
}
TEST_F(InvertedIndexReaderTest, BkdRangeDateTimeRangeQuery) {
test_bkd_range_datetime();
}
TEST_F(InvertedIndexReaderTest, BkdRangeDateV2RangeQuery) {
test_bkd_range_datev2();
}
TEST_F(InvertedIndexReaderTest, BkdRangeDateTimeV2RangeQuery) {
test_bkd_range_datetimev2();
}
TEST_F(InvertedIndexReaderTest, BkdRangeTimestampTzRangeQuery) {
test_bkd_range_timestamptz();
}
TEST_F(InvertedIndexReaderTest, BkdRangeBoolRangeQuery) {
test_bkd_range_bool();
}
TEST_F(InvertedIndexReaderTest, BkdRangeFloatRangeQuery) {
test_bkd_range_float();
}
TEST_F(InvertedIndexReaderTest, BkdRangeDoubleRangeQuery) {
test_bkd_range_double();
}
TEST_F(InvertedIndexReaderTest, BkdRangeDecimal32RangeQuery) {
test_bkd_range_decimal32();
}
TEST_F(InvertedIndexReaderTest, BkdRangeDecimal64RangeQuery) {
test_bkd_range_decimal64();
}
TEST_F(InvertedIndexReaderTest, BkdRangeDecimal128IRangeQuery) {
test_bkd_range_decimal128i();
}
TEST_F(InvertedIndexReaderTest, BkdRangeDecimal256RangeQuery) {
test_bkd_range_decimal256();
}
TEST_F(InvertedIndexReaderTest, BkdRangeIPv4RangeQuery) {
test_bkd_range_ipv4();
}
TEST_F(InvertedIndexReaderTest, BkdRangeIPv6RangeQuery) {
test_bkd_range_ipv6();
}
// Verifies that KeyCoder<OLAP_FIELD_TYPE_DATETIME> produces byte-identical
// output regardless of whether the input pointer is to int64_t or uint64_t.
// This is what makes TypedInvertedIndexQueryParam<TYPE_DATETIME>::storage_val
// = int64_t (signed view) and the historic uint64_t storage interchangeable for
// real datetime values: KeyCoder reads bit pattern via memcpy, then sign-flips
// based on its own CppType (= int64_t) — so signed/unsigned at the call site
// doesn't change the encoded bytes as long as bit patterns agree.
TEST(KeyCoderDateTimeTest, ByteIdenticalForSignedAndUnsignedInput) {
const auto* coder = get_key_coder(FieldType::OLAP_FIELD_TYPE_DATETIME);
ASSERT_NE(coder, nullptr);
// Mix realistic datetimes with the boundary values that drive sentinels.
constexpr int64_t kCases[] = {
10101000000LL, // 0001-01-01 00:00:00 (smallest valid set_to_min sentinel)
20200101120000LL, // 2020-01-01 12:00:00
20240310093000LL, // 2024-03-10 09:30:00
99991231235959LL, // 9999-12-31 23:59:59 (largest valid set_to_max sentinel)
std::numeric_limits<int64_t>::max(), // type_limit max sentinel
0LL, // type_limit min (also = INT64_MIN's bit-flipped image)
std::numeric_limits<int64_t>::lowest(),
};
for (int64_t case_val : kCases) {
int64_t signed_val = case_val;
uint64_t unsigned_val;
std::memcpy(&unsigned_val, &signed_val, sizeof(unsigned_val));
std::string signed_buf;
std::string unsigned_buf;
coder->full_encode_ascending(&signed_val, &signed_buf);
coder->full_encode_ascending(&unsigned_val, &unsigned_buf);
ASSERT_EQ(signed_buf.size(), sizeof(int64_t));
ASSERT_EQ(unsigned_buf.size(), sizeof(uint64_t));
EXPECT_EQ(signed_buf, unsigned_buf)
<< "DATETIME KeyCoder must produce identical bytes for value "
<< static_cast<int64_t>(case_val) << " regardless of pointer type";
}
}
// Query cache test
TEST_F(InvertedIndexReaderTest, QueryCache) {
test_query_cache();
}
// Searcher cache test
TEST_F(InvertedIndexReaderTest, SearcherCache) {
test_searcher_cache();
}
// Exercise the different combinations of query/searcher caches.
TEST_F(InvertedIndexReaderTest, CacheCombinationMatrix) {
test_inverted_index_cache_matrix();
}
// Test string index with large document set (>512 docs)
TEST_F(InvertedIndexReaderTest, StringIndexLargeDocset) {
test_string_index_large_docset();
}
// Test string index with large document set using V3 format
TEST_F(InvertedIndexReaderTest, StringIndexLargeDocsetV3) {
test_string_index_large_docset_v3();
}
// Test reading existing large document set index file
TEST_F(InvertedIndexReaderTest, CompatibleTest) {
test_compatible_read_cross_platform();
}
// Test cache error scenarios that could crash BE
TEST_F(InvertedIndexReaderTest, CacheErrorScenarios) {
test_cache_error_scenarios();
}
// Test tokenized index query error scenarios
TEST_F(InvertedIndexReaderTest, TokenizedIndexQueryErrorScenarios) {
test_tokenized_index_query_error_scenarios();
}
// Additional comprehensive tests for uncovered paths
TEST_F(InvertedIndexReaderTest, ErrorHandlingComprehensive) {
test_error_handling_comprehensive();
}
TEST_F(InvertedIndexReaderTest, ErrorHandling) {
test_error_handling();
}
TEST_F(InvertedIndexReaderTest, UncoveredErrorPaths) {
test_uncovered_error_paths();
}
TEST_F(InvertedIndexReaderTest, BkdUncoveredPaths) {
test_bkd_uncovered_paths();
}
TEST_F(InvertedIndexReaderTest, IteratorUncoveredPaths) {
test_iterator_uncovered_paths();
}
TEST_F(InvertedIndexReaderTest, BkdVariousDataTypes) {
test_bkd_various_data_types();
}
TEST_F(InvertedIndexReaderTest, AdditionalDataTypesCoverage) {
test_additional_data_types_coverage();
}
TEST_F(InvertedIndexReaderTest, UnsupportedDataTypes) {
test_unsupported_data_types();
}
// Test InvertedIndexResultBitmap operator|= with NULL handling
TEST_F(InvertedIndexReaderTest, ResultBitmapOrOperatorNullHandling) {
// Test SQL three-valued logic for OR:
// - TRUE OR NULL = TRUE (not NULL)
// - FALSE OR NULL = NULL
// - NULL OR NULL = NULL
// Case 1: TRUE OR NULL = TRUE
{
auto data_a = std::make_shared<roaring::Roaring>();
auto null_a = std::make_shared<roaring::Roaring>();
data_a->add(1); // row 1 is TRUE
// row 2 is FALSE (not in data_a, not in null_a)
auto data_b = std::make_shared<roaring::Roaring>();
auto null_b = std::make_shared<roaring::Roaring>();
null_b->add(1); // row 1 is NULL
data_b->add(2); // row 2 is TRUE
InvertedIndexResultBitmap bitmap_a(data_a, null_a);
InvertedIndexResultBitmap bitmap_b(data_b, null_b);
bitmap_a |= bitmap_b;
// Result: row 1 should be TRUE (TRUE OR NULL = TRUE)
// row 2 should be TRUE (FALSE OR TRUE = TRUE)
EXPECT_TRUE(bitmap_a.get_data_bitmap()->contains(1));
EXPECT_TRUE(bitmap_a.get_data_bitmap()->contains(2));
EXPECT_FALSE(bitmap_a.get_null_bitmap()->contains(1)); // row 1 is not NULL
EXPECT_FALSE(bitmap_a.get_null_bitmap()->contains(2)); // row 2 is not NULL
}
// Case 2: FALSE OR NULL = NULL
{
auto data_a = std::make_shared<roaring::Roaring>();
auto null_a = std::make_shared<roaring::Roaring>();
// row 0 is FALSE
auto data_b = std::make_shared<roaring::Roaring>();
auto null_b = std::make_shared<roaring::Roaring>();
null_b->add(0); // row 0 is NULL
InvertedIndexResultBitmap bitmap_a(data_a, null_a);
InvertedIndexResultBitmap bitmap_b(data_b, null_b);
bitmap_a |= bitmap_b;
// Result: row 0 should be NULL (FALSE OR NULL = NULL)
EXPECT_FALSE(bitmap_a.get_data_bitmap()->contains(0));
EXPECT_TRUE(bitmap_a.get_null_bitmap()->contains(0));
}
// Case 3: NULL OR NULL = NULL
{
auto data_a = std::make_shared<roaring::Roaring>();
auto null_a = std::make_shared<roaring::Roaring>();
null_a->add(5); // row 5 is NULL
auto data_b = std::make_shared<roaring::Roaring>();
auto null_b = std::make_shared<roaring::Roaring>();
null_b->add(5); // row 5 is NULL
InvertedIndexResultBitmap bitmap_a(data_a, null_a);
InvertedIndexResultBitmap bitmap_b(data_b, null_b);
bitmap_a |= bitmap_b;
// Result: row 5 should be NULL (NULL OR NULL = NULL)
EXPECT_FALSE(bitmap_a.get_data_bitmap()->contains(5));
EXPECT_TRUE(bitmap_a.get_null_bitmap()->contains(5));
}
// Case 4: Complex scenario - cross-field OR with NULL
// Simulating: field1="value" OR field2="value" where field2 has NULL
{
auto data_field1 = std::make_shared<roaring::Roaring>();
auto null_field1 = std::make_shared<roaring::Roaring>();
data_field1->addRange(0, 15); // rows 0-14 match field1
auto data_field2 = std::make_shared<roaring::Roaring>();
auto null_field2 = std::make_shared<roaring::Roaring>();
null_field2->addRange(0, 15); // rows 0-14 have NULL in field2
data_field2->add(20); // row 20 matches field2
InvertedIndexResultBitmap bitmap_field1(data_field1, null_field1);
InvertedIndexResultBitmap bitmap_field2(data_field2, null_field2);
bitmap_field1 |= bitmap_field2;
// Result: rows 0-14 should be TRUE (TRUE OR NULL = TRUE)
// row 20 should be TRUE
for (uint32_t i = 0; i < 15; ++i) {
EXPECT_TRUE(bitmap_field1.get_data_bitmap()->contains(i))
<< "Row " << i << " should be TRUE";
EXPECT_FALSE(bitmap_field1.get_null_bitmap()->contains(i))
<< "Row " << i << " should not be NULL";
}
EXPECT_TRUE(bitmap_field1.get_data_bitmap()->contains(20));
EXPECT_FALSE(bitmap_field1.get_null_bitmap()->contains(20));
}
}
} // namespace doris::segment_v2