Archiving and sharing¶
To comply with legal requirements, Statistics Norway commits itself to working according to a formal process model. For the sake of transparency and process reviews, at certain points in the process data has to be persisted. That does not simply mean the data must be saved. Stricter requirements apply. First, immutability: the persisted data must be stored “forever”, without being subject to change. Second, conventions apply to storage formats, naming and documentation.
Data shared between different statistics are subject to the same restrictions.
The conventions that apply are designed for archive and review purposes, not to for efficient data manipulation or retrievel. That is contrary to the purpose of the SSB Timeseries library, which is the reason “archiving” and “sharing” are treated differently from ordinary reads and writes.
Configurations at the set level control how a dataset is archived and shared, but the actual writing happens when data is persisted.
Since an archive is a persisted copy, the .archive() function takes care of both.
Setup¶
data_path = CONFIG.repositories['tutorials']['directory']['options']['path']
def treee():
print(tree(data_path))
treee()
timeseries/
├── archives/
│ ├── statistics/
│ │ └── PQR/
│ │ └── PQR_p2019-12-31T23-00-00.000+00-00_p2025-08-14T22-00-00.000+00-00_v1.parquet
│ ├── The Sample Statistic/
│ │ └── statistics/
│ │ └── SampleDataset/
│ │ └── SampleDataset_p2021-12-31T23-00-00.000+00-00_p2022-11-30T23-00-00.000+00-00_v1.parquet
│ └── XYZ/
│ └── XYZ_p2025-07-30T22-00-00.000+00-00_p2025-08-05T22-00-00.000+00-00_v2025-08-06T22-00-00.000+00-00_v_v1.parquet
├── AS_OF_AT/
│ └── POPU06/
│ ├── POPU06-as_of_2023-12-31T230000+0000-data.parquet
│ ├── POPU06-as_of_2024-01-31T230000+0000-data.parquet
│ ├── POPU06-as_of_2025-10-31T230000+0000-data.parquet
│ ├── POPU06-as_of_2025-11-30T230000+0000-data.parquet
│ └── ...
├── AS_OF_FROM_TO/
│ ├── BNO/
│ │ ├── BNO-as_of_2025-05-31T220000+0000-data.parquet
│ │ └── BNO-as_of_2025-08-06T220000+0000-data.parquet
│ └── Prices and Volumes/
│ ├── Prices and Volumes-as_of_2023-12-31T230000+0000-data.parquet
│ ├── Prices and Volumes-as_of_2024-01-31T230000+0000-data.parquet
│ ├── Prices and Volumes-as_of_2025-10-31T230000+0000-data.parquet
│ ├── Prices and Volumes-as_of_2025-11-30T230000+0000-data.parquet
│ └── ...
├── metadata/
│ ├── AZ_beverages-metadata.json
│ ├── AZ_drinks-metadata.json
│ ├── SampleDataset-metadata.json
│ ├── XYZ-metadata.json
│ └── ...
├── NONE_AT/
│ ├── PQR/
│ │ └── PQR-latest-data.parquet
│ ├── SampleDataset/
│ │ └── SampleDataset-latest-data.parquet
│ └── XYZ/
│ └── XYZ-latest-data.parquet
├── NONE_FROM_TO/
│ ├── AZ_beverages/
│ │ └── AZ_beverages-latest-data.parquet
│ ├── AZ_drinks/
│ │ └── AZ_drinks-latest-data.parquet
│ └── More Prices and Volumes/
│ └── More Prices and Volumes-latest-data.parquet
└── shared/
└── default/
├── statistics/
│ └── PQR/
│ └── PQR_p2019-12-31T23-00-00.000+00-00_p2025-08-14T22-00-00.000+00-00_v1.parquet
└── XYZ/
└── XYZ_p2025-07-30T22-00-00.000+00-00_p2025-08-05T22-00-00.000+00-00_v2025-08-06T22-00-00.000+00-00_v_v1.parquet
# what is there before we start?
treee()
timeseries/
├── archives/
│ ├── statistics/
│ │ └── PQR/
│ │ └── PQR_p2019-12-31T23-00-00.000+00-00_p2025-08-14T22-00-00.000+00-00_v1.parquet
│ ├── The Sample Statistic/
│ │ └── statistics/
│ │ └── SampleDataset/
│ │ └── SampleDataset_p2021-12-31T23-00-00.000+00-00_p2022-11-30T23-00-00.000+00-00_v1.parquet
│ └── XYZ/
│ └── XYZ_p2025-07-30T22-00-00.000+00-00_p2025-08-05T22-00-00.000+00-00_v2025-08-06T22-00-00.000+00-00_v_v1.parquet
├── AS_OF_AT/
│ └── POPU06/
│ ├── POPU06-as_of_2023-12-31T230000+0000-data.parquet
│ ├── POPU06-as_of_2024-01-31T230000+0000-data.parquet
│ ├── POPU06-as_of_2025-10-31T230000+0000-data.parquet
│ ├── POPU06-as_of_2025-11-30T230000+0000-data.parquet
│ └── ...
├── AS_OF_FROM_TO/
│ ├── BNO/
│ │ ├── BNO-as_of_2025-05-31T220000+0000-data.parquet
│ │ └── BNO-as_of_2025-08-06T220000+0000-data.parquet
│ └── Prices and Volumes/
│ ├── Prices and Volumes-as_of_2023-12-31T230000+0000-data.parquet
│ ├── Prices and Volumes-as_of_2024-01-31T230000+0000-data.parquet
│ ├── Prices and Volumes-as_of_2025-10-31T230000+0000-data.parquet
│ ├── Prices and Volumes-as_of_2025-11-30T230000+0000-data.parquet
│ └── ...
├── metadata/
│ ├── AZ_beverages-metadata.json
│ ├── AZ_drinks-metadata.json
│ ├── SampleDataset-metadata.json
│ ├── XYZ-metadata.json
│ └── ...
├── NONE_AT/
│ ├── PQR/
│ │ └── PQR-latest-data.parquet
│ ├── SampleDataset/
│ │ └── SampleDataset-latest-data.parquet
│ └── XYZ/
│ └── XYZ-latest-data.parquet
├── NONE_FROM_TO/
│ ├── AZ_beverages/
│ │ └── AZ_beverages-latest-data.parquet
│ ├── AZ_drinks/
│ │ └── AZ_drinks-latest-data.parquet
│ └── More Prices and Volumes/
│ └── More Prices and Volumes-latest-data.parquet
└── shared/
└── default/
├── statistics/
│ └── PQR/
│ └── PQR_p2019-12-31T23-00-00.000+00-00_p2025-08-14T22-00-00.000+00-00_v1.parquet
└── XYZ/
└── XYZ_p2025-07-30T22-00-00.000+00-00_p2025-08-05T22-00-00.000+00-00_v2025-08-06T22-00-00.000+00-00_v_v1.parquet
Example: point-in-time data, without versioning¶
from ssb_timeseries.sample_data import xyz_at
import ssb_timeseries as ts
# the ssb archive convention allows no spaces in a name:
set_name = 'SampleDataset'
p = ts.dataset.Dataset(
name = set_name,
data_type = ts.types.SeriesType('NONE','AT'),
data = xyz_at(),
).save()
# what is there after the .save():
treee()
timeseries/
├── archives/
│ ├── statistics/
│ │ └── PQR/
│ │ └── PQR_p2019-12-31T23-00-00.000+00-00_p2025-08-14T22-00-00.000+00-00_v1.parquet
│ ├── The Sample Statistic/
│ │ └── statistics/
│ │ └── SampleDataset/
│ │ └── SampleDataset_p2021-12-31T23-00-00.000+00-00_p2022-11-30T23-00-00.000+00-00_v1.parquet
│ └── XYZ/
│ └── XYZ_p2025-07-30T22-00-00.000+00-00_p2025-08-05T22-00-00.000+00-00_v2025-08-06T22-00-00.000+00-00_v_v1.parquet
├── AS_OF_AT/
│ └── POPU06/
│ ├── POPU06-as_of_2023-12-31T230000+0000-data.parquet
│ ├── POPU06-as_of_2024-01-31T230000+0000-data.parquet
│ ├── POPU06-as_of_2025-10-31T230000+0000-data.parquet
│ ├── POPU06-as_of_2025-11-30T230000+0000-data.parquet
│ └── ...
├── AS_OF_FROM_TO/
│ ├── BNO/
│ │ ├── BNO-as_of_2025-05-31T220000+0000-data.parquet
│ │ └── BNO-as_of_2025-08-06T220000+0000-data.parquet
│ └── Prices and Volumes/
│ ├── Prices and Volumes-as_of_2023-12-31T230000+0000-data.parquet
│ ├── Prices and Volumes-as_of_2024-01-31T230000+0000-data.parquet
│ ├── Prices and Volumes-as_of_2025-10-31T230000+0000-data.parquet
│ ├── Prices and Volumes-as_of_2025-11-30T230000+0000-data.parquet
│ └── ...
├── metadata/
│ ├── AZ_beverages-metadata.json
│ ├── AZ_drinks-metadata.json
│ ├── SampleDataset-metadata.json
│ ├── XYZ-metadata.json
│ └── ...
├── NONE_AT/
│ ├── PQR/
│ │ └── PQR-latest-data.parquet
│ ├── SampleDataset/
│ │ └── SampleDataset-latest-data.parquet
│ └── XYZ/
│ └── XYZ-latest-data.parquet
├── NONE_FROM_TO/
│ ├── AZ_beverages/
│ │ └── AZ_beverages-latest-data.parquet
│ ├── AZ_drinks/
│ │ └── AZ_drinks-latest-data.parquet
│ └── More Prices and Volumes/
│ └── More Prices and Volumes-latest-data.parquet
└── shared/
└── default/
├── statistics/
│ └── PQR/
│ └── PQR_p2019-12-31T23-00-00.000+00-00_p2025-08-14T22-00-00.000+00-00_v1.parquet
└── XYZ/
└── XYZ_p2025-07-30T22-00-00.000+00-00_p2025-08-05T22-00-00.000+00-00_v2025-08-06T22-00-00.000+00-00_v_v1.parquet
#read the data back, just because we can
q = ts.dataset.Dataset(set_name)
Archiving¶
Archiving writes to the archive and, for each sharing key, to the
destination that key names.
The archive path is built from the tags, so product and process_stage are set
before the dataset is archived.
statistics_product = 'The Sample Statistic'
q.process_stage = 'statistics'
q.product = statistics_product
q.archive()
print(tree(f'{data_path}/archives'))
archives/
├── statistics/
│ └── PQR/
│ └── PQR_p2019-12-31T23-00-00.000+00-00_p2025-08-14T22-00-00.000+00-00_v1.parquet
├── The Sample Statistic/
│ └── statistics/
│ └── SampleDataset/
│ ├── SampleDataset_p2021-12-31T23-00-00.000+00-00_p2022-11-30T23-00-00.000+00-00_v1.parquet
│ └── SampleDataset_p2021-12-31T23-00-00.000+00-00_p2022-11-30T23-00-00.000+00-00_v2.parquet
└── XYZ/
└── XYZ_p2025-07-30T22-00-00.000+00-00_p2025-08-05T22-00-00.000+00-00_v2025-08-06T22-00-00.000+00-00_v_v1.parquet