Powered by AppSignal & Oban Pro

ExArrow Quick Start

livebook/00_quickstart.livemd

ExArrow Quick Start

Get up and running with ExArrow in a few minutes. This notebook touches all three pillars: IPC (read/write Arrow streams), Arrow Flight (client/server), and ADBC (query databases and get Arrow results).

Configure adbc to use the SQLite driver (for section 5):

Application.put_env(:adbc, :drivers, [:sqlite])
db = Kino.start_child!({Adbc.Database, driver: :sqlite})
conn = Kino.start_child!({Adbc.Connection, database: db})
{:ok, result} = Adbc.Connection.query(conn, "SELECT 1 AS n, 'hello' AS msg")

1. Setup

Add ex_arrow to your Mix project and start a Livebook (or run in IEx). Here we assume the dependency is already in place.

# Verify the NIF loaded
ExArrow.native_version()

2. IPC: Read an Arrow stream

ExArrow can read Arrow IPC from a binary (e.g. from a file, socket, or HTTP body). We’ll use a small built-in fixture so you can run this without any external file.

# Get a small IPC stream binary (schema: id int64, name utf8; 2 rows)
{:ok, ipc_bytes} = ExArrow.Native.ipc_test_fixture_binary()

# Open a stream from the binary
{:ok, stream} = ExArrow.IPC.Reader.from_binary(ipc_bytes)

# Inspect schema (without consuming the stream)
{:ok, schema} = ExArrow.Stream.schema(stream)
ExArrow.Schema.fields(schema) |> Enum.map(& &1.name)

Read batches one at a time until the stream is done:

# First batch
batch1 = ExArrow.Stream.next(stream)
if batch1, do: ExArrow.RecordBatch.num_rows(batch1), else: nil

# Second call: no more batches
ExArrow.Stream.next(stream)

3. IPC: Write then read (roundtrip)

You can write the same schema and batches back to a binary or file, then read again.

# Rebuild stream from fixture and collect schema + all batches
{:ok, ipc_bytes} = ExArrow.Native.ipc_test_fixture_binary()
{:ok, stream} = ExArrow.IPC.Reader.from_binary(ipc_bytes)
{:ok, schema} = ExArrow.Stream.schema(stream)

batches =
  Stream.repeatedly(fn -> ExArrow.Stream.next(stream) end)
  |> Enum.take_while(&(is_struct(&1, ExArrow.RecordBatch)))

# Write to binary
{:ok, out_binary} = ExArrow.IPC.Writer.to_binary(schema, batches)
byte_size(out_binary)

4. Arrow Flight: Echo server and client

Arrow Flight is a gRPC-based protocol for streaming Arrow data. ExArrow includes a small echo server: you upload data with do_put, then download it with do_get using the ticket "echo".

Start the server (one cell), then use the client in the next.


## Start the built-in echo server on port 9999

{:ok, server} = ExArrow.Flight.Server.start_link(9999, [])
ExArrow.Flight.Server.port(server)

## Connect and upload our fixture data

{:ok, ipc_bytes} = ExArrow.Native.ipc_test_fixture_binary()
{:ok, stream} = ExArrow.IPC.Reader.from_binary(ipc_bytes)
{:ok, schema} = ExArrow.Stream.schema(stream)
batches = Stream.repeatedly(fn -> ExArrow.Stream.next(stream) end) |> Enum.take_while(&is_struct(&1, ExArrow.RecordBatch))

{:ok, client} = ExArrow.Flight.Client.connect("localhost", 9999, [])
:ok = ExArrow.Flight.Client.do_put(client, schema, batches)

## Download the same data via do_get

{:ok, down_stream} = ExArrow.Flight.Client.do_get(client, "echo")
{:ok, down_schema} = ExArrow.Stream.schema(down_stream)

Mix.install([ {:exarrow, path: Path.join(_DIR, “..”)}, {:rustler, “~> 0.32.0”, optional: true}, {:adbc, “~> 0.7”},

], config: [adbc: [drivers: [:sqlite]]] ) first = ExArrow.Stream.next(down_stream) ExArrow.RecordBatch.num_rows(first)

Clean up

ExArrow.Flight.Server.stop(server)


---

### 5. ADBC: Query a database, get Arrow results

With ADBC you open a database (e.g. SQLite), run SQL, and get an **Arrow stream** of result batches—same `ExArrow.Stream` API as IPC and Flight.

**Note:** ExArrow's ADBC layer uses the **C driver manager** and needs a **loadable shared library** (e.g. `libadbc_driver_sqlite.so`). The [`adbc`](https://hex.pm/packages/adbc) Hex package has its own process-based Database/Connection and native stack; its drivers are not necessarily loadable by ExArrow. So if opening with ExArrow fails below, we fall back to the adbc package's API so you still see a working query. To use ExArrow's ADBC (and get `ExArrow.Stream` batches), see [Installing an ADBC driver](INSTALL_ADBC_DRIVER.md).

Try ExArrow first (needs a driver loadable by the ADBC C driver manager)

ex_arrow_db = ExArrow.ADBC.Database.open(driver_name: “adbc_driver_sqlite”, uri: “:memory:”) |> case do

{:ok, _} = ok -> ok
{:error, _} -> ExArrow.ADBC.DriverHelper.ensure_driver_and_open(:sqlite, ":memory:")

end

case ex_arrow_db do {:ok, db} ->

# ExArrow path: Arrow stream of record batches
{:ok, conn} = ExArrow.ADBC.Connection.open(db)
{:ok, stmt} = ExArrow.ADBC.Statement.new(conn, "SELECT 1 AS n, 'hello' AS msg")
{:ok, stream} = ExArrow.ADBC.Statement.execute(stmt)
{:ok, schema} = ExArrow.Stream.schema(stream)
batch = ExArrow.Stream.next(stream)
IO.inspect(ExArrow.Schema.fields(schema), label: "Columns (ExArrow)")
IO.inspect(ExArrow.RecordBatch.num_rows(batch), label: "Rows")

->

# Fallback: adbc package's own API (works when the package is in deps)
if Code.ensure_loaded?(Kino) and Code.ensure_loaded?(Adbc.Database) do
  db = Kino.start_child!({Adbc.Database, driver: :sqlite})
  conn = Kino.start_child!({Adbc.Connection, database: db})
  {:ok, result} = Adbc.Connection.query(conn, "SELECT 1 AS n, 'hello' AS msg")
  IO.inspect(result, label: "Query result (adbc package API)")
  IO.puts("\n(ExArrow's ADBC could not load a driver. This uses the adbc package's Database/Connection. For ExArrow Arrow streams, install a standalone ADBC C driver: see livebook/INSTALL_ADBC_DRIVER.md)")
else
  IO.puts("ADBC driver not available: #{msg}")
  IO.puts("See livebook/INSTALL_ADBC_DRIVER.md for how to install a driver ExArrow can load.")
end

end


---

### Next steps

* **Notebook 01 — IPC**: Stream vs file format, reading from files, writing to files, schema and types.
* **Notebook 02 — Flight**: Full server/client API: `list_flights`, `get_flight_info`, `get_schema`, actions.
* **Notebook 03 — ADBC**: Metadata APIs, optional Explorer roundtrip, and production tips.

Docs: [hexdocs.pm/ex_arrow](https://hexdocs.pm/ex_arrow).