Skip to main content

Sampler Module

The sampler module lives at ingestion/src/metadata/sampler/. It provides a unified interface for sampling data from tables across different database backends. Both the profiler and data quality modules depend on the sampler to get a representative subset of rows for computing metrics and running tests.

Directory Layout

How It Fits Together

The sampler sits between the data source and the profiler/data quality modules:

Core Abstraction

SamplerInterface (sampler_interface.py) is the abstract base class all samplers extend.

Key Methods

Constructor Parameters

Data Models

Defined in models.py:

Sampling Strategies

Percentage-Based Sampling

The default strategy. Takes X% of rows from the table. With randomization (default):
With TABLESAMPLE (database-specific):

Row-Count-Based Sampling

Takes exactly N rows. With randomization:
Without randomization:
Snowflake row-based:

Database-Specific Overrides

Each database sampler can override set_tablesample() to use the database’s native sampling:

Partition Handling

partition.py detects and configures partition filtering so the sampler only reads relevant partitions:
When partitions are configured, the sampler creates a CTE filtered by the partition predicate before applying sampling:

Configuration Resolution

config.py provides hierarchical config lookup (table → schema → database → default):
This means an admin can set a global “sample 50% of all tables” default, override it to “sample 10% for schema X”, and further override to “sample 1000 rows for table Y”.

Notable Database-Specific Behavior

TimescaleDB — Compressed Chunk Awareness

TimescaleDB compresses old data into compressed chunks. Decompressing during profiling would be extremely expensive. The TimescaleDB sampler:
  1. Queries TimescaleDB metadata to find the boundary between compressed and uncompressed chunks
  2. Adds a filter WHERE time_col >= uncompressed_boundary to the sample query
  3. Only samples from uncompressed (recent) data

Databricks — Array Column Slicing

Large array columns can cause OOM errors. The Databricks sampler:
  1. Detects CustomArray type columns
  2. Replaces them with slice(col, 1, N) in the SELECT to limit array elements
  3. Converts numpy arrays back to Python lists in results

BigQuery — Struct Column Handling

BigQuery struct columns (nested fields like address.city) require special handling:
  1. Detects struct columns via _handle_struct_columns()
  2. Builds queries that properly reference nested fields
  3. Handles project ID correction from entity database name

Trino — NaN Filtering

Trino float columns can contain NaN values that break downstream processing:
  1. Identifies float columns via FLOAT_SET registry
  2. Wraps float columns in CASE WHEN IS_NAN(col) THEN NULL ELSE col END

Pandas / Datalake Sampler

For non-SQL sources, DatalakeSampler works with DataFrames:
Supports:
  • Partitioned DataFrames via get_partitioned_df()
  • Custom queries via get_sampled_query_dataframe()
  • Chunked processing via DataFrame iterators
  • NaN value filtering

NoSQL Sampler

For NoSQL databases (MongoDB, DynamoDB), NoSQLSampler:
  • Uses NoSQLAdaptor to abstract database-specific operations
  • Converts percentage to row count: num_rows * (profileSample / 100)
  • Calls client.scan(limit=N) for sampling
  • Transposes list-of-dicts format into columnar TableData

Adding a Database-Specific Sampler

1

Create the sampler file

Create sampler/sqlalchemy/{dialect}/sampler.py.Extend SQASampler and override set_tablesample():
2

Register the sampler

The sampler is discovered via import_sampler_class() which resolves the class dynamically based on the database service type. Ensure your module path follows the convention:
3

Handle edge cases

Override additional methods if your database needs special handling:
  • _base_sample_query() — customize the core sampling query
  • fetch_sample_data() — customize how rows are fetched
  • _handle_array_column() — if your database has array types that need slicing

Key Design Patterns

Key Files Quick Reference

All paths above are relative to ingestion/src/metadata/. For example, sqlalchemy/sampler.py means ingestion/src/metadata/sampler/sqlalchemy/sampler.py.