From ce06e4e98aa98440bbd701f43efb74664860de29 Mon Sep 17 00:00:00 2001 From: Agnes Kiss Date: Thu, 13 Aug 2026 18:10:55 +0100 Subject: [PATCH 1/3] Update warehouse docs --- .../attributes/attribute-groups/index.md | 2 +- .../attributes/warehouse-config/index.md | 52 ++++++++++++------ docs/signals/concepts/index.md | 4 ++ docs/signals/get-started/index.md | 2 +- docs/signals/images/warehouse-config.png | Bin 0 -> 67657 bytes docs/signals/setup/index.md | 2 +- 6 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 docs/signals/images/warehouse-config.png diff --git a/docs/signals/attributes/attribute-groups/index.md b/docs/signals/attributes/attribute-groups/index.md index 090a1b228..ff76c1394 100644 --- a/docs/signals/attributes/attribute-groups/index.md +++ b/docs/signals/attributes/attribute-groups/index.md @@ -89,7 +89,7 @@ Stream attribute groups only calculate attributes from the moment they are publi :::note[Warehouse connection] -A warehouse connection is required to use the backfill option. Only Snowflake and BigQuery are supported currently. +A warehouse connection is required to use the backfill option. Snowflake, BigQuery, and Databricks are supported currently. ::: Enable **Backfill attributes** when creating the group. A date picker appears — select the date from which Signals should backfill attribute values from your Snowplow `atomic` events table. On publish, Signals backfills all events from that date up to the publish timestamp using your warehouse. diff --git a/docs/signals/attributes/warehouse-config/index.md b/docs/signals/attributes/warehouse-config/index.md index 064358a87..6dab32b92 100644 --- a/docs/signals/attributes/warehouse-config/index.md +++ b/docs/signals/attributes/warehouse-config/index.md @@ -17,8 +17,6 @@ To sync existing, pre-calculated attributes from your warehouse to Signals, conf If your source data comes from Snowplow events, consider using a stream attribute group with the backfill option enabled instead. It gives you real-time updates from your event stream alongside historical backfill, without needing to maintain a separate warehouse table. Attributes that are fetched from a warehouse are best suited for pre-calculated values from non-Snowplow sources, or tables that already exist independently of your event pipeline. ::: -## Provide source table details - @@ -26,14 +24,36 @@ When creating an attribute group, select **Warehouse** as the data source. ![Create attribute group form showing where to select the Warehouse data source in Snowplow Console](../../images/warehouse.png) -Then provide the warehouse and table details, and select which fields you want to send to Signals. +### Provide the basic configuration + +Select the `attribute key` you have data for. The [attribute key](/docs/signals/attributes/attribute-keys/index.md) for the group must correspond to a column in the table that contains the key values. + +Decide on how long you would like the data to persist in the profile store by setting the `TTL`. + +By default, the updates will run on an hourly basis, which you can adjust to a lower cadence by the `sync frequency` selector (6h, 12h, 24h). + +You must also specify a `backfill start date`, the earliest date from which Signals should read rows on the first sync. + +![Create attribute group form showing where to add basic warehouse configuration in Snowplow Console](../../images/warehouse-config.png) + +### Define which fields to sync + +Select which `table` to sync from. + +Choose the `Modified date` column: the column that tells when a particular row was last written or updated in the table (for example, a `load_tstamp` or `updated_at` column populated by your ETL process on every write). The Modified date column must be in UTC. A column in local time will cause rows to be silently matched against the wrong sync window, with no error raised. If multiple rows exist for the same attribute key within a sync period, the engine uses the row with the latest `Modified date` value. + +:::warning +Avoid using a business or event timestamp that doesn't change when a row is reloaded or updated to avoid data being missed. +::: + +Finally, select which `table fields` you want to send to Signals. ![Warehouse source configuration showing warehouse table and field mapping options](../../images/attribute-group-warehouse-fields.png) -Configure which table to sync by specifying a `BatchSource` object. +Start by configuring which table to sync by specifying a `BatchSource` object. ```python from snowplow_signals import BatchSource @@ -57,25 +77,19 @@ The table below lists all available arguments for a `BatchSource`: | `database` | The database where the attributes are stored | `string` | ✅ | | `schema` | The schema for the table of interest | `string` | ✅ | | `table` | The table where the attributes are stored | `string` | ✅ | -| `timestamp_field` | Primary timestamp of the attribute value, indicating data freshness | `string` | ❌ | +| `timestamp_field` | Primary timestamp of the attribute value, indicating data freshness | `string` | ✅ | | `owner` | The owner of the source | `string` | ❌ | -The batch engine only sends rows with a newer timestamp to the Profiles Store, based on the `timestamp_field`. If multiple rows exist for the same attribute key within a sync period, the engine uses the row with the greatest `timestamp_field` value. - - - - -## Define which fields to sync +The batch engine uses `timestamp_field` as the change-watermark for incremental syncs — it must reflect when a row was actually last written or updated in the table (for example, a `load_tstamp` or `updated_at` column populated by your ETL process on every write), not a business or event timestamp that stays fixed once set. `timestamp_field` must be in UTC, a column in local time will cause rows to be silently matched against the wrong sync window, with no error raised. - - +If multiple rows exist for the same attribute key within a sync period, the engine uses the row with the greatest `timestamp_field` value. -Select the fields (columns) from your warehouse table that you want to sync to the Profiles Store. You must also specify a backfill start date — the earliest date from which Signals should read rows on the first sync. +:::warning +Avoid using a business or event timestamp that doesn't change when a row is reloaded or updated — Signals won't be able to tell the row has changed, and the data may be missed. +::: -The [attribute key](/docs/signals/attributes/attribute-keys/index.md) for the group must correspond to a column in the table that contains the key values. - - +### Define which fields to sync Use `ExternalBatchAttributeGroup` to define which source table and fields to use. Instead of `attributes`, this class uses `fields` — abstractions over the warehouse columns. @@ -84,7 +98,7 @@ You must set `backfill_since_tstamp` to tell the batch engine the earliest times The attribute key must correspond to a column in the source table. The example below uses the built-in `domain_userid` key, so the table must have a `domain_userid` column. To key on a different column, [define a custom attribute key](/docs/signals/attributes/attribute-keys/index.md#custom-attribute-keys) with `external_column` set to the column name. ```python -from datetime import datetime, timezone +from datetime import datetime, timedelta, timezone from snowplow_signals import ExternalBatchAttributeGroup, domain_userid, Field attribute_group = ExternalBatchAttributeGroup( @@ -94,6 +108,7 @@ attribute_group = ExternalBatchAttributeGroup( owner="user@company.com", batch_source=data_source, backfill_since_tstamp=datetime(2026, 6, 1, tzinfo=timezone.utc), + refresh_rate=timedelta(hours=6), fields=[ Field(name="TOTAL_TRANSACTIONS", type="int32"), Field(name="TOTAL_REVENUE", type="int32"), @@ -111,6 +126,7 @@ The table below lists all available arguments for `ExternalBatchAttributeGroup`: | `attribute_key` | The key used to identify profiles. Its name must match a column in the source table | `AttributeKey` | ✅ | | `batch_source` | The `BatchSource` defining the warehouse table to sync from | `BatchSource` | ✅ | | `backfill_since_tstamp` | The earliest timestamp from which to read rows on the first sync. Accepts tz-aware or naive UTC `datetime`; tz-aware is recommended. | `datetime` | ✅ | +| `refresh_rate` | How frequently the attribute group should be synced (e.g. `timedelta(hours=1)`, `timedelta(hours=6)`, `timedelta(days=1)`). Defaults to hourly. | `timedelta` | ❌ | | `fields` | The list of `Field` objects defining which columns to sync | `list` | ✅ | | `description` | A description of the attribute group | `string` | ❌ | | `owner` | The owner of the attribute group | `string` | ❌ | diff --git a/docs/signals/concepts/index.md b/docs/signals/concepts/index.md index e814866c1..84c95bad5 100644 --- a/docs/signals/concepts/index.md +++ b/docs/signals/concepts/index.md @@ -117,6 +117,10 @@ Stream attribute groups by default only calculate attributes from the moment the When backfill is enabled, you select a start date. On publish, Signals uses your Snowplow `atomic` events table to calculate attribute values for all events from that date up to the publish timestamp. The streaming engine starts immediately and processes all new events in real time. Backfill operates within this defined period and can take some time depending on data volume. Once backfill completes, only the streaming engine remains active. +:::info +When backfilling, the events table filtered on the `load_tstamp` column, since this is typically the partition or cluster key on Snowplow-loaded event tables (by default, or per deployment's instructions). Filtering on it allows queries to prune partitions efficiently. +::: + You can monitor progress in Snowplow Console on the attribute group's details page. While historical values are syncing, a status bar labeled `Backfill in progress` is shown. This status remains visible until the backfill period has completed. ![Backfill progress status bar shown for stream with backfill attribute groups](../images/backfill_progress.png) diff --git a/docs/signals/get-started/index.md b/docs/signals/get-started/index.md index fff0c6548..3eae37d04 100644 --- a/docs/signals/get-started/index.md +++ b/docs/signals/get-started/index.md @@ -31,7 +31,7 @@ If you don't have a Snowplow account yet, sign up for a [Snowplow free trial](ht You will need a [Snowplow pipeline](/docs/get-started/index.md) to use Signals. Your Signals infrastructure is deployed into the same cloud as your pipeline. :::note[Warehouse support] -Only Snowflake and BigQuery are supported currently. However, you can also use Signals without the warehouse functionality. +Snowflake, BigQuery, and Databricks are supported currently. However, you can also use Signals without the warehouse functionality. ::: Signals consists of several new infrastructure components. When running Signals, your Snowplow pipeline will continue to process events as usual. diff --git a/docs/signals/images/warehouse-config.png b/docs/signals/images/warehouse-config.png new file mode 100644 index 0000000000000000000000000000000000000000..f505926351944aa7fcfe82b284d255d11ab8d2db GIT binary patch literal 67657 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 NbISx0 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 literal 0 HcmV?d00001 diff --git a/docs/signals/setup/index.md b/docs/signals/setup/index.md index 7f0a078b9..a48c555ed 100644 --- a/docs/signals/setup/index.md +++ b/docs/signals/setup/index.md @@ -20,7 +20,7 @@ Log in to Console and navigate to the **Signals** section. Click **Enable** to s ![Snowplow Console Signals section showing Enable button to set up connection](../images/console-no-connection.png) :::note[Warehouse connection] -Signals can also be deployed without connecting to a warehouse. Only Snowflake and BigQuery are supported currently. +Signals can also be deployed without connecting to a warehouse. Snowflake, BigQuery, and Databricks are supported currently. ::: You'll need to: From 4bb8fc6043479ffc6c91d3354f847a4584702368 Mon Sep 17 00:00:00 2001 From: Agnes Kiss Date: Thu, 13 Aug 2026 18:48:19 +0100 Subject: [PATCH 2/3] Claude fixes --- .../attributes/attribute-groups/index.md | 2 +- .../attributes/warehouse-config/index.md | 27 ++++++++++--------- docs/signals/concepts/index.md | 4 +-- docs/signals/get-started/index.md | 2 +- docs/signals/setup/index.md | 2 +- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/docs/signals/attributes/attribute-groups/index.md b/docs/signals/attributes/attribute-groups/index.md index ff76c1394..e94bc49d9 100644 --- a/docs/signals/attributes/attribute-groups/index.md +++ b/docs/signals/attributes/attribute-groups/index.md @@ -89,7 +89,7 @@ Stream attribute groups only calculate attributes from the moment they are publi :::note[Warehouse connection] -A warehouse connection is required to use the backfill option. Snowflake, BigQuery, and Databricks are supported currently. +A warehouse connection is required to use the backfill option. Snowflake, BigQuery, and Databricks are supported. ::: Enable **Backfill attributes** when creating the group. A date picker appears — select the date from which Signals should backfill attribute values from your Snowplow `atomic` events table. On publish, Signals backfills all events from that date up to the publish timestamp using your warehouse. diff --git a/docs/signals/attributes/warehouse-config/index.md b/docs/signals/attributes/warehouse-config/index.md index 6dab32b92..2ec6e7683 100644 --- a/docs/signals/attributes/warehouse-config/index.md +++ b/docs/signals/attributes/warehouse-config/index.md @@ -17,6 +17,8 @@ To sync existing, pre-calculated attributes from your warehouse to Signals, conf If your source data comes from Snowplow events, consider using a stream attribute group with the backfill option enabled instead. It gives you real-time updates from your event stream alongside historical backfill, without needing to maintain a separate warehouse table. Attributes that are fetched from a warehouse are best suited for pre-calculated values from non-Snowplow sources, or tables that already exist independently of your event pipeline. ::: +## Configure a warehouse source + @@ -26,27 +28,27 @@ When creating an attribute group, select **Warehouse** as the data source. ### Provide the basic configuration -Select the `attribute key` you have data for. The [attribute key](/docs/signals/attributes/attribute-keys/index.md) for the group must correspond to a column in the table that contains the key values. +Select the **Attribute key** you have data for. The [attribute key](/docs/signals/attributes/attribute-keys/index.md) for the group must correspond to a column in the table that contains the key values. -Decide on how long you would like the data to persist in the profile store by setting the `TTL`. +Set the **TTL** to control how long the data persists in the Profiles Store. -By default, the updates will run on an hourly basis, which you can adjust to a lower cadence by the `sync frequency` selector (6h, 12h, 24h). +Updates run hourly by default. Use the **Sync frequency** selector to sync less often (6h, 12h, or 24h). -You must also specify a `backfill start date`, the earliest date from which Signals should read rows on the first sync. +You must also specify a **Backfill start date**: the earliest date from which Signals should read rows on the first sync. ![Create attribute group form showing where to add basic warehouse configuration in Snowplow Console](../../images/warehouse-config.png) ### Define which fields to sync -Select which `table` to sync from. +Select which **Table** to sync from. -Choose the `Modified date` column: the column that tells when a particular row was last written or updated in the table (for example, a `load_tstamp` or `updated_at` column populated by your ETL process on every write). The Modified date column must be in UTC. A column in local time will cause rows to be silently matched against the wrong sync window, with no error raised. If multiple rows exist for the same attribute key within a sync period, the engine uses the row with the latest `Modified date` value. +Choose the **Modified date** column: the column that tells when a particular row was last written or updated in the table (for example, a `load_tstamp` or `updated_at` column populated by your ETL process on every write). The **Modified date** column must be in UTC. A column in local time causes rows to be silently matched against the wrong sync window, with no error raised. If multiple rows exist for the same attribute key within a sync period, the engine uses the row with the latest **Modified date** value. -:::warning -Avoid using a business or event timestamp that doesn't change when a row is reloaded or updated to avoid data being missed. +:::warning[Use a last-modified timestamp] +Don't use a business or event timestamp that doesn't change when a row is reloaded or updated. The batch engine won't be able to tell the row has changed, and the data may be missed. ::: -Finally, select which `table fields` you want to send to Signals. +Finally, select which **Table fields** you want to send to Signals. ![Warehouse source configuration showing warehouse table and field mapping options](../../images/attribute-group-warehouse-fields.png) @@ -80,15 +82,14 @@ The table below lists all available arguments for a `BatchSource`: | `timestamp_field` | Primary timestamp of the attribute value, indicating data freshness | `string` | ✅ | | `owner` | The owner of the source | `string` | ❌ | -The batch engine uses `timestamp_field` as the change-watermark for incremental syncs — it must reflect when a row was actually last written or updated in the table (for example, a `load_tstamp` or `updated_at` column populated by your ETL process on every write), not a business or event timestamp that stays fixed once set. `timestamp_field` must be in UTC, a column in local time will cause rows to be silently matched against the wrong sync window, with no error raised. +The batch engine uses `timestamp_field` as the change-watermark for incremental syncs — it must reflect when a row was actually last written or updated in the table (for example, a `load_tstamp` or `updated_at` column populated by your ETL process on every write), not a business or event timestamp that stays fixed once set. `timestamp_field` must be in UTC. A column in local time causes rows to be silently matched against the wrong sync window, with no error raised. If multiple rows exist for the same attribute key within a sync period, the engine uses the row with the greatest `timestamp_field` value. -:::warning -Avoid using a business or event timestamp that doesn't change when a row is reloaded or updated — Signals won't be able to tell the row has changed, and the data may be missed. +:::warning[Use a last-modified timestamp] +Don't use a business or event timestamp that doesn't change when a row is reloaded or updated. The batch engine won't be able to tell the row has changed, and the data may be missed. ::: - ### Define which fields to sync Use `ExternalBatchAttributeGroup` to define which source table and fields to use. Instead of `attributes`, this class uses `fields` — abstractions over the warehouse columns. diff --git a/docs/signals/concepts/index.md b/docs/signals/concepts/index.md index 84c95bad5..d5894f048 100644 --- a/docs/signals/concepts/index.md +++ b/docs/signals/concepts/index.md @@ -117,8 +117,8 @@ Stream attribute groups by default only calculate attributes from the moment the When backfill is enabled, you select a start date. On publish, Signals uses your Snowplow `atomic` events table to calculate attribute values for all events from that date up to the publish timestamp. The streaming engine starts immediately and processes all new events in real time. Backfill operates within this defined period and can take some time depending on data volume. Once backfill completes, only the streaming engine remains active. -:::info -When backfilling, the events table filtered on the `load_tstamp` column, since this is typically the partition or cluster key on Snowplow-loaded event tables (by default, or per deployment's instructions). Filtering on it allows queries to prune partitions efficiently. +:::info[Backfill query performance] +Signals filters the events table on the `load_tstamp` column. This column is typically the partition or cluster key on Snowplow-loaded event tables, so filtering on it lets queries prune partitions efficiently. ::: You can monitor progress in Snowplow Console on the attribute group's details page. While historical values are syncing, a status bar labeled `Backfill in progress` is shown. This status remains visible until the backfill period has completed. diff --git a/docs/signals/get-started/index.md b/docs/signals/get-started/index.md index 3eae37d04..d73277b62 100644 --- a/docs/signals/get-started/index.md +++ b/docs/signals/get-started/index.md @@ -31,7 +31,7 @@ If you don't have a Snowplow account yet, sign up for a [Snowplow free trial](ht You will need a [Snowplow pipeline](/docs/get-started/index.md) to use Signals. Your Signals infrastructure is deployed into the same cloud as your pipeline. :::note[Warehouse support] -Snowflake, BigQuery, and Databricks are supported currently. However, you can also use Signals without the warehouse functionality. +Snowflake, BigQuery, and Databricks are supported. However, you can also use Signals without the warehouse functionality. ::: Signals consists of several new infrastructure components. When running Signals, your Snowplow pipeline will continue to process events as usual. diff --git a/docs/signals/setup/index.md b/docs/signals/setup/index.md index a48c555ed..771cb192e 100644 --- a/docs/signals/setup/index.md +++ b/docs/signals/setup/index.md @@ -20,7 +20,7 @@ Log in to Console and navigate to the **Signals** section. Click **Enable** to s ![Snowplow Console Signals section showing Enable button to set up connection](../images/console-no-connection.png) :::note[Warehouse connection] -Signals can also be deployed without connecting to a warehouse. Snowflake, BigQuery, and Databricks are supported currently. +Signals can also be deployed without connecting to a warehouse. Snowflake, BigQuery, and Databricks are supported. ::: You'll need to: From b05d874543494e306c68288ecebc5a53f10313cf Mon Sep 17 00:00:00 2001 From: Agnes Kiss Date: Mon, 17 Aug 2026 11:08:46 +0100 Subject: [PATCH 3/3] Call out about backfill since calcualtion --- docs/signals/attributes/attribute-groups/index.md | 4 ++-- docs/signals/concepts/index.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/signals/attributes/attribute-groups/index.md b/docs/signals/attributes/attribute-groups/index.md index e94bc49d9..2fffc0c2d 100644 --- a/docs/signals/attributes/attribute-groups/index.md +++ b/docs/signals/attributes/attribute-groups/index.md @@ -92,7 +92,7 @@ Stream attribute groups only calculate attributes from the moment they are publi A warehouse connection is required to use the backfill option. Snowflake, BigQuery, and Databricks are supported. ::: -Enable **Backfill attributes** when creating the group. A date picker appears — select the date from which Signals should backfill attribute values from your Snowplow `atomic` events table. On publish, Signals backfills all events from that date up to the publish timestamp using your warehouse. +Enable **Backfill attributes** when creating the group. A date picker appears — select the date from which Signals should backfill attribute values from your Snowplow `atomic` events table. On publish, Signals backfills all events from that date up to the publish timestamp using your warehouse, based on the `load_tstamp` column. Backfill operates within a defined period: from your selected start date to the publish timestamp. This can take some time depending on data volume. The streaming engine starts immediately on publish and processes all new events in real time. Once backfill completes its defined period, only the streaming engine is active. You can monitor progress with the status bar in Snowplow Console. @@ -101,7 +101,7 @@ Backfill operates within a defined period: from your selected start date to the -Set `backfill_since_tstamp` on your `StreamAttributeGroup` to specify the earliest date to backfill from. +Set `backfill_since_tstamp` on your `StreamAttributeGroup` to specify the earliest date to backfill from. This date is matched against the `load_tstamp` column of your Snowplow `atomic` events table, the time each event was loaded into your warehouse. ```python from datetime import datetime, timezone diff --git a/docs/signals/concepts/index.md b/docs/signals/concepts/index.md index d5894f048..09b9f99d4 100644 --- a/docs/signals/concepts/index.md +++ b/docs/signals/concepts/index.md @@ -115,10 +115,10 @@ Real-time stream flow: Stream attribute groups by default only calculate attributes from the moment they are published. If you would like to pre-populate your attributes with values from your warehouse, you can optionally enable backfill when creating the group. Backfilling stream attributes requires a warehouse connection. -When backfill is enabled, you select a start date. On publish, Signals uses your Snowplow `atomic` events table to calculate attribute values for all events from that date up to the publish timestamp. The streaming engine starts immediately and processes all new events in real time. Backfill operates within this defined period and can take some time depending on data volume. Once backfill completes, only the streaming engine remains active. +When backfill is enabled, you select a start date. On publish, Signals uses your Snowplow `atomic` events table to calculate attribute values for all events from that date up to the publish timestamp, based on the `load_tstamp` column. The streaming engine starts immediately and processes all new events in real time. Backfill operates within this defined period and can take some time depending on data volume. Once backfill completes, only the streaming engine remains active. :::info[Backfill query performance] -Signals filters the events table on the `load_tstamp` column. This column is typically the partition or cluster key on Snowplow-loaded event tables, so filtering on it lets queries prune partitions efficiently. +Signals filters the events table on the `load_tstamp` column, the time an event was loaded into your warehouse. This column is typically the partition or cluster key on Snowplow-loaded event tables, so filtering on it lets queries prune partitions efficiently. ::: You can monitor progress in Snowplow Console on the attribute group's details page. While historical values are syncing, a status bar labeled `Backfill in progress` is shown. This status remains visible until the backfill period has completed.