Skip to content

Pre-release documentation

This describes Beacon 2.0.0-rc3, a release candidate. Behavior documented here may still change before 2.0.0 ships, and some of it is not in any released build yet. For the current stable release, see the 1.8.0 documentation.

Query a File Collection

Scientific data comes as many files, not as one file. This guide makes one queryable table from a directory of files.

It works through one small collection end to end, and shows the result of each step, so you can see the shape Beacon returns before you run anything.

The collection

text
argo/
  2024/01/  R6901234_001.nc  R6901234_002.nc  R6901235_001.nc
  2024/02/  R6901234_003.nc  R6901236_001.nc
  2024/03/  R6901235_002.nc  R6901236_002.nc

Seven files, one Argo profile each. Each file holds N_PROF = 1 and N_LEVELS = 400, so each one carries 400 rows.

1. Look before you query

Read the columns and the types first. This opens metadata only:

sql
SELECT * FROM read_netcdf_schema('argo/2024/01/*.nc');
column_namedata_typenullable
PLATFORM_NUMBERUtf8true
JULDTimestamp(Nanosecond)true
LATITUDEFloat64true
LONGITUDEFloat64true
PRESFloat64true
TEMPFloat64true
PSALFloat64true

Then look at rows:

sql
SELECT PLATFORM_NUMBER, JULD, LATITUDE, PRES, TEMP
FROM read_netcdf('argo/2024/01/*.nc')
LIMIT 5;
PLATFORM_NUMBERJULDLATITUDEPRESTEMP
69012342024-01-03 06:12:0043.1172.614.882
69012342024-01-03 06:12:0043.1176.114.879
69012342024-01-03 06:12:0043.11710.414.851
69012342024-01-03 06:12:0043.11715.214.774
69012342024-01-03 06:12:0043.11720.014.702

PLATFORM_NUMBER, JULD and LATITUDE repeat, because they are per-profile values broadcast across the 400 levels. See Arrays to tables.

Check the size:

sql
SELECT count(*) AS rows FROM read_netcdf('argo/2024/01/*.nc');
rows
1200

Three files, 400 levels each.

SUMMARIZE profiles every column in one pass. It gives the type, the null count and the range:

sql
SUMMARIZE (SELECT * FROM read_netcdf('argo/2024/01/*.nc'));

2. Widen the glob

** goes into every subdirectory. One call can therefore cover the whole archive:

sql
SELECT count(*) AS rows, count(DISTINCT PLATFORM_NUMBER) AS floats
FROM read_netcdf('argo/**/*.nc');
rowsfloats
28003

All seven files, 400 levels each. Now narrow it:

sql
SELECT PLATFORM_NUMBER, JULD, LATITUDE, LONGITUDE, TEMP
FROM read_netcdf('argo/**/*.nc')
WHERE TEMP > 20
  AND JULD >= '2024-02-01';

Beacon merges the schemas of the files. It reads them in parallel. It also prunes the files that cannot match the filters. Make the WHERE clause as specific as possible. The clause lets the engine skip data.

Pass a list to combine different locations in one query:

sql
SELECT * FROM read_netcdf(['argo/**/*.nc', 'wod/**/*.nc']);

3. Handle schema differences

Files from different sources have different columns. UNION BY NAME aligns them by column name, not by position. Beacon sets a missing column to null:

sql
SELECT time, temperature FROM read_netcdf('argo/**/*.nc')
UNION ALL BY NAME
SELECT time, temperature FROM read_parquet('gliders/*.parquet');

See UNION BY NAME.

Some NetCDF collections mix variables with different dimensions. Give an explicit dimension list. Beacon then returns only the compatible variables:

sql
SELECT * FROM read_netcdf('argo/**/*.nc', ['time', 'pressure']);

4. Use the metadata

Beacon gives the variable attributes as columns in dot notation. A file attribute uses a leading dot. Quote these names, because they contain a dot:

sql
SELECT temperature, "temperature.units", ".source"
FROM read_netcdf('argo/**/*.nc')
LIMIT 1;

5. Give it a name

Register the glob when it is final. Your queries then no longer repeat the path:

sql
CREATE EXTERNAL TABLE argo
STORED AS NC
LOCATION 'argo/**/*.nc';

SELECT platform, avg(temperature) FROM argo GROUP BY platform;

See External Tables.

6. If it is slow

Do you scan thousands of NetCDF or Zarr files often? Then merge them into one Atlas collection. Atlas drops whole datasets with its stored statistics. See Speed Up Slow Queries.

Released under the AGPL-3.0 License.