Skip to the page

Databricks interview question · easy

Starfire needs to create a rolling average over a time series dataset in a Delta table. However, the data contains gaps (missing timestamps). How can she use Databricks SQL's window functions or other Databricks-specific features to handle these gaps and ensure accurate rolling average calculations?

The short answerStarfire needs to be careful when calculating rolling averages on time series data with gaps.

The full answer

Starfire needs to be careful when calculating rolling averages on time series data with gaps. Standard window functions in SQL can produce misleading results if gaps aren't handled correctly. Here's how she can address this in Databricks SQL:

1. Using ROWS BETWEEN for Fixed-Size Windows (Simplest, but Doesn't Handle Gaps Well):

If Starfire doesn't need to account for the gaps (i.e., she wants a rolling average over the last n rows regardless of the time difference between them), she can use a standard window function:

SELECT
    timestamp_column,
    value_column,
    AVG(value_column) OVER (ORDER BY timestamp_column ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS rolling_avg_3_rows
FROM
    your_delta_table;

However, as stated, this approach is not suitable for accurate time-based rolling averages with gaps.

2. Using RANGE BETWEEN for Time-Based Windows (Better, but Still Has Limitations):

RANGE BETWEEN allows specifying a time range for the window. However, with gaps, it can still lead to incorrect averages if the gaps are large.

SELECT
    timestamp_column,
    value_column,
    AVG(value_column) OVER (ORDER BY timestamp_column RANGE BETWEEN INTERVAL 2 DAY PRECEDING AND CURRENT ROW) AS rolling_avg_2_days
FROM
    your_delta_table;

This will include all rows within the last two days. If there's a large gap, it will average over a longer effective period.

3. Generating a Complete Time Series and Using LEFT JOIN (Most Accurate):

This is the most robust way to handle gaps.

  • Generate a Time Series: Create a table or CTE (Common Table Expression) containing all the timestamps within the desired range.
WITH time_series AS (
    SELECT explode(sequence(min(timestamp_column), max(timestamp_column), interval 1 day)) AS timestamp_day
    FROM your_delta_table
)
SELECT ts.timestamp_day, COALESCE(yt.value_column, 0) as value_column
FROM time_series ts
LEFT JOIN your_delta_table yt ON date(ts.timestamp_day) = date(yt.timestamp_column)
ORDER BY ts.timestamp_day;

This generates a time series with daily intervals. Adjust the interval as needed (e.g., interval 1 hour, interval 1 minute). The COALESCE function handles missing values by filling them with 0 (or any other appropriate value).

  • Calculate Rolling Average: Now that you have a complete time series, you can use a window function:
WITH time_series AS (
    SELECT explode(sequence(min(timestamp_column), max(timestamp_column), interval 1 day)) AS timestamp_day
    FROM your_delta_table
),
filled_data AS (
SELECT ts.timestamp_day, COALESCE(yt.value_column, 0) as value_column
FROM time_series ts
LEFT JOIN your_delta_table yt ON date(ts.timestamp_day) = date(yt.timestamp_column)
ORDER BY ts.timestamp_day
)
SELECT
    timestamp_day,
    value_column,
    AVG(value_column) OVER (ORDER BY timestamp_day RANGE BETWEEN INTERVAL 2 DAY PRECEDING AND CURRENT ROW) AS rolling_avg_2_days
FROM filled_data;

4. Using fill() with RANGE BETWEEN (Alternative for Simpler Cases):

If the gaps are not too large and you want to fill the missing values with the previous available value, you can use the fill() function.

SELECT
    timestamp_column,
    value_column,
    LAST(value_column, true) OVER (ORDER BY timestamp_column RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as filled_value,
    AVG(value_column) OVER (ORDER BY timestamp_column RANGE BETWEEN INTERVAL 2 DAY PRECEDING AND CURRENT ROW) AS rolling_avg_2_days
FROM your_delta_table;

This method is simpler than generating the whole time series but might not be appropriate if you need to handle gaps in a different way (e.g., filling with 0).

Recommendation:

For accurate rolling averages on time series data with gaps, generating a complete time series using sequence() and LEFT JOIN (method 3) is the most reliable approach. This ensures that the rolling average is calculated over the correct time period, regardless of missing data points. The fill() function can be a good alternative if you simply want to fill the gaps with the last known value and the gaps are not too significant.

Last updated 17 January 2025

Asked next