Applies to VAST Cluster 5.5.
The Catalog answers "where are the files that…" without walking directories. This guide shows the filters you'll use most: by path, type, age, size, owner and extension, and how to combine them so the cluster does the filtering.
Each code block is complete on its own. They read your connection settings from the environment, as in the quickstart, and use CATALOG_PATH as the subtree to search.
Filter on the cluster
Every example follows the same pattern:
search_pathrestricts the query to a subtree. Use it in every query, so the cluster reads only that part of the Catalog. See search_path.predicate=with filters the SDK can push down: comparisons,isin,between,startswith,containsandisnull, combined with&and|. The cluster applies them before it sends any rows. See pushdowns.columns=lists only the columns you'll use.
Then sort, count or sum the result in your client.
By age and size
Find files under your path that haven't been modified for 90 days and are larger than 10 MB. This needs at least one such file to return rows:
import os
from datetime import datetime, timedelta, timezone
import pyarrow.compute as pc
import vastdb
from ibis import _
path = os.environ.get("CATALOG_PATH", "/")
cutoff = datetime.now(timezone.utc).replace(tzinfo=None) - timedelta(days=90)
session = vastdb.connect()
with session.transaction() as tx:
rows = tx.catalog().select(
columns=["parent_path", "name", "size", "mtime"],
predicate=(_.search_path == path)
& (_.element_type == "FILE")
& (_.mtime < cutoff)
& (_.size > 10 * 1024**2),
).read_all()
print(rows.num_rows, "files")
oldest = rows.sort_by([("mtime", "ascending")]).slice(0, 10)
# Catalog times have nanosecond precision, finer than Python's datetime, so format them in Arrow.
when = pc.strftime(oldest["mtime"], format="%Y-%m-%d").to_pylist()
for row, t in zip(oldest.drop_columns(["mtime"]).to_pylist(), when):
print(f"{t} {row['size']:>14,} {row['parent_path']}{row['name']}")
1 files
2026-02-01 26,214,400 /cat-data/archive/2025/sensor-dump.bin
The Catalog has four timestamps: creation_time (when the element was created), mtime (last modification of its data), ctime (last change to its metadata) and atime (last access). Pick the one that matches your question. Whether atime is kept up to date depends on how the view is set up, so check with your platform team before you report on "not accessed since". The timestamps are UTC, although their type carries no time zone, so compare them with UTC times, as the examples do. They have nanosecond precision, which Python's datetime can't hold: format them with pyarrow.compute.strftime (as above), or cast them, before you convert them to Python values.
Created recently, by one owner
Find files a user created in the last 7 days. Set CATALOG_OWNER to a user name that owns files under your path:
import os
from datetime import datetime, timedelta, timezone
import vastdb
from ibis import _
path = os.environ.get("CATALOG_PATH", "/")
owner = os.environ["CATALOG_OWNER"]
since = datetime.now(timezone.utc).replace(tzinfo=None) - timedelta(days=7)
session = vastdb.connect()
with session.transaction() as tx:
rows = tx.catalog().select(
columns=["parent_path", "name", "creation_time"],
predicate=(_.search_path == path)
& (_.element_type == "FILE")
& (_.owner_name == owner)
& (_.creation_time >= since),
).read_all()
print(rows.num_rows, "files created by", owner, "since", since.date())
23 files created by cat-app since 2026-10-02
owner_name is the owner's user name. You can filter on uid (POSIX), owner_sid (SMB) or login_name instead, depending on how the data was written. The schema reference describes each owner column.
By extension
Find log and CSV files with isin, which pushes down as an OR of equalities. This needs files with those extensions under your path:
import os
import vastdb
from ibis import _
path = os.environ.get("CATALOG_PATH", "/")
session = vastdb.connect()
with session.transaction() as tx:
rows = tx.catalog().select(
columns=["extension", "size"],
predicate=(_.search_path == path)
& (_.element_type == "FILE")
& _.extension.isin(["log", "csv"]),
).read_all()
totals = rows.group_by("extension").aggregate([("size", "count"), ("size", "sum")])
for row in totals.to_pylist():
print(f"{row['extension']:<6} {row['size_count']:>8,} files {row['size_sum']:>16,} bytes")
csv 5 files 1,465,344 bytes
log 5 files 377,856 bytes
By name and directory
startswith and contains push down on string columns. Find files whose name contains report in directories that start with your path:
import os
import vastdb
from ibis import _
path = os.environ.get("CATALOG_PATH", "/")
session = vastdb.connect()
with session.transaction() as tx:
rows = tx.catalog().select(
columns=["parent_path", "name"],
predicate=(_.search_path == path)
& (_.element_type == "FILE")
& _.parent_path.startswith(path)
& _.name.contains("report"),
limit_rows=20,
).read_all()
for row in rows.to_pylist():
print(row["parent_path"] + row["name"])
limit_rows stops the query after that many rows, which is handy when you only want to see a sample. Which rows you get isn't defined.
Filters that don't push down
Some filters can't be sent to the cluster. The SDK raises NotImplementedError showing your expression, rather than filtering in your client without telling you. Common cases with the Catalog:
- A key inside a map column, such as one tag in
user_tags. Fetch the map and filter in your client, or ask for a user-defined column. See tags and metadata. - Arithmetic or functions on a column, such as
_.size / 1024 > 10. Rewrite it as a comparison on the column itself:_.size > 10 * 1024. - Comparing two columns, such as
_.mtime > _.creation_time. Fetch both and compare in your client.
See rewrite filters that don't push down.
See also
- Capacity reports: sum sizes by owner, extension or directory.
- Catalog schema.
- Trino and Spark: the same queries in SQL.