blob: 01452db50809d8da50d7b30ed94754d7bc01f475 [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.
"""Convert public Python split values for Native execution."""
from pypaimon.read import split_serializer
def _native_read_split(split, ranges_use_row_ids):
"""Express Python's file slices with the existing indexed-split selector."""
from pypaimon.globalindex.indexed_split import IndexedSplit
from pypaimon.read.query_auth_split import QueryAuthSplit
from pypaimon.read.sliced_split import SlicedSplit
from pypaimon.utils.range import Range
def select_rows(base, ranges):
if isinstance(base, QueryAuthSplit):
return QueryAuthSplit(select_rows(base.split, ranges), base.auth_result)
if isinstance(base, IndexedSplit):
return select_rows(base.data_split(), Range.and_(base.row_ranges(), ranges))
return IndexedSplit(base, ranges)
if isinstance(split, QueryAuthSplit):
base = _native_read_split(split.split, ranges_use_row_ids)
return split if base is split.split else QueryAuthSplit(base, split.auth_result)
if isinstance(split, IndexedSplit):
base = _native_read_split(split.data_split(), ranges_use_row_ids)
return split if base is split.data_split() else select_rows(base, split.row_ranges())
if not isinstance(split, SlicedSplit):
return split
if ranges_use_row_ids is None:
raise ValueError('Native file-slice conversion requires the reader row-tracking mode')
ranges = []
offset = 0
slices = split.shard_file_idx_map()
for file in split.files:
start, end = slices.get(file.file_name, (0, file.row_count))
start, end = max(0, start), min(file.row_count, end)
if start < end:
base = file.first_row_id if ranges_use_row_ids else offset
if base is None:
raise ValueError("Row-tracked file '%s' is missing first_row_id" % file.file_name)
ranges.append(Range(base + start, base + end - 1))
offset += file.row_count
return select_rows(_native_read_split(split.data_split(), ranges_use_row_ids), ranges)
def native_split_from_python(split, *, ranges_use_row_ids=None):
"""Convert a Python-planned split for the Rust reader.
Vector scores intentionally stay on the Python IndexedSplit. Rust needs
only its row ranges to perform the physical read. File slices need the
reader's tracking mode to map their local offsets to those ranges.
"""
from pypaimon_rust.datafusion import Split as NativeSplit
return NativeSplit.deserialize(split_serializer.serialize_split_v1(
_native_read_split(split, ranges_use_row_ids), include_scores=False))