-
Notifications
You must be signed in to change notification settings - Fork 4
add pagination to examples metric #864
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,10 @@ | ||
| import heapq | ||
| import tempfile | ||
| from pathlib import Path | ||
| from typing import Callable | ||
| from typing import Callable, Generator | ||
|
|
||
| import pyarrow as pa | ||
| import pyarrow.compute as pc | ||
|
|
||
| from valor_lite.cache.ephemeral import MemoryCacheReader, MemoryCacheWriter | ||
| from valor_lite.cache.persistent import FileCacheReader, FileCacheWriter | ||
|
|
@@ -50,7 +51,9 @@ def create_sort_key( | |
| batch_iterators = [] | ||
| batches = [] | ||
| for batch_idx, batch_iter in enumerate( | ||
| intermediate_source.iterate_fragments(batch_size=batch_size) | ||
| intermediate_source.iterate_fragment_batch_iterators( | ||
| batch_size=batch_size | ||
| ) | ||
| ): | ||
| batch_iterators.append(batch_iter) | ||
| batches.append(next(batch_iterators[batch_idx], None)) | ||
|
|
@@ -152,3 +155,57 @@ def sort( | |
| columns=columns, | ||
| table_sort_override=table_sort_override, | ||
| ) | ||
|
|
||
|
|
||
| def paginate_index( | ||
| source: MemoryCacheReader | FileCacheReader, | ||
| column_key: str, | ||
| modifier: pc.Expression | None = None, | ||
| limit: int | None = None, | ||
| offset: int = 0, | ||
| ) -> Generator[pa.Table, None, None]: | ||
| """ | ||
| Iterate through a paginated cache reader. | ||
|
|
||
| Note this function expects unqiue keys to be fragment-aligned. | ||
| """ | ||
| total = source.count_rows() | ||
| limit = limit if limit else total | ||
|
|
||
| # pagination broader than data scope | ||
| if offset == 0 and limit >= total: | ||
| for tbl in source.iterate_tables(filter=modifier): | ||
| yield tbl | ||
| return | ||
| elif offset >= total: | ||
| return | ||
|
|
||
| curr_idx = 0 | ||
| for tbl in source.iterate_tables(filter=modifier): | ||
| if tbl.num_rows == 0: | ||
| continue | ||
|
|
||
| # sort the unique keys as they may be out of order | ||
| unique_values = pc.unique(tbl[column_key]).sort() # type: ignore[reportAttributeAccessIssue] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Docstring says unique keys should be fragment aligned and in ascending order. So why sort here? Are
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ive added a comment to better document this |
||
| n_unique = len(unique_values) | ||
| prev_idx = curr_idx | ||
| curr_idx += n_unique | ||
|
|
||
| # check for page overlap | ||
| if curr_idx <= offset: | ||
| continue | ||
| elif prev_idx >= (offset + limit): | ||
| return | ||
|
|
||
| # apply any pagination conditions | ||
| condition = pc.scalar(True) | ||
| if prev_idx < offset and curr_idx > offset: | ||
| condition &= ( | ||
| pc.field(column_key) >= unique_values[offset - prev_idx] | ||
| ) | ||
| if prev_idx < (offset + limit) and curr_idx > (offset + limit): | ||
| condition &= ( | ||
| pc.field(column_key) < unique_values[offset + limit - prev_idx] | ||
| ) | ||
|
|
||
| yield tbl.filter(condition) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the iterator return tables always in the same order? Is the order compatible with the ordering on
column_key? (Or does that even matter, seems like it might not as long as it's always the same and keys don't span fragments?)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All iterators operate over the underlying cache fragment files in order (e.g. 0000, 0001, 0002, ...).
For the use case of paginating datums there is no interaction. For the primary ingestion cache, each fragment file is datum aligned and there is no rollover.
This fragment-aligned behavior is not the case for other columns and other ranked caches which is why this function lives in
compute.pyand not directly on the cache readers.