blob: 4bf2103f0b1ab6c087601aa00a019ada3205b8fc [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.
"""The ``$table_indexes`` system table."""
from typing import Dict, List, Optional
import pyarrow
from pypaimon.index.index_file_handler import IndexFileHandler
from pypaimon.schema.data_types import (ArrayType, AtomicType, DataField,
RowType)
from pypaimon.table.system.files_table import _render_partition
from pypaimon.table.system.system_table import SystemTable
_DV_RANGE_ROW_TYPE = RowType(False, [
DataField(0, "f0", AtomicType("STRING", nullable=False)),
DataField(1, "f1", AtomicType("INT", nullable=False)),
DataField(2, "f2", AtomicType("INT", nullable=False)),
DataField(3, "_CARDINALITY", AtomicType("BIGINT", nullable=True)),
])
_DV_RANGES_TYPE = pyarrow.list_(pyarrow.struct([
pyarrow.field("f0", pyarrow.string(), nullable=False),
pyarrow.field("f1", pyarrow.int32(), nullable=False),
pyarrow.field("f2", pyarrow.int32(), nullable=False),
pyarrow.field("_CARDINALITY", pyarrow.int64(), nullable=True),
]))
TABLE_TYPE = RowType(False, [
DataField(0, "partition", AtomicType("STRING", nullable=True)),
DataField(1, "bucket", AtomicType("INT", nullable=False)),
DataField(2, "index_type", AtomicType("STRING", nullable=False)),
DataField(3, "file_name", AtomicType("STRING", nullable=False)),
DataField(4, "file_size", AtomicType("BIGINT", nullable=False)),
DataField(5, "row_count", AtomicType("BIGINT", nullable=False)),
DataField(
6,
"dv_ranges",
ArrayType(nullable=True,
element_type=_DV_RANGE_ROW_TYPE)),
DataField(7, "row_range_start", AtomicType("BIGINT", nullable=True)),
DataField(8, "row_range_end", AtomicType("BIGINT", nullable=True)),
DataField(9, "index_field_id", AtomicType("INT", nullable=True)),
DataField(10, "index_field_name", AtomicType("STRING", nullable=True)),
])
class TableIndexesTable(SystemTable):
"""The ``$table_indexes`` system table."""
def system_table_name(self) -> str:
return "table_indexes"
def row_type(self) -> RowType:
return TABLE_TYPE
def primary_keys(self) -> List[str]:
return ["file_name"]
def _build_arrow_table(self) -> pyarrow.Table:
snapshot = self.base_table.snapshot_manager().get_latest_snapshot()
entries = IndexFileHandler(self.base_table).scan(snapshot)
rows = {
"partition": [],
"bucket": [],
"index_type": [],
"file_name": [],
"file_size": [],
"row_count": [],
"dv_ranges": [],
"row_range_start": [],
"row_range_end": [],
"index_field_id": [],
"index_field_name": [],
}
for entry in entries:
index_file = entry.index_file
global_meta = index_file.global_index_meta
rows["partition"].append(_render_partition(entry.partition))
rows["bucket"].append(int(entry.bucket))
rows["index_type"].append(index_file.index_type)
rows["file_name"].append(index_file.file_name)
rows["file_size"].append(int(index_file.file_size))
rows["row_count"].append(int(index_file.row_count))
rows["dv_ranges"].append(_render_dv_ranges(index_file.dv_ranges))
rows["row_range_start"].append(
None if global_meta is None
else int(global_meta.row_range_start))
rows["row_range_end"].append(
None if global_meta is None
else int(global_meta.row_range_end))
rows["index_field_id"].append(
None if global_meta is None
else int(global_meta.index_field_id))
rows["index_field_name"].append(
None if global_meta is None
else _index_field_names(self.base_table, global_meta))
return pyarrow.table({
"partition": pyarrow.array(
rows["partition"], type=pyarrow.string()),
"bucket": pyarrow.array(rows["bucket"], type=pyarrow.int32()),
"index_type": pyarrow.array(
rows["index_type"], type=pyarrow.string()),
"file_name": pyarrow.array(
rows["file_name"], type=pyarrow.string()),
"file_size": pyarrow.array(
rows["file_size"], type=pyarrow.int64()),
"row_count": pyarrow.array(
rows["row_count"], type=pyarrow.int64()),
"dv_ranges": pyarrow.array(
rows["dv_ranges"], type=_DV_RANGES_TYPE),
"row_range_start": pyarrow.array(
rows["row_range_start"], type=pyarrow.int64()),
"row_range_end": pyarrow.array(
rows["row_range_end"], type=pyarrow.int64()),
"index_field_id": pyarrow.array(
rows["index_field_id"], type=pyarrow.int32()),
"index_field_name": pyarrow.array(
rows["index_field_name"], type=pyarrow.string()),
})
def _render_dv_ranges(dv_ranges) -> Optional[List[Dict[str, object]]]:
if not dv_ranges:
return None
rendered = []
for meta in dv_ranges.values():
rendered.append({
"f0": meta.data_file_name,
"f1": int(meta.offset),
"f2": int(meta.length),
"_CARDINALITY": (
None if meta.cardinality is None else int(meta.cardinality)
),
})
return rendered
def _index_field_names(table, global_meta) -> Optional[str]:
field_by_id = {field.id: field.name for field in table.fields}
field_ids = [global_meta.index_field_id]
if global_meta.extra_field_ids:
field_ids.extend(global_meta.extra_field_ids)
names = []
for field_id in field_ids:
name = field_by_id.get(field_id)
if name is None:
return None
names.append(name)
return ",".join(names)