Persisting Data

(this is an experimental new feature, expect enhancements and changes)

Introduction

As defined in the glossary, to Persist is to convert data into the storage format most appropriate for the container type, and save a copy of this for rapid lookup in the future. This is of great potential benefit where the creation or transfer of the original data source takes some time.

This is not to be confused with the file Cache.

Usage

Any Data Source has a method .persist(). The only option that you will need to pick is a TTL, the number of seconds that the persisted version lasts before expiry (leave as None for no expiry). This creates a local copy in the persist directory, which may be in "~/.intake/persist, but can be configured.

Each container type (dataframe, array, …) will have its own implementation of persistence, and a particular file storage format associated. The call to .persist() may take arguments to tune how the local files are created, and in some cases may require additional optional packages to be installed.

Example:

cat = intake.open_catalog('mycat.yaml')  # load a remote cat
source = cat.csvsource()  # source pointing to remote data
source.persist()

source = cat.csvsource()  # future use now gives local intake_parquet.ParquetSource

To control whether a catalog will automatically give you the persisted version of a source in this way using the argument persist_mode, e.g., to ignore locally persisted versions, you could have done:

cat = intake.open_catalog('mycat.yaml', persist_mode='never')
or
source = cat.csvsource(persist_mode='never')

Note that if you give a TTL (in seconds), then the original source will be accessed and a new persisted version written transparently when the old persisted version has expired.

Note that after persisting, the original source will have source.has_been_persisted == True and the persisted source (i.e., the one loaded from local files) will have source.is_persisted == True.

Export

A similar concept to Persist, Export allows you to make a copy of some data source, in the format appropriate for its container, and place this data-set in whichever location suits you, including remote locations. This functionality (source.export()) does not touch the persist store; instead, it returns a YAML text representation of the output, so that you can put it into a catalog of your own. It would be this catalog that you share with other people.

Note that “exported” data-sources like this do contain the information of the original source they were made from in their metadata, so you can recreate the original source, if you want to, and read from there.

Persisting to Remote

If you are typically running your code inside of ephemoral containers, then persisting data-sets may be something that you want to do (because the original source is slow, or parsing is CPU/memory intensive), but the local storage is not useful. In some cases you may have access to some shared network storage mounted on the instance, but in other cases you will want to persist to a remote store.

The config value 'persist_path', which can also be set by the environment variable INTAKE_PERSIST_PATH can be a remote location such as s3://mybucket/intake-persist. You will need to install the appropriate package to talk to the external storage (e.g., s3fs, gcsfs, pyarrow), but otherwise everything should work as before, and you can access the persisted data from any container.

The Persist Store

You can interact directly with the class implementing persistence:

from intake.container.persist import store

This singleton instance, which acts like a catalog, allows you to query the contents of the instance store and to add and remove entries. It also allows you to find the original source for any given persisted source, and refresh the persisted version on demand.

For details on the methods of the persist store, see the API documentation: intake.container.persist.PersistStore(). Sources in the store carry a lot of information about the sources they were made from, so that they can be remade successfully. This all appears in the source metadata. The sources use the “token” of the original data source as their key in the store, a value which can be found by dask.base.tokenize(source) for the original source, or can be taken from the metadata of a persisted source.

Note that all of the information about persisted sources is held in a single YAML file in the persist directory (typically /persisted/cat.yaml within the config directory, but see intake.config.conf['persist_path']). This file can be edited by hand if you wanted to, for example, set some persisted source not to expire. This is only recommended for experts.

Future Enhancements

  • CLI functionality to investigate and alter the state of the persist store.

  • Time check-pointing of persisted data, such that you can not only get the “most recent” but any version in the time-series.

  • (eventually) pipeline functionality, whereby a persisted data source depends on another persisted data source, and the whole train can be refreshed on a schedule or on demand.