Quickstart

Welcome to TileDB! This quickstart will walk you through getting TileDB installed and writing your first TileDB programs.

Install TileDB

C++ API

First, grab a TileDB release for your system:

macOS

# Homebrew:
$ brew update
$ brew install tiledb-inc/stable/tiledb

# Or Conda:
$ conda install -c conda-forge tiledb

Linux

# Conda:
$ conda install -c conda-forge tiledb

# Or Docker:
$ docker pull tiledb/tiledb
$ docker run -it tiledb/tiledb

Windows

# Conda
> conda install -c conda-forge tiledb

# Or download the pre-built release binaries from:
# https://github.com/TileDB-Inc/TileDB/releases

For more in-depth installation information, see the Installation page.

Compiling TileDB programs

In the remainder of this quickstart and the tutorials to follow, you will learn how to create TileDB programs using the language API of your choice. To compile and run a TileDB program called my_tiledb_program.cc using the C++ API:

$ g++ -std=c++11 my_tiledb_program.cc -o my_tiledb_program -ltiledb
$ ./my_tiledb_program

If you run into compilation issues, see the Usage page for more complete instructions on how to compile and link against TileDB. If you are on Windows, use the Windows usage instructions to create a Visual Studio project instead.

Python API

A working TileDB Python system can be installed with pip:

$ pip install tiledb

This will automatically download and build the core TileDB library in addition to the Python bindings, so it may take a while.

To use TileDB-Py in a program, simply import the TileDB Python module:

import tiledb

And run your program as usual:

$ python my_tiledb_program.py

R API

TileDB needs to be installed. After the core library is installed, the R source package can be installed and built with devtools:

install.packages("devtools")
library(devtools)
devtools::install_github("TileDB-Inc/[email protected]")

To use the TileDB-R package, simply import the installed R library in your R script or REPL:

library(tiledb)

To run a TileDB-R script:

$ Rscript my_tiledb_program.R

Golang API

TileDB needs to be installed. After the core library is installed the Go api can be installed with go get:

$ go get -v github.com/TileDB/TileDB-Go

This will automatically download and build the Go API bindings and link to the core library.

To use the TileDB Go API, simply import the installed Go library in your Go source file:

import tiledb "github.com/TileDB/TileDB-Go"

And run your program as usual:

$ go run my_tiledb_program.go

A Simple Dense Array Example

First let’s create a simple 4x4 dense array, i.e., with two dimensions (called rows and cols), each with domain [1,4]. This array has a single int attribute, i.e., it will store integer values in its cells.

C++

// Name of array.
std::string array_name("quickstart_dense");

void create_array() {
  // Create a TileDB context.
  Context ctx;

  // The array will be 4x4 with dimensions "rows" and "cols", with domain [1,4].
  Domain domain(ctx);
  domain.add_dimension(Dimension::create<int>(ctx, "rows", {{1, 4}}, 4))
        .add_dimension(Dimension::create<int>(ctx, "cols", {{1, 4}}, 4));

  // The array will be dense.
  ArraySchema schema(ctx, TILEDB_DENSE);
  schema.set_domain(domain)
        .set_order({{TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR}})

  // Add a single attribute "a" so each (i,j) cell can store an integer.
  schema.add_attribute(Attribute::create<int>(ctx, "a"));

  // Create the (empty) array on disk.
  Array::create(array_name, schema);
}

Python

import numpy as np
import sys
import tiledb

# Name of the array to create.
array_name = "quickstart_dense"

def create_array():
    # Create a TileDB context
    ctx = tiledb.Ctx()

    # Check if the array already exists.
    if tiledb.object_type(ctx, array_name) == "array":
        print("Array already exists.")
        sys.exit(0)

    # The array will be 4x4 with dimensions "rows" and "cols", with domain [1,4].
    dom = tiledb.Domain(ctx,
                        tiledb.Dim(ctx, name="rows", domain=(1, 4), tile=4, dtype=np.int32),
                        tiledb.Dim(ctx, name="cols", domain=(1, 4), tile=4, dtype=np.int32))

    # The array will be dense with a single attribute "a" so each (i,j) cell can store an integer.
    schema = tiledb.ArraySchema(ctx, domain=dom, sparse=False,
                                attrs=[tiledb.Attr(ctx, name="a", dtype=np.int32)])

    # Create the (empty) array on disk.
    tiledb.DenseArray.create(array_name, schema)

R

 library(tiledb)

 # Name of the array to create.
 array_name = "quickstart_dense"

 create_array <- function() {
     # Create a TileDB context
    ctx <- tiledb_ctx()

    # Check if the array already exists.
    if (tiledb_object_type(ctx, array_name) == "ARRAY") {
        stop("Array already exists.")
        quit(0)
    }

    # The array will be 4x4 with dimensions "rows" and "cols", with domain [1,4].
    dom <- tiledb_domain(ctx,
                dims = c(tiledb_dim(ctx, "rows", c(1L, 4L), 4L, "INT32"),
                         tiledb_dim(ctx, "cols", c(1L, 4L), 4L, "INT32")))

    # The array will be dense with a single attribute "a" so each (i,j) cell can store an integer.
    schema <- tiledb_array_schema(ctx,
                dom, attrs=c(tiledb_attr(ctx, "a", type = "INT32")))

    # Create the (empty) array on disk.
    tiledb_array_create(array_name, schema)
}

Golang

// Name of array.
var arrayName = "quickstart_dense"

func createDenseArray() {
        // Create a TileDB context.
        ctx, _ := tiledb.NewContext(nil)

        // The array will be 4x4 with dimensions "rows" and "cols", with domain [1,4].
        domain, _ := tiledb.NewDomain(ctx)
        rowDim, _ := tiledb.NewDimension(ctx, "rows", []int32{1, 4}, int32(4))
        colDim, _ := tiledb.NewDimension(ctx, "cols", []int32{1, 4}, int32(4))
        domain.AddDimensions(rowDim, colDim)

        // The array will be dense.
        schema, _ := tiledb.NewArraySchema(ctx, tiledb.TILEDB_DENSE)
        schema.SetDomain(domain)
        schema.SetCellOrder(tiledb.TILEDB_ROW_MAJOR)
        schema.SetTileOrder(tiledb.TILEDB_ROW_MAJOR)

        // Add a single attribute "a" so each (i,j) cell can store an integer.
        a, _ := tiledb.NewAttribute(ctx, "a", tiledb.TILEDB_INT32)
        schema.AddAttributes(a)

        // Create the (empty) array on disk.
        array, _ := tiledb.NewArray(ctx, arrayName)
        array.Create(schema)
}

Next we populate the array by writing some values to its cells, specifically 1, 2, …, 16 in a row-major layout (i.e., the columns of the first row will be populated first, then those of the second row, etc.).

C++

void write_array() {
  Context ctx;

  // Prepare some data for the array
  std::vector<int> data = {
      1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};

  // Open the array for writing and create the query.
  Array array(ctx, array_name, TILEDB_WRITE);
  Query query(ctx, array);
  query.set_layout(TILEDB_ROW_MAJOR)
       .set_buffer("a", data);

  // Perform the write and close the array.
  query.submit();
  array.close();
}

Python

def write_array():
    ctx = tiledb.Ctx()
    # Open the array and write to it.
    with tiledb.DenseArray(ctx, array_name, mode='w') as A:
        data = np.array(([1, 2, 3, 4],
                         [5, 6, 7, 8],
                         [9, 10, 11, 12],
                         [13, 14, 15, 16]))
        A[:] = data

R

library(tiledb)

write_array <- function() {
    data <- array(c(c(1L, 5L, 9L, 13L),
                    c(2L, 6L, 10L, 14L),
                    c(3L, 7L, 11L, 15L),
                    c(4L, 8L, 12L, 16L)),
                  dim = c(4,4))
    # Open the array and write to it.
    ctx <- tiledb_ctx()
    A <- tiledb_dense(ctx, uri = array_name)
    A[] <- data
}

Golang

func writeDenseArray() {
  ctx, _ := tiledb.NewContext(nil)

  // Prepare some data for the array
  data := []int32{
    1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}

  // Open the array for writing and create the query.
  array, _ := tiledb.NewArray(ctx, arrayName)
  array.Open(tiledb.TILEDB_WRITE)
  query, _ := tiledb.NewQuery(ctx, array)
  query.SetLayout(tiledb.TILEDB_ROW_MAJOR)
  query.SetBuffer("a", data)

  // Perform the write and close the array.
  query.Submit()
  array.Close()
}

The resulting array is depicted in the figure below. Finally, we will read a portion of the array (called slicing) and simply output the contents of the selected cells on the screen. Suppose we wish to read subarray [1,2], [2,4], i.e., focus on the cells in rows 1, 2 and columns 2, 3, 4. The result values should be 2 3 4 6 7 8, reading again in row-major order (i.e., first the three selected columns of row 1, then the three selected columns of row 2).

_images/quickstart_dense.png

A 4x4 dense array, highlighting subarray [1:2,2:4]

C++

void read_array() {
  Context ctx;

  // Prepare the array for reading
  Array array(ctx, array_name, TILEDB_READ);

  // Slice only rows 1, 2 and cols 2, 3, 4
  const std::vector<int> subarray = {1, 2, 2, 4};

  // Prepare the vector that will hold the result (of size 6 elements)
  std::vector<int> data(6);

  // Prepare the query
  Query query(ctx, array);
  query.set_subarray(subarray)
       .set_layout(TILEDB_ROW_MAJOR)
       .set_buffer("a", data);

  // Submit the query and close the array.
  query.submit();
  array.close();

  // Print out the results.
  for (auto d : data)
    std::cout << d << " ";
  std::cout << "\n";
}

Python

def read_array():
    ctx = tiledb.Ctx()
    # Open the array and read from it.
    with tiledb.DenseArray(ctx, array_name, mode='r') as A:
        # Slice only rows 1, 2 and cols 2, 3, 4.
        data = A[1:3, 2:5]
        print(data["a"])

R

library(tiledb)

read_array <- function() {
    ctx <- tiledb_ctx()
    # Open the array and read from it.
    A <- tiledb_dense(ctx, uri = array_name)
    data <- A[1:2, 2:4]
    show(data)
}

Golang

func readDenseArray() {
  ctx, _ := tiledb.NewContext(nil)

  // Prepare the array for reading
  array, _ := tiledb.NewArray(ctx, arrayName)
  array.Open(tiledb.TILEDB_READ)

  // Slice only rows 1, 2 and cols 2, 3, 4
  subArray := []int32{1, 2, 2, 4}

  // Prepare the vector that will hold the result (of size 6 elements)
  data := make([]int32, 6)

  // Prepare the query
  query, _ := tiledb.NewQuery(ctx, array)
  query.SetSubArray(subArray)
  query.SetLayout(tiledb.TILEDB_ROW_MAJOR)
  query.SetBuffer("a", data)

  // Submit the query and close the array.
  query.Submit()
  array.Close()

  // Print out the results.
  fmt.Println(data)
}

If you run the example, you should see the following output:

C++

$ g++ -std=c++11 quickstart_dense.cc -o quickstart_dense -ltiledb
$ ./quickstart_dense
2 3 4 6 7 8

Python

$ python quickstart_dense.py
[[2 3 4]
 [6 7 8]]

R

$ Rscript quickstart_dense.R
     [,1] [,2] [,3]
[1,]    2    3    4
[2,]    6    7    8

Golang

$ go test -v quickstart_dense.go
[2 3 4 6 7 8]

A Simple Sparse Array Example

First let’s create a simple 4x4 sparse array, i.e., with two dimensions (called rows and cols), each with domain [1,4]. This array has a single int attribute, i.e., it will store integer values in its cells.

C++

// Name of array.
std::string array_name("quickstart_sparse");

void create_array() {
  // Create a TileDB context.
  Context ctx;

  // The array will be 4x4 with dimensions "rows" and "cols", with domain [1,4].
  Domain domain(ctx);
  domain.add_dimension(Dimension::create<int>(ctx, "rows", {{1, 4}}, 4))
        .add_dimension(Dimension::create<int>(ctx, "cols", {{1, 4}}, 4));

  // The array will be sparse.
  ArraySchema schema(ctx, TILEDB_SPARSE);
  schema.set_domain(domain).set_order({{TILEDB_ROW_MAJOR, TILEDB_ROW_MAJOR}});

  // Add a single attribute "a" so each (i,j) cell can store an integer.
  schema.add_attribute(Attribute::create<int>(ctx, "a"));

  // Create the (empty) array on disk.
  Array::create(array_name, schema);
}

Python

import numpy as np
import sys
import tiledb

# Name of the array to create.
array_name = "quickstart_sparse"

def create_array():
    # Create a TileDB context
    ctx = tiledb.Ctx()

    # Check if the array already exists.
    if tiledb.object_type(ctx, array_name) == "array":
        print("Array already exists.")
        sys.exit(0)

    # The array will be 4x4 with dimensions "rows" and "cols", with domain [1,4].
    dom = tiledb.Domain(ctx,
                        tiledb.Dim(ctx, name="rows", domain=(1, 4), tile=4, dtype=np.int32),
                        tiledb.Dim(ctx, name="cols", domain=(1, 4), tile=4, dtype=np.int32))

    # The array will be sparse with a single attribute "a" so each (i,j) cell can store an integer.
    schema = tiledb.ArraySchema(ctx, domain=dom, sparse=True,
                                attrs=[tiledb.Attr(ctx, name="a", dtype=np.int32)])

    # Create the (empty) array on disk.
    tiledb.SparseArray.create(array_name, schema)

R

 library(tiledb)

 # Name of the array to create.
 array_name = "sparse_sparse"

 create_array <- function() {
     # Create a TileDB context
    ctx <- tiledb_ctx()

    # Check if the array already exists.
    if (tiledb_object_type(ctx, array_name) == "ARRAY") {
        stop("Array already exists.")
        quit(0)
    }

    # The array will be 4x4 with dimensions "rows" and "cols", with domain [1,4].
    dom <- tiledb_domain(ctx,
                dims = c(tiledb_dim(ctx, "rows", c(1L, 4L), 4L, "INT32"),
                         tiledb_dim(ctx, "cols", c(1L, 4L), 4L, "INT32")))

   # The array will be dense with a single attribute "a" so each (i,j) cell can store an integer.
    schema <- tiledb_array_schema(ctx,
                dom, attrs=c(tiledb_attr(ctx, "a", type = "INT32")),
                sparse = TRUE)

    # Create the (empty) array on disk.
    tiledb_array_create(array_name, schema)
}

Golang

// Name of array.
var sparseArrayName = "quickstart_sparse"

func createSparseArray() {
  // Create a TileDB context.
  ctx, _ := tiledb.NewContext(nil)

  // The array will be 4x4 with dimensions "rows" and "cols", with domain [1,4].
  domain, _ := tiledb.NewDomain(ctx)
  rowDim, _ := tiledb.NewDimension(ctx, "rows", []int32{1, 4}, int32(4))
  colDim, _ := tiledb.NewDimension(ctx, "cols", []int32{1, 4}, int32(4))
  domain.AddDimensions(rowDim, colDim)

  // The array will be dense.
  schema, _ := tiledb.NewArraySchema(ctx, tiledb.TILEDB_SPARSE)
  schema.SetDomain(domain)
  schema.SetCellOrder(tiledb.TILEDB_ROW_MAJOR)
  schema.SetTileOrder(tiledb.TILEDB_ROW_MAJOR)

  // Add a single attribute "a" so each (i,j) cell can store an integer.
  a, _ := tiledb.NewAttribute(ctx, "a", tiledb.TILEDB_INT32)
  schema.AddAttributes(a)

  // Create the (empty) array on disk.
  array, _ := tiledb.NewArray(ctx, sparseArrayName)
  array.Create(schema)
 }

Next we populate the array by writing some values to its cells, specifically 1, 2, and 3 at cells (1,1), (2,4) and (2,3), respectively. Notice that, contrary to the dense case, here we specify the exact indices where the values will be written, i.e., we provide the cell coordinates. Do not worry about the “unordered” query layout for now, just know that it is important.

C++

void write_array() {
  Context ctx;

  // Write some simple data to cells (1, 1), (2, 4) and (2, 3).
  std::vector<int> coords = {1, 1, 2, 4, 2, 3};
  std::vector<int> data = {1, 2, 3};

  // Open the array for writing and create the query.
  Array array(ctx, array_name, TILEDB_WRITE);
  Query query(ctx, array);
  query.set_layout(TILEDB_UNORDERED)
       .set_buffer("a", data)
       .set_coordinates(coords);

  // Perform the write and close the array.
  query.submit();
  array.close();
}

Python

def write_array():
    ctx = tiledb.Ctx()
    # Open the array and write to it.
    with tiledb.SparseArray(ctx, array_name, mode='w') as A:
        # Write some simple data to cells (1, 1), (2, 4) and (2, 3).
        I, J = [1, 2, 2], [1, 4, 3]
        data = np.array(([1, 2, 3]));
        A[I, J] = data

R

library(tiledb)

write_array <- function() {
    I <- c(1L, 2L, 2L)
    J <- c(1L, 4L, 3L)
    data <- c(1L, 2L, 3L)
    # Open the array and write to it.
    ctx <- tiledb_ctx()
    A <- tiledb_sparse(ctx, uri = array_name)
    A[I, J] <- data
}

Golang

func writeSparseArray() {
  ctx, _ := tiledb.NewContext(nil)

  // Write some simple data to cells (1, 1), (2, 4) and (2, 3).
  coords := []int32{1, 1, 2, 4, 2, 3}
  data := []int32{1, 2, 3}

  // Open the array for writing and create the query.
  array, _ := tiledb.NewArray(ctx, sparseArrayName)
  array.Open(tiledb.TILEDB_WRITE)
  query, _ := tiledb.NewQuery(ctx, array)
  query.SetLayout(tiledb.TILEDB_ROW_MAJOR)
  query.SetBuffer("a", data)
  query.SetCoordinates(coords)

  // Perform the write and close the array.
  query.Submit()
  array.Close()
}

The resulting array is depicted in the figure below. Similar to the dense array example, we read subarray [1,2], [2,4], i.e., focus on the cells in rows 1, 2 and columns 2, 3, 4. The result values should be 3 for cell (2,3) and 2 for cell (2,4) reading again in row-major order.

_images/quickstart_sparse.png

A 4x4 sparse array, highlighting subarray [1:2,2:4]

One of the most challenging issues when using the C++ API is estimating how large the result of a read query on a sparse array is, so that you know how much space to allocate for your buffers, and how to parse the result (this was not an issue in the dense case). TileDB offers several utility functions in the C++ API to help deal with this issue; read through the “Tutorial” sections for the details. The Python API takes care of this issue for you automatically.

C++

void read_array() {
  Context ctx;

  // Prepare the array for reading
  Array array(ctx, array_name, TILEDB_READ);

  // Slice only rows 1, 2 and cols 2, 3, 4
  const std::vector<int> subarray = {1, 2, 2, 4};

  // Prepare the vector that will hold the result.
  // We take an upper bound on the result size, as we do not
  // know a priori how big it is (since the array is sparse)
  auto max_el = array.max_buffer_elements(subarray);
  std::vector<int> data(max_el["a"].second);
  std::vector<int> coords(max_el[TILEDB_COORDS].second);

  // Prepare the query
  Query query(ctx, array);
  query.set_subarray(subarray)
       .set_layout(TILEDB_ROW_MAJOR)
       .set_buffer("a", data)
       .set_coordinates(coords);

  // Submit the query and close the array.
  query.submit();
  array.close();

  // Print out the results.
  auto result_num = (int) query.result_buffer_elements()["a"].second;
  for (int r = 0; r < result_num; r++) {
    int i = coords[2 * r], j = coords[2 * r + 1];
    int a = data[r];
    std::cout << "Cell (" << i << "," << j << ") has data " << a << "\n";
  }
}

Python

def read_array():
    ctx = tiledb.Ctx()
    # Open the array and read from it.
    with tiledb.SparseArray(ctx, array_name, mode='r') as A:
        # Slice only rows 1, 2 and cols 2, 3, 4.
        data = A[1:3, 2:5]
        a_vals = data["a"]
        for i, coord in enumerate(data["coords"]):
            print("Cell (%d,%d) has data %d" % (coord[0], coord[1], a_vals[i]))

R

library(tiledb)

read_array <- function() {
    ctx <- tiledb_ctx()
    # Open the array and read from it.
    A <- tiledb_dense(ctx, uri = array_name)
    data <- A[1:2, 2:4]

    coords <- data[["coords"]]
    a_vals <- data[["a"]]
    for (idx in seq_along(a_vals)) {
        i <- coords[((idx - 1) * 2) + 1]
        j <- coords[((idx - 1) * 2) + 2]
        cat(sprintf("Cell (%d,%d) has data %d\n", i, j, a_vals[idx]))
    }
}

Golang

func readSparseArray() {
  ctx, _ := tiledb.NewContext(nil)

  // Prepare the array for reading
  array, _ := tiledb.NewArray(ctx, sparseArrayName)
  array.Open(tiledb.TILEDB_READ)

  // Slice only rows 1, 2 and cols 2, 3, 4
  subArray := []int32{1, 2, 2, 4}

  // Prepare the vector that will hold the results
  // We take the upper bound on the result size as we do not know how large
  // a buffer is needed since the array is sparse
  maxElements, _ := array.MaxBufferElements(subArray)
  data := make([]int32, maxElements["a"][1])
  coords := make([]int32, maxElements[tiledb.TILEDB_COORDS][1])

  // Prepare the query
  query, _ := tiledb.NewQuery(ctx, array)
  query.SetSubArray(subArray)
  query.SetLayout(tiledb.TILEDB_ROW_MAJOR)
  query.SetBuffer("a", data)
  query.SetCoordinates(coords)

  // Submit the query and close the array.
  query.Submit()
  array.Close()

  // Print out the results.
  for r := 0; r < len(data); r++ {
    i := coords[2*r]
    j := coords[2*r+1]
    fmt.Printf("Cell (%d, %d) has data %d\n", i, j, data[r])
  }
}

If you run the example, you should see the following output:

C++

$ g++ -std=c++11 quickstart_sparse.cc -o quickstart_sparse -ltiledb
$ ./quickstart_sparse
Cell (2, 3) has data 3
Cell (2, 4) has data 2

Python

$ python quickstart_sparse.py
Cell (2,3) has data 3
Cell (2,4) has data 2

R

$ Rscript quickstart_dense.R
Cell (2,3) has data 3
Cell (2,4) has data 2

Golang

$ go test -v quickstart_sparse_test.go
Cell (2, 3) has data 3
Cell (2, 4) has data 2

Links to full programs

Program Links
quickstart_sparse quickstartsparsecpp quickstartsparsepy quickstartsparser quickstartsparsego

A Simple Key-Value Example

Warning

Key-value arrays are not yet supported for the Go or R APIs.

First let’s create a simple map with a single integer attribute.

C++

// Name of map.
std::string map_name("quickstart_map");

void create_map() {
  // Create TileDB context
  tiledb::Context ctx;

  // Create a map with a single integer attribute
  tiledb::MapSchema schema(ctx);
  tiledb::Attribute a = tiledb::Attribute::create<int>(ctx, "a");
  schema.add_attribute(a);
  tiledb::Map::create(map_name, schema);
}

Python

import numpy as np
import sys
import tiledb

# Name of the array to create.
array_name = "quickstart_kv"

def create_array():
    # Create a TileDB context
    ctx = tiledb.Ctx()

    # The KV store will have a single attribute "a" storing a string.
    schema = tiledb.KVSchema(ctx, attrs=[tiledb.Attr(ctx, name="a", dtype=bytes)])

    # Create the (empty) array on disk.
    tiledb.KV.create(ctx, array_name, schema)

Note

Currently the Python key-value API only supports string-valued attributes. The C and C++ APIs support any attribute type for key-value arrays.

Next we populate the map with 3 key-value pairs: "key_1": 1, "key_2": 2 and "key_3": 3.

C++

void write_map() {
  tiledb::Context ctx;

  // Open the map
  tiledb::Map map(ctx, map_name);

  map["key_1"]["a"] = 1;
  map["key_2"] = 2;  // Implicit "a" since there is 1 attr
  map["key_3"] = 3;

  // Close the map
  map.close();
}

Python

def write_array():
    ctx = tiledb.Ctx()
    # Open the array and write to it.
    A = tiledb.KV(ctx, array_name)
    A["key_1"] = "1"
    A["key_2"] = "2"
    A["key_3"] = "3"
    A.flush()

Finally, we read the data back using the keys and print them on the screen.

C++

void read_map() {
  Context ctx;

  // Open the map
  tiledb::Map map(ctx, map_name);

  // Read the keys
  int a1 = map["key_1"];
  int a2 = map["key_2"];
  int a3 = map["key_3"];

  // Print
  std::cout << "key_1: " << a1 << "\n";
  std::cout << "key_2: " << a2 << "\n";
  std::cout << "key_3: " << a3 << "\n";

  // Close the map
  map.close();
}

Python

def read_array():
    ctx = tiledb.Ctx()
    # Open the array and read from it.
    A = tiledb.KV(ctx, array_name)
    print("key_1: %s" % A["key_1"])
    print("key_2: %s" % A["key_2"])
    print("key_3: %s" % A["key_3"])

If you run the example, you should see the following output:

C++

$ g++ -std=c++11 quickstart_map.cc -o quickstart_map -ltiledb
$ ./quickstart_map
key_1: 1
key_2: 2
key_3: 3

Python

$ python quickstart_kv.py
key_1: 1
key_2: 2
key_3: 3

Links to full programs

Program Links
quickstart_kv quickstartkvcpp quickstartkvpy

Further reading

This quickstart omits discussion of several important concepts such as tiling, cell/tile layouts, types of write and read queries, memory management, and many more exciting topics. To learn more about these subjects, read through the “Tutorial” sections that cover all the TileDB concepts and functionality in great depth.