Skip to content

Commit fe119fe

Browse files
bitnermmcfarland
andauthored
add docs for queryables (#176)
* add docs for queryables * Formatting and fixups * Fixups * typo * More typos! --------- Co-authored-by: Matt McFarland <[email protected]>
1 parent 3cb13a8 commit fe119fe

File tree

1 file changed

+69
-6
lines changed

1 file changed

+69
-6
lines changed

docs/src/pgstac.md

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ PGStac installs everything into the pgstac schema in the database. This schema m
1212
#### PGStac Users
1313
The pgstac_admin role is the owner of all the objects within pgstac and should be used when running things such as migrations.
1414

15-
The pgstac_ingest role has read/write priviliges on all tables and should be used for data ingest or if using the transactions extension with stac-fastapi-pgstac.
15+
The pgstac_ingest role has read/write privileges on all tables and should be used for data ingest or if using the transactions extension with stac-fastapi-pgstac.
1616

1717
The pgstac_read role has read only access to the items and collections, but will still be able to write to the logging tables.
1818

@@ -51,7 +51,7 @@ The context is "off" by default, and the default filter language is set to "cql2
5151

5252
Variables can be set either by passing them in via the connection options using your connection library, setting them in the pgstac_settings table or by setting them on the Role that is used to log in to the database.
5353

54-
Turning "context" on can be **very** expensive on larger databases. Much of what PGStac does is to optimize the search of items sorted by time where only fewer than 10,000 records are returned at a time. It does this by searching for the data in chunks and is able to "short circuit" and return as soon as it has the number of records requested. Calculating the context (the total count for a query) requires a scan of all records that match the query parameters and can take a very long time. Settting "context" to auto will use database statistics to estimate the number of rows much more quickly, but for some queries, the estimate may be quite a bit off.
54+
Turning "context" on can be **very** expensive on larger databases. Much of what PGStac does is to optimize the search of items sorted by time where only fewer than 10,000 records are returned at a time. It does this by searching for the data in chunks and is able to "short circuit" and return as soon as it has the number of records requested. Calculating the context (the total count for a query) requires a scan of all records that match the query parameters and can take a very long time. Setting "context" to auto will use database statistics to estimate the number of rows much more quickly, but for some queries, the estimate may be quite a bit off.
5555

5656
Example for updating the pgstac_settings table with a new value:
5757
```sql
@@ -72,7 +72,7 @@ ALTER ROLE <username> SET pgstac.context_estimated_cost TO '<estimated query cos
7272
ALTER ROLE <username> SET pgstac.context_stats_ttl TO '<an interval string ie "1 day" after which pgstac search will force recalculation of it's estimates>>';
7373
```
7474
75-
The check_pgstac_settings function can be used to check what pgstac settings are being used and to check recomendations for system settings. It takes a single parameter which should be the amount of memory available on the database system.
75+
The check_pgstac_settings function can be used to check what pgstac settings are being used and to check recommendations for system settings. It takes a single parameter which should be the amount of memory available on the database system.
7676
```sql
7777
SELECT check_pgstac_settings('16GB');
7878
```
@@ -97,20 +97,83 @@ UPDATE collections set partition_trunc='month' WHERE id='<collection id>';
9797
In general, you should aim to keep each partition less than a few hundred thousand rows. Further partitioning (ie setting everything to 'month' when not needed to keep the partitions below a few hundred thousand rows) can be detrimental.
9898
9999
#### PGStac Indexes / Queryables
100+
100101
By default, PGStac includes indexes on the id, datetime, collection, geometry, and the eo:cloud_cover property. Further indexing can be added for additional properties globally or only on particular collections by modifications to the queryables table.
101102
102-
Currently indexing is the only place the queryables table is used, but in future versions, it will be extended to provide a queryables backend api.
103+
The `queryables` table controls the indexes that PGStac will build as well as the metadata that is returned from a [STAC Queryables endpoint](https://github.com/stac-api-extensions/filter#queryables).
104+
105+
| Column | Description | Type | Example |
106+
|-----------------------|--------------------------------------------------------------------------|------------|--------------------------------------------------------------------------------------------------------------------|
107+
| `id` | The id of the queryable | bigint[pk] | - |
108+
| `name` | The name of the property | text | `eo:cloud_cover` |
109+
| `collection_ids` | The collection ids that this queryable applies to | text[] | `{sentinel-2-l2a,landsat-c2-l2,aster-l1t}` or `NULL` |
110+
| `definition` | The queryable definition of the property | jsonb | `{"title": "Cloud Cover", "type": "number", "minimum": 0, "maximum": 100}` |
111+
| `property_wrapper` | The wrapper function to use to convert the property to a searchable type | text | One of `to_int`, `to_float`, `to_tstz`, `to_text` or `NULL` |
112+
| `property_index_type` | The index type to use for the property | text | `BTREE`, `NULL` or other valid [PostgreSQL index type](https://www.postgresql.org/docs/current/indexes-types.html) |
113+
114+
Each record in the queryables table references a single property but can apply to any number of collections. If the `collection_ids` field is left as NULL, then that queryable will apply to all collections. There are constraints that allow only a single queryable record to be active per collection. If there is a queryable already set for a property field with collection_ids set to NULL, you will not be able to create a separate queryable entry that applies to that property with a specific collection as pgstac would not then be able to determine which queryable entry to use.
115+
116+
##### Queryable Metadata
117+
118+
When used with [stac-fastapi](https://stac-utils.github.io/stac-fastapi/), the metadata returned in the queryables endpoint is determined using the definition field on the `queryables` table. This is a jsonb field that will be returned as-is in the queryables response. The full queryable response for a collection will be determined by all the `queryables` records that have a match in `collection_ids` or have a NULL `collection_ids`.
119+
120+
If two or more collections in your catalog share a property name, but have different definitions (e.g., `platform` with different enum values), be sure to repeat the property for each collection id, each with a unique `definition`.
121+
122+
There is a utility SQL function that can be used to help populate the `queryables` table by looking at a sample of data for each collection. This utility can also look to the json schema for STAC extensions defined in the `stac_extensions` table.
123+
124+
The `stac_extensions` table contains a `url` field and a `content` field for each extension that should be introspected to compare for fields. This can either be filled in manually or by using the `pypgstac loadextensions` command included with pypgstac. This command will look at the `stac_extensions` attribute in all collections to populate the `stac_extensions` table, fetching the json content of each extension. If any urls were added manually to the stac_extensions table, it will also populate any records where the content is NULL.
125+
126+
Once the `stac_extensions` table has been filled in, you can run the `missing_queryables` function either for a single collection:
127+
128+
```sql
129+
SELECT * FROM missing_queryables('mycollection', 5);
130+
```
131+
132+
or for all collections:
133+
134+
```sql
135+
SELECT * FROM missing_queryables(5);
136+
```
137+
138+
The numeric argument is the approximate percent of items that should be sampled to look for fields to include. This function will look for fields in the properties of items that do not already exist in the queryables table for each collection. It will then look to see if there is a field in any definition in the stac_extensions table to populate the definition for the queryable. If no definition was found, it will use the data type of the values for that field in the sample of items to fill in a generic definition with just the field type.
139+
140+
In order to populate the queryables table, you can then run:
141+
142+
```sql
143+
INSERT INTO queryables (collection_ids, name, definition, property_wrapper) SELECT * FROM missing_queryables(5);
144+
```
145+
146+
If you run into conflicts due to the unique constraints on collection/name, you may need to create a temp table, make any changes to remove the conflicts, and then INSERT.
147+
148+
```sql
149+
CREATE TEMP TABLE draft_queryables AS SELECT * FROM missing_queryables(5);
150+
```
151+
152+
Make any edits to that table or the existing queryables, then:
153+
154+
```sql
155+
INSERT INTO queryables (collection_ids, name, definition, property_wrapper) SELECT * FROM draft_queryables;
156+
```
157+
158+
##### Indexing
159+
160+
The `queryables` table is also used to specify which item `properties` attributes to add indexes on.
161+
162+
To add a new global index across all collection partitions:
103163
104-
To add a new global index across all partitions:
105164
```sql
106165
INSERT INTO pgstac.queryables (name, property_wrapper, property_index_type)
107166
VALUES (<property name>, <property wrapper>, <index type>);
108167
```
109-
Property wrapper should be one of to_int, to_float, to_tstz, or to_text. The index type should almost always be 'BTREE', but can be any PostgreSQL index type valid for the data type.
168+
169+
Property wrapper should be one of `to_int`, `to_float`, `to_tstz`, or `to_text`. The index type should almost always be `BTREE`, but can be any PostgreSQL index type valid for the data type.
110170
111171
**More indexes is note necessarily better.** You should only index the primary fields that are actively being used to search. Adding too many indexes can be very detrimental to performance and ingest speed. If your primary use case is delivering items sorted by datetime and you do not use the context extension, you likely will not need any further indexes.
112172
173+
Leave `property_index_type` set to NULL if you do not want an index set for a property.
174+
113175
### Maintenance Procedures
176+
114177
These are procedures that should be run periodically to make sure that statistics and constraints are kept up-to-date and validated. These can be made to run regularly using the pg_cron extension if available.
115178
```sql
116179
SELECT cron.schedule('0 * * * *', 'CALL validate_constraints();');

0 commit comments

Comments
 (0)