Skip to content

Commit c4fc518

Browse files
committed
feat(lumina): support Lumina tag filtering
1 parent debf91d commit c4fc518

8 files changed

Lines changed: 1323 additions & 50 deletions

File tree

include/paimon/global_index/global_index_io_meta.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,11 @@
1616

1717
#pragma once
1818

19+
#include <cstdint>
1920
#include <memory>
21+
#include <optional>
2022
#include <string>
23+
#include <vector>
2124

2225
#include "paimon/memory/bytes.h"
2326
#include "paimon/utils/range.h"
@@ -27,14 +30,24 @@ namespace paimon {
2730
struct PAIMON_EXPORT GlobalIndexIOMeta {
2831
GlobalIndexIOMeta(const std::string& _file_path, int64_t _file_size,
2932
const std::shared_ptr<Bytes>& _metadata)
30-
: file_path(_file_path), file_size(_file_size), metadata(_metadata) {}
33+
: GlobalIndexIOMeta(_file_path, _file_size, _metadata, std::nullopt) {}
34+
35+
GlobalIndexIOMeta(const std::string& _file_path, int64_t _file_size,
36+
const std::shared_ptr<Bytes>& _metadata,
37+
const std::optional<std::vector<int32_t>>& _extra_field_ids)
38+
: file_path(_file_path),
39+
file_size(_file_size),
40+
metadata(_metadata),
41+
extra_field_ids(_extra_field_ids) {}
3142

3243
std::string file_path;
3344
int64_t file_size;
3445
/// Optional binary metadata associated with the file, such as serialized
3546
/// secondary index structures or inline index bytes.
3647
/// May be null if no additional metadata is available.
3748
std::shared_ptr<Bytes> metadata;
49+
/// Optional table field ids materialized together with the indexed field.
50+
std::optional<std::vector<int32_t>> extra_field_ids;
3851
};
3952

4053
} // namespace paimon

include/paimon/global_index/global_indexer.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#pragma once
1818

1919
#include <memory>
20+
#include <optional>
2021
#include <string>
2122
#include <vector>
2223

@@ -36,6 +37,11 @@ class PAIMON_EXPORT GlobalIndexer {
3637
public:
3738
virtual ~GlobalIndexer() = default;
3839

40+
/// Returns additional table fields required during index construction.
41+
virtual Result<std::optional<std::vector<std::string>>> GetExtraFieldNames() const {
42+
return std::optional<std::vector<std::string>>(std::nullopt);
43+
}
44+
3945
/// Creates a writer for building a global index on a specific field.
4046
///
4147
/// @param field_name Name of the field to be indexed.

src/paimon/core/global_index/global_index_scan_impl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <utility>
2121

2222
#include "arrow/c/bridge.h"
23+
#include "arrow/c/helpers.h"
2324
#include "paimon/common/global_index/offset_global_index_reader.h"
2425
#include "paimon/common/global_index/union_global_index_reader.h"
2526
#include "paimon/common/utils/scope_guard.h"
@@ -185,7 +186,6 @@ Result<std::vector<std::shared_ptr<GlobalIndexReader>>> GlobalIndexScanImpl::Cre
185186
if (row_range_index && !row_range_index->Intersects(range.from, range.to)) {
186187
continue;
187188
}
188-
// TODO(xinyu.lxy): c_arrow_schema may contains additional associated fields.
189189
auto arrow_field = DataField::ConvertDataFieldToArrowField(field);
190190
auto arrow_schema = arrow::schema({arrow_field});
191191

@@ -223,7 +223,7 @@ GlobalIndexIOMeta GlobalIndexScanImpl::ToGlobalIndexIOMeta(
223223
assert(index_meta->GetGlobalIndexMeta());
224224
const auto& global_index_meta = index_meta->GetGlobalIndexMeta().value();
225225
return {index_file_manager_->ToPath(index_meta), index_meta->FileSize(),
226-
global_index_meta.index_meta};
226+
global_index_meta.index_meta, global_index_meta.extra_field_ids};
227227
}
228228

229229
Result<std::shared_ptr<GlobalIndexResult>> GlobalIndexScanImpl::Scan(

src/paimon/core/global_index/global_index_write_task.cpp

Lines changed: 117 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
#include "paimon/global_index/global_index_write_task.h"
1818

19+
#include <set>
20+
1921
#include "arrow/c/bridge.h"
22+
#include "arrow/c/helpers.h"
2023
#include "paimon/common/table/special_fields.h"
2124
#include "paimon/common/types/data_field.h"
2225
#include "paimon/common/utils/arrow/status_utils.h"
@@ -35,6 +38,17 @@
3538
#include "paimon/table/source/table_read.h"
3639
namespace paimon {
3740
namespace {
41+
Result<std::unique_ptr<GlobalIndexer>> CreateGlobalIndexer(const std::string& index_type,
42+
const CoreOptions& core_options) {
43+
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<GlobalIndexer> indexer,
44+
GlobalIndexerFactory::Get(index_type, core_options.ToMap()));
45+
if (!indexer) {
46+
return Status::Invalid(
47+
fmt::format("Unknown index type {}, may not registered", index_type));
48+
}
49+
return indexer;
50+
}
51+
3852
Result<std::shared_ptr<GlobalIndexFileManager>> CreateGlobalIndexFileManager(
3953
const std::string& table_path, const std::shared_ptr<TableSchema>& table_schema,
4054
const CoreOptions& core_options, const std::shared_ptr<MemoryPool>& pool) {
@@ -58,43 +72,95 @@ Result<std::shared_ptr<GlobalIndexFileManager>> CreateGlobalIndexFileManager(
5872
}
5973

6074
Result<std::shared_ptr<GlobalIndexWriter>> CreateGlobalIndexWriter(
61-
const std::string& index_type, const DataField& field,
75+
const GlobalIndexer& indexer, const DataField& field,
76+
const std::vector<DataField>& extra_fields,
6277
const std::shared_ptr<GlobalIndexFileManager>& index_file_manager,
63-
const CoreOptions& core_options, const std::shared_ptr<MemoryPool>& pool) {
64-
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<GlobalIndexer> indexer,
65-
GlobalIndexerFactory::Get(index_type, core_options.ToMap()));
66-
if (!indexer) {
67-
return Status::Invalid(
68-
fmt::format("Unknown index type {}, may not registered", index_type));
78+
const std::shared_ptr<MemoryPool>& pool) {
79+
arrow::FieldVector arrow_fields;
80+
arrow_fields.reserve(extra_fields.size() + 1);
81+
arrow_fields.push_back(DataField::ConvertDataFieldToArrowField(field));
82+
for (const auto& extra_field : extra_fields) {
83+
arrow_fields.push_back(DataField::ConvertDataFieldToArrowField(extra_field));
6984
}
70-
// TODO(xinyu.lxy): may add additional fields to read for index write
71-
auto arrow_field = DataField::ConvertDataFieldToArrowField(field);
72-
auto arrow_schema = arrow::schema({arrow_field});
85+
auto arrow_schema = arrow::schema(arrow_fields);
7386
ArrowSchema c_arrow_schema;
7487
PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportSchema(*arrow_schema, &c_arrow_schema));
75-
return indexer->CreateWriter(field.Name(), &c_arrow_schema, index_file_manager, pool);
88+
ScopeGuard guard([&]() { ArrowSchemaRelease(&c_arrow_schema); });
89+
return indexer.CreateWriter(field.Name(), &c_arrow_schema, index_file_manager, pool);
90+
}
91+
92+
Result<std::vector<DataField>> GetExtraFields(const TableSchema& table_schema,
93+
const std::string& field_name,
94+
const std::vector<std::string>& extra_field_names) {
95+
std::vector<DataField> extra_fields;
96+
extra_fields.reserve(extra_field_names.size());
97+
std::set<std::string> dedup_field_names;
98+
for (const auto& extra_field_name : extra_field_names) {
99+
if (extra_field_name == field_name || !dedup_field_names.insert(extra_field_name).second) {
100+
continue;
101+
}
102+
PAIMON_ASSIGN_OR_RAISE(DataField extra_field, table_schema.GetField(extra_field_name));
103+
extra_fields.push_back(extra_field);
104+
}
105+
return extra_fields;
106+
}
107+
108+
std::vector<std::string> BuildReadFieldNames(const std::string& field_name,
109+
const std::vector<DataField>& extra_fields) {
110+
std::vector<std::string> read_field_names;
111+
read_field_names.reserve(extra_fields.size() + 2);
112+
read_field_names.push_back(field_name);
113+
for (const auto& extra_field : extra_fields) {
114+
read_field_names.push_back(extra_field.Name());
115+
}
116+
read_field_names.push_back(SpecialFields::RowId().Name());
117+
return read_field_names;
118+
}
119+
120+
std::vector<std::string> BuildWriterFieldNames(const std::string& field_name,
121+
const std::vector<DataField>& extra_fields) {
122+
std::vector<std::string> writer_field_names;
123+
writer_field_names.reserve(extra_fields.size() + 1);
124+
writer_field_names.push_back(field_name);
125+
for (const auto& extra_field : extra_fields) {
126+
writer_field_names.push_back(extra_field.Name());
127+
}
128+
return writer_field_names;
129+
}
130+
131+
std::optional<std::vector<int32_t>> GetExtraFieldIds(const std::vector<DataField>& extra_fields) {
132+
if (extra_fields.empty()) {
133+
return std::nullopt;
134+
}
135+
std::vector<int32_t> extra_field_ids;
136+
extra_field_ids.reserve(extra_fields.size());
137+
for (const auto& extra_field : extra_fields) {
138+
extra_field_ids.push_back(extra_field.Id());
139+
}
140+
return extra_field_ids;
76141
}
77142

78143
Result<std::unique_ptr<BatchReader>> CreateBatchReader(
79-
const std::string& table_path, const std::string& field_name,
144+
const std::string& table_path, const std::vector<std::string>& read_field_names,
80145
const std::shared_ptr<IndexedSplit>& indexed_split, const CoreOptions& core_options,
81146
const std::shared_ptr<MemoryPool>& pool) {
82147
ReadContextBuilder read_context_builder(table_path);
83148
read_context_builder.SetOptions(core_options.ToMap())
84149
.WithFileSystem(core_options.GetFileSystem())
85150
.EnablePrefetch(true)
86151
.WithMemoryPool(pool)
87-
.SetReadFieldNames({field_name, SpecialFields::RowId().Name()});
152+
.SetReadFieldNames(read_field_names);
88153
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<ReadContext> read_context,
89154
read_context_builder.Finish());
90155
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<TableRead> table_read,
91156
TableRead::Create(std::move(read_context)));
92157
return table_read->CreateReader(indexed_split);
93158
}
94159

95-
Result<std::vector<GlobalIndexIOMeta>> BuildIndex(const std::string& field_name, const Range& range,
96-
BatchReader* batch_reader,
97-
GlobalIndexWriter* global_index_writer) {
160+
Result<std::vector<GlobalIndexIOMeta>> BuildIndex(
161+
const std::string& field_name, const Range& range,
162+
const std::vector<std::string>& writer_field_names, BatchReader* batch_reader,
163+
GlobalIndexWriter* global_index_writer) {
98164
while (true) {
99165
PAIMON_ASSIGN_OR_RAISE(BatchReader::ReadBatch read_batch, batch_reader->NextBatch());
100166
if (BatchReader::IsEofBatch(read_batch)) {
@@ -131,8 +197,20 @@ Result<std::vector<GlobalIndexIOMeta>> BuildIndex(const std::string& field_name,
131197
}
132198
relative_row_ids.push_back(row_id - range.from);
133199
}
134-
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(std::shared_ptr<arrow::StructArray> new_array,
135-
arrow::StructArray::Make({indexed_array}, {field_name}));
200+
std::vector<std::shared_ptr<arrow::Array>> writer_arrays;
201+
writer_arrays.reserve(writer_field_names.size());
202+
for (const auto& writer_field_name : writer_field_names) {
203+
auto writer_array = struct_array->GetFieldByName(writer_field_name);
204+
if (!writer_array) {
205+
return Status::Invalid(
206+
fmt::format("read array does not contain {} field in GlobalIndexWriteTask",
207+
writer_field_name));
208+
}
209+
writer_arrays.push_back(writer_array);
210+
}
211+
PAIMON_ASSIGN_OR_RAISE_FROM_ARROW(
212+
std::shared_ptr<arrow::StructArray> new_array,
213+
arrow::StructArray::Make(writer_arrays, writer_field_names));
136214
::ArrowArray c_new_array;
137215
PAIMON_RETURN_NOT_OK_FROM_ARROW(arrow::ExportArray(*new_array, &c_new_array));
138216
PAIMON_RETURN_NOT_OK(
@@ -157,8 +235,8 @@ Result<std::shared_ptr<CommitMessage>> ToCommitMessage(
157235
index_file_metas.push_back(std::make_shared<IndexFileMeta>(
158236
index_type, PathUtil::GetName(io_meta.file_path), io_meta.file_size, range.Count(),
159237
/*dv_ranges=*/std::nullopt, external_path,
160-
GlobalIndexMeta(range.from, range.to, field_id,
161-
/*extra_field_ids=*/std::nullopt, io_meta.metadata)));
238+
GlobalIndexMeta(range.from, range.to, field_id, io_meta.extra_field_ids,
239+
io_meta.metadata)));
162240
}
163241
DataIncrement data_increment(std::move(index_file_metas));
164242
return std::make_shared<CommitMessageImpl>(partition, bucket,
@@ -199,6 +277,17 @@ Result<std::shared_ptr<CommitMessage>> GlobalIndexWriteTask::WriteIndex(
199277
}
200278
PAIMON_ASSIGN_OR_RAISE(CoreOptions core_options,
201279
CoreOptions::FromMap(final_options, file_system));
280+
PAIMON_ASSIGN_OR_RAISE(std::unique_ptr<GlobalIndexer> indexer,
281+
CreateGlobalIndexer(index_type, core_options));
282+
PAIMON_ASSIGN_OR_RAISE(std::optional<std::vector<std::string>> extra_field_names,
283+
indexer->GetExtraFieldNames());
284+
PAIMON_ASSIGN_OR_RAISE(DataField field, table_schema->GetField(field_name));
285+
PAIMON_ASSIGN_OR_RAISE(std::vector<DataField> extra_fields,
286+
GetExtraFields(*table_schema, field_name,
287+
extra_field_names.value_or(std::vector<std::string>())));
288+
std::optional<std::vector<int32_t>> extra_field_ids = GetExtraFieldIds(extra_fields);
289+
std::vector<std::string> writer_field_names = BuildWriterFieldNames(field_name, extra_fields);
290+
std::vector<std::string> read_field_names = BuildReadFieldNames(field_name, extra_fields);
202291

203292
// create index file manager
204293
PAIMON_ASSIGN_OR_RAISE(
@@ -208,23 +297,25 @@ Result<std::shared_ptr<CommitMessage>> GlobalIndexWriteTask::WriteIndex(
208297
// create batch reader
209298
PAIMON_ASSIGN_OR_RAISE(
210299
std::unique_ptr<BatchReader> batch_reader,
211-
CreateBatchReader(table_path, field_name, indexed_split, core_options, pool));
300+
CreateBatchReader(table_path, read_field_names, indexed_split, core_options, pool));
212301

213302
// create global index writer
214-
PAIMON_ASSIGN_OR_RAISE(DataField field, table_schema->GetField(field_name));
215303
PAIMON_ASSIGN_OR_RAISE(
216304
std::shared_ptr<GlobalIndexWriter> global_index_writer,
217-
CreateGlobalIndexWriter(index_type, field, index_file_manager, core_options, pool));
305+
CreateGlobalIndexWriter(*indexer, field, extra_fields, index_file_manager, pool));
218306

219307
ScopeGuard guard([&]() {
220308
global_index_writer.reset();
221309
batch_reader.reset();
222310
});
223311

224312
// read from data split and write to index writer
225-
PAIMON_ASSIGN_OR_RAISE(
226-
std::vector<GlobalIndexIOMeta> global_index_io_metas,
227-
BuildIndex(field_name, range, batch_reader.get(), global_index_writer.get()));
313+
PAIMON_ASSIGN_OR_RAISE(std::vector<GlobalIndexIOMeta> global_index_io_metas,
314+
BuildIndex(field_name, range, writer_field_names, batch_reader.get(),
315+
global_index_writer.get()));
316+
for (auto& io_meta : global_index_io_metas) {
317+
io_meta.extra_field_ids = extra_field_ids;
318+
}
228319

229320
// generate commit message
230321
return ToCommitMessage(index_type, field.Id(), range, global_index_io_metas,

0 commit comments

Comments
 (0)