Learn how to time travel across different write operations on your arrays.
How to run this tutorial
You can run this tutorial in two ways:
Locally on your machine.
On TileDB Cloud.
However, since TileDB Cloud has a free tier, we strongly recommend that you sign up and run everything there, as that requires no installations or deployment.
This tutorial demonstrates the time traveling functionality on fragments (that is, on the various write operations performed to the array). For more information on time traveling, visit the Key Concepts: Time Traveling section.
First, import the necessary libraries, set the array URI (i.e., its path, which in this tutorial will be on local storage), and delete any previously created arrays with the same name.
# Import necessary librariesimport tiledbimport numpy as npimport shutilimport os.path# Set array URIarray_uri = os.path.expanduser("~/time_traveling_fragments")# Delete array if it already existsif os.path.exists(array_uri): shutil.rmtree(array_uri)
# Import necessary librarieslibrary(tiledb)# Set array URIarray_uri <-path.expand("~/time_traveling_fragments_r")# Delete array if it already existsif (file.exists(array_uri)) {unlink(array_uri, recursive =TRUE)}
Next, create the array by specifying its schema. This example uses a sparse array, but the described time traveling functionality is applicable to any array.
# Create the two dimensionsd1 = tiledb.Dim(name="d1", domain=(0, 3), tile=2, dtype=np.int32)d2 = tiledb.Dim(name="d2", domain=(0, 3), tile=2, dtype=np.int32)# Create a domain using the two dimensionsdom = tiledb.Domain(d1, d2)# Create an attributea = tiledb.Attr(name="a", dtype=np.int32)# Create the array schema with `sparse=True`.sch = tiledb.ArraySchema(domain=dom, sparse=True, attrs=[a])# Create the array on disk (it will initially be empty)tiledb.Array.create(array_uri, sch)
# Create the two dimensionsd1 <-tiledb_dim("d1", c(0L, 3L), 2L, "INT32")d2 <-tiledb_dim("d2", c(0L, 3L), 2L, "INT32")# Create a domain using the two dimensionsdom <-tiledb_domain(dims =c(d1, d2))# Create an attributea <-tiledb_attr("a", type ="INT32")# Create the array schema with `sparse = TRUE`sch <-tiledb_array_schema(dom, a, sparse =TRUE)# Create the array on disk (it will initially be empty)arr <-tiledb_array_create(array_uri, sch)
Populate the array using a set of 1D arrays, one for the coordinates of each dimension, and one for the attribute values (TileDB sparse arrays expect the COO format). Observe that the write is perfomed at a specific user-defined timestamp (namely, at 1), in order to make time traveling easier later.
# Prepare some data in numpy arraysd1_data = np.array([2, 0, 3, 2, 0, 1], dtype=np.int32)d2_data = np.array([0, 1, 1, 2, 3, 3], dtype=np.int32)a_data = np.array([4, 1, 6, 5, 2, 3], dtype=np.int32)# Open the array in write mode and write the data in COO formatwith tiledb.open(array_uri, "w", timestamp=1) as A: A[d1_data, d2_data] = a_data
# Prepare some data in an arrayd1_data <-c(2L, 0L, 3L, 2L, 0L, 1L)d2_data <-c(0L, 1L, 1L, 2L, 3L, 3L)a_data <-c(4L, 1L, 6L, 5L, 2L, 3L)# Open the array for writing and write data to the arrayarr <-tiledb_array(uri = array_uri)invisible(tiledb_array_close(arr))arr <-tiledb_array_open_at( arr,type ="WRITE",timestamp =as.POSIXct(1))arr[d1_data, d2_data] <- a_data# Close the arrayinvisible(tiledb_array_close(arr))arr <-tiledb_array_open_at( arr,type ="READ",timestamp =as.POSIXct(1))cat("Entire array at timestamp 1:\n")print(arr[])cat("\n\n")arr <-tiledb_array_close(arr)
# Prepare some data in numpy arraysd1_data = np.array([1], dtype=np.int32)d2_data = np.array([1], dtype=np.int32)a_data = np.array([100], dtype=np.int32)# Open the array in write mode and write the data in COO formatwith tiledb.open(array_uri, "w", timestamp=2) as A: A[d1_data, d2_data] = a_data
# Prepare some datad1_data <-1Ld2_data <-1La_data <-100L# Open the array for writing and write data to the arrayarr <-tiledb_array_open_at( arr,type ="WRITE",timestamp =as.POSIXct(2))arr[d1_data, d2_data] <- a_data# Close the arrayinvisible(tiledb_array_close(arr))
The array is a folder in the path specified in array_uri. The contents are explained in other sections of the Academy, but you can observe that the above write operations created two fragment folders inside the fragments directory, one prefixed with _1_1 and one with _2_2, which are the timestamps the writes were performed at.
Next, read the array at different timestamp combinations:
No timestamp provided: This means read at the current timestamp, which will include data from both the write operations.
At timestamp 1: This will include data from only the first write (i.e., read the array as of timestamp 1).
At timestamp 2: This will include data from both writes (i.e., read the array as of timestamp 2)
At timestamp range [2,2]: This will include data written only within the timestamp range, i.e., data only from the second write.
In a real-world scenario, the fragment timestamps will be the actual times at which the writes occured. In order to see what fragments the array contains and guide your time traveling, visit the Tutorials: Get Fragment Info section.
# Read the entire array at current timestampwith tiledb.open(array_uri, "r") as A:print("Entire array at current timestamp: ")print(A[:])print("\n")# Read the entire array at timestamp 1with tiledb.open(array_uri, "r", timestamp=1) as A:print("Entire array at timestamp 1: ")print(A[:])print("\n")# Read the entire array at timestamp 2with tiledb.open(array_uri, "r", timestamp=2) as A:print("Entire array at timestamp 2: ")print(A[:])print("\n")# Read the entire array at timestamp range [2,2]with tiledb.open(array_uri, "r", timestamp=(2, 2)) as A:print("Entire array at timestamp range [2,2]: ")print(A[:])
# Read the entire array at current timestamparr <-tiledb_array_open(arr, type ="READ")cat("Entire array:\n")print(arr[])cat("\n\n")arr <-tiledb_array_close(arr)# Read the array up to and including timestamp 1arr <-tiledb_array(uri = array_uri,query_type ="READ",timestamp_end =as.POSIXct(1),return_as ="data.frame")cat("Entire array at timestamp 1:\n")print(arr[])cat("\n\n")arr <-tiledb_array_close(arr)# Read the array at timestamp 2arr <-tiledb_array(uri = array_uri,query_type ="READ",timestamp_end =as.POSIXct(2),return_as ="data.frame")cat("Entire array at timestamp 2:\n")print(arr[])cat("\n\n")arr <-tiledb_array_close(arr)# Read the array at timestamp range [2,2]arr <-tiledb_array(uri = array_uri,query_type ="READ",timestamp_start =as.POSIXct(2),timestamp_end =as.POSIXct(2),return_as ="data.frame")cat("Entire array at timestamp range [2,2]:\n")print(arr[])cat("\n\n")arr <-tiledb_array_close(arr)