stac-fastapi-core 4.2.0__py3-none-any.whl → 5.0.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,232 +0,0 @@
1
- """Database logic core."""
2
-
3
- import os
4
- from functools import lru_cache
5
- from typing import Any, Dict, List, Optional, Protocol
6
-
7
- from stac_fastapi.types.stac import Item
8
-
9
-
10
- # stac_pydantic classes extend _GeometryBase, which doesn't have a type field,
11
- # So create our own Protocol for typing
12
- # Union[ Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon, GeometryCollection]
13
- class Geometry(Protocol): # noqa
14
- type: str
15
- coordinates: Any
16
-
17
-
18
- COLLECTIONS_INDEX = os.getenv("STAC_COLLECTIONS_INDEX", "collections")
19
- ITEMS_INDEX_PREFIX = os.getenv("STAC_ITEMS_INDEX_PREFIX", "items_")
20
-
21
- ES_INDEX_NAME_UNSUPPORTED_CHARS = {
22
- "\\",
23
- "/",
24
- "*",
25
- "?",
26
- '"',
27
- "<",
28
- ">",
29
- "|",
30
- " ",
31
- ",",
32
- "#",
33
- ":",
34
- }
35
-
36
- _ES_INDEX_NAME_UNSUPPORTED_CHARS_TABLE = str.maketrans(
37
- "", "", "".join(ES_INDEX_NAME_UNSUPPORTED_CHARS)
38
- )
39
-
40
- ITEM_INDICES = f"{ITEMS_INDEX_PREFIX}*,-*kibana*,-{COLLECTIONS_INDEX}*"
41
-
42
- DEFAULT_SORT = {
43
- "properties.datetime": {"order": "desc"},
44
- "id": {"order": "desc"},
45
- "collection": {"order": "desc"},
46
- }
47
-
48
- ES_ITEMS_SETTINGS = {
49
- "index": {
50
- "sort.field": list(DEFAULT_SORT.keys()),
51
- "sort.order": [v["order"] for v in DEFAULT_SORT.values()],
52
- }
53
- }
54
-
55
- ES_MAPPINGS_DYNAMIC_TEMPLATES = [
56
- # Common https://github.com/radiantearth/stac-spec/blob/master/item-spec/common-metadata.md
57
- {
58
- "descriptions": {
59
- "match_mapping_type": "string",
60
- "match": "description",
61
- "mapping": {"type": "text"},
62
- }
63
- },
64
- {
65
- "titles": {
66
- "match_mapping_type": "string",
67
- "match": "title",
68
- "mapping": {"type": "text"},
69
- }
70
- },
71
- # Projection Extension https://github.com/stac-extensions/projection
72
- {"proj_epsg": {"match": "proj:epsg", "mapping": {"type": "integer"}}},
73
- {
74
- "proj_projjson": {
75
- "match": "proj:projjson",
76
- "mapping": {"type": "object", "enabled": False},
77
- }
78
- },
79
- {
80
- "proj_centroid": {
81
- "match": "proj:centroid",
82
- "mapping": {"type": "geo_point"},
83
- }
84
- },
85
- {
86
- "proj_geometry": {
87
- "match": "proj:geometry",
88
- "mapping": {"type": "object", "enabled": False},
89
- }
90
- },
91
- {
92
- "no_index_href": {
93
- "match": "href",
94
- "mapping": {"type": "text", "index": False},
95
- }
96
- },
97
- # Default all other strings not otherwise specified to keyword
98
- {"strings": {"match_mapping_type": "string", "mapping": {"type": "keyword"}}},
99
- {"long_to_double": {"match_mapping_type": "long", "mapping": {"type": "double"}}},
100
- {
101
- "double_to_double": {
102
- "match_mapping_type": "double",
103
- "mapping": {"type": "double"},
104
- }
105
- },
106
- ]
107
-
108
- ES_ITEMS_MAPPINGS = {
109
- "numeric_detection": False,
110
- "dynamic_templates": ES_MAPPINGS_DYNAMIC_TEMPLATES,
111
- "properties": {
112
- "id": {"type": "keyword"},
113
- "collection": {"type": "keyword"},
114
- "geometry": {"type": "geo_shape"},
115
- "assets": {"type": "object", "enabled": False},
116
- "links": {"type": "object", "enabled": False},
117
- "properties": {
118
- "type": "object",
119
- "properties": {
120
- # Common https://github.com/radiantearth/stac-spec/blob/master/item-spec/common-metadata.md
121
- "datetime": {"type": "date"},
122
- "start_datetime": {"type": "date"},
123
- "end_datetime": {"type": "date"},
124
- "created": {"type": "date"},
125
- "updated": {"type": "date"},
126
- # Satellite Extension https://github.com/stac-extensions/sat
127
- "sat:absolute_orbit": {"type": "integer"},
128
- "sat:relative_orbit": {"type": "integer"},
129
- },
130
- },
131
- },
132
- }
133
-
134
- ES_COLLECTIONS_MAPPINGS = {
135
- "numeric_detection": False,
136
- "dynamic_templates": ES_MAPPINGS_DYNAMIC_TEMPLATES,
137
- "properties": {
138
- "id": {"type": "keyword"},
139
- "extent.spatial.bbox": {"type": "long"},
140
- "extent.temporal.interval": {"type": "date"},
141
- "providers": {"type": "object", "enabled": False},
142
- "links": {"type": "object", "enabled": False},
143
- "item_assets": {"type": "object", "enabled": False},
144
- },
145
- }
146
-
147
-
148
- @lru_cache(256)
149
- def index_by_collection_id(collection_id: str) -> str:
150
- """
151
- Translate a collection id into an Elasticsearch index name.
152
-
153
- Args:
154
- collection_id (str): The collection id to translate into an index name.
155
-
156
- Returns:
157
- str: The index name derived from the collection id.
158
- """
159
- cleaned = collection_id.translate(_ES_INDEX_NAME_UNSUPPORTED_CHARS_TABLE)
160
- return (
161
- f"{ITEMS_INDEX_PREFIX}{cleaned.lower()}_{collection_id.encode('utf-8').hex()}"
162
- )
163
-
164
-
165
- @lru_cache(256)
166
- def index_alias_by_collection_id(collection_id: str) -> str:
167
- """
168
- Translate a collection id into an Elasticsearch index alias.
169
-
170
- Args:
171
- collection_id (str): The collection id to translate into an index alias.
172
-
173
- Returns:
174
- str: The index alias derived from the collection id.
175
- """
176
- cleaned = collection_id.translate(_ES_INDEX_NAME_UNSUPPORTED_CHARS_TABLE)
177
- return f"{ITEMS_INDEX_PREFIX}{cleaned}"
178
-
179
-
180
- def indices(collection_ids: Optional[List[str]]) -> str:
181
- """
182
- Get a comma-separated string of index names for a given list of collection ids.
183
-
184
- Args:
185
- collection_ids: A list of collection ids.
186
-
187
- Returns:
188
- A string of comma-separated index names. If `collection_ids` is empty, returns the default indices.
189
- """
190
- return (
191
- ",".join(map(index_alias_by_collection_id, collection_ids))
192
- if collection_ids
193
- else ITEM_INDICES
194
- )
195
-
196
-
197
- def mk_item_id(item_id: str, collection_id: str) -> str:
198
- """Create the document id for an Item in Elasticsearch.
199
-
200
- Args:
201
- item_id (str): The id of the Item.
202
- collection_id (str): The id of the Collection that the Item belongs to.
203
-
204
- Returns:
205
- str: The document id for the Item, combining the Item id and the Collection id, separated by a `|` character.
206
- """
207
- return f"{item_id}|{collection_id}"
208
-
209
-
210
- def mk_actions(collection_id: str, processed_items: List[Item]) -> List[Dict[str, Any]]:
211
- """Create Elasticsearch bulk actions for a list of processed items.
212
-
213
- Args:
214
- collection_id (str): The identifier for the collection the items belong to.
215
- processed_items (List[Item]): The list of processed items to be bulk indexed.
216
-
217
- Returns:
218
- List[Dict[str, Union[str, Dict]]]: The list of bulk actions to be executed,
219
- each action being a dictionary with the following keys:
220
- - `_index`: the index to store the document in.
221
- - `_id`: the document's identifier.
222
- - `_source`: the source of the document.
223
- """
224
- index_alias = index_alias_by_collection_id(collection_id)
225
- return [
226
- {
227
- "_index": index_alias,
228
- "_id": mk_item_id(item["id"], item["collection"]),
229
- "_source": item,
230
- }
231
- for item in processed_items
232
- ]
@@ -1,377 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: stac-fastapi-core
3
- Version: 4.2.0
4
- Summary: Core library for the Elasticsearch and Opensearch stac-fastapi backends.
5
- Home-page: https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch
6
- License: MIT
7
- Classifier: Intended Audience :: Developers
8
- Classifier: Intended Audience :: Information Technology
9
- Classifier: Intended Audience :: Science/Research
10
- Classifier: Programming Language :: Python :: 3.9
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Classifier: Programming Language :: Python :: 3.13
15
- Classifier: License :: OSI Approved :: MIT License
16
- Requires-Python: >=3.9
17
- Description-Content-Type: text/markdown
18
- Requires-Dist: fastapi~=0.109.0
19
- Requires-Dist: attrs>=23.2.0
20
- Requires-Dist: pydantic<3.0.0,>=2.4.1
21
- Requires-Dist: stac-pydantic~=3.1.0
22
- Requires-Dist: stac-fastapi.api==5.2.0
23
- Requires-Dist: stac-fastapi.extensions==5.2.0
24
- Requires-Dist: stac-fastapi.types==5.2.0
25
- Requires-Dist: orjson~=3.9.0
26
- Requires-Dist: overrides~=7.4.0
27
- Requires-Dist: geojson-pydantic~=1.0.0
28
- Requires-Dist: pygeofilter~=0.3.1
29
- Requires-Dist: jsonschema~=4.0.0
30
- Requires-Dist: slowapi~=0.1.9
31
-
32
- # stac-fastapi-elasticsearch-opensearch (sfeos)
33
-
34
- <!-- markdownlint-disable MD033 MD041 -->
35
-
36
- <p align="left">
37
- <img src="https://github.com/radiantearth/stac-site/raw/master/images/logo/stac-030-long.png" width=600>
38
- <p align="left"><b>Elasticsearch and Opensearch backends for the stac-fastapi project.</b></p>
39
- <p align="left"><b>Featuring stac-fastapi.core for simplifying the creation and maintenance of custom STAC api backends.</b></p>
40
- </p>
41
-
42
-
43
- [![PyPI version](https://badge.fury.io/py/stac-fastapi-elasticsearch.svg)](https://badge.fury.io/py/stac-fastapi-elasticsearch) [![PyPI version](https://badge.fury.io/py/stac-fastapi-opensearch.svg)](https://badge.fury.io/py/stac-fastapi-opensearch)
44
- [![Join the chat at https://gitter.im/stac-fastapi-elasticsearch/community](https://badges.gitter.im/stac-fastapi-elasticsearch/community.svg)](https://gitter.im/stac-fastapi-elasticsearch/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
45
-
46
-
47
- ---
48
-
49
- **Online Documentation**: [https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch](https://stac-utils.github.io/stac-fastapi-elasticsearch-opensearch/)
50
-
51
- **Source Code**: [https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch)
52
-
53
-
54
- ---
55
-
56
- ### Notes:
57
-
58
- - Our Api core library can be used to create custom backends. See [stac-fastapi-mongo](https://github.com/Healy-Hyperspatial/stac-fastapi-mongo) for a working example.
59
- - Reach out on our [Gitter](https://app.gitter.im/#/room/#stac-fastapi-elasticsearch_community:gitter.im) channel or feel free to add to our [Discussions](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/discussions) page here on github.
60
- - There is [Postman](https://documenter.getpostman.com/view/12888943/2s8ZDSdRHA) documentation here for examples on how to run some of the API routes locally - after starting the elasticsearch backend via the compose.yml file.
61
- - The `/examples` folder shows an example of running stac-fastapi-elasticsearch from PyPI in docker without needing any code from the repository. There is also a Postman collection here that you can load into Postman for testing the API routes.
62
-
63
-
64
- ### Performance Note
65
-
66
- The `enable_direct_response` option is provided by the stac-fastapi core library (introduced in stac-fastapi 5.2.0) and is available in this project starting from v4.0.0.
67
-
68
- **You can now control this setting via the `ENABLE_DIRECT_RESPONSE` environment variable.**
69
-
70
- When enabled (`ENABLE_DIRECT_RESPONSE=true`), endpoints return Starlette Response objects directly, bypassing FastAPI's default serialization for improved performance. **However, all FastAPI dependencies (including authentication, custom status codes, and validation) are disabled for all routes.**
71
-
72
- This mode is best suited for public or read-only APIs where authentication and custom logic are not required. Default is `false` for safety.
73
-
74
- See: [issue #347](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/issues/347)
75
-
76
-
77
- ### To install from PyPI:
78
-
79
- ```bash
80
- # For versions 4.0.0a1 and newer (PEP 625 compliant naming):
81
- pip install stac-fastapi-elasticsearch # Elasticsearch backend
82
- pip install stac-fastapi-opensearch # Opensearch backend
83
- pip install stac-fastapi-core # Core library
84
-
85
- # For versions 4.0.0a0 and older:
86
- pip install stac-fastapi.elasticsearch # Elasticsearch backend
87
- pip install stac-fastapi.opensearch # Opensearch backend
88
- pip install stac-fastapi.core # Core library
89
- ```
90
-
91
- > **Important Note:** Starting with version 4.0.0a1, package names have changed from using periods (e.g., `stac-fastapi.core`) to using hyphens (e.g., `stac-fastapi-core`) to comply with PEP 625. The internal package structure uses underscores, but users should install with hyphens as shown above. Please update your requirements files accordingly.
92
-
93
- ### To install and run via pre-built Docker Images
94
-
95
- We provide ready-to-use Docker images through GitHub Container Registry ([ElasticSearch](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pkgs/container/stac-fastapi-es) and [OpenSearch](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pkgs/container/stac-fastapi-os) backends). You can easily pull and run these images:
96
-
97
- ```shell
98
- # For Elasticsearch backend
99
- docker pull ghcr.io/stac-utils/stac-fastapi-es:latest
100
-
101
- # For OpenSearch backend
102
- docker pull ghcr.io/stac-utils/stac-fastapi-os:latest
103
- ```
104
-
105
- ## Run Elasticsearch API backend on localhost:8080
106
-
107
- You need to ensure [**Docker Compose**](https://docs.docker.com/compose/install/) or [**Podman Compose**](https://podman-desktop.io/docs/compose) installed and running on your machine. In the following command instead of `docker compose` you can use `podman-compose` as well.
108
-
109
- ```shell
110
- docker compose up elasticsearch app-elasticsearch
111
- ```
112
-
113
- By default, Docker Compose uses Elasticsearch 8.x and OpenSearch 2.11.1.
114
- If you wish to use a different version, put the following in a
115
- file named `.env` in the same directory you run Docker Compose from:
116
-
117
- ```shell
118
- ELASTICSEARCH_VERSION=8.11.0
119
- OPENSEARCH_VERSION=2.11.1
120
- ENABLE_DIRECT_RESPONSE=false
121
- ```
122
- The most recent Elasticsearch 7.x versions should also work. See the [opensearch-py docs](https://github.com/opensearch-project/opensearch-py/blob/main/COMPATIBILITY.md) for compatibility information.
123
-
124
- #### **Configuration reference keys:**
125
-
126
- You can customize additional settings in your `.env` file:
127
- ###### Key variables to configure:
128
-
129
- | Variable | Description | Default | Required |
130
- |------------------------------|--------------------------------------------------------------------------------------|--------------------------|---------------------------------------------------------------------------------------------|
131
- | `ES_HOST` | Hostname for external Elasticsearch/OpenSearch. | `localhost` | Optional |
132
- | `ES_PORT` | Port for Elasticsearch/OpenSearch. | `9200` (ES) / `9202` (OS)| Optional |
133
- | `ES_USE_SSL` | Use SSL for connecting to Elasticsearch/OpenSearch. | `false` | Optional |
134
- | `ES_VERIFY_CERTS` | Verify SSL certificates when connecting. | `false` | Optional |
135
- | `STAC_FASTAPI_TITLE` | Title of the API in the documentation. | `stac-fastapi-elasticsearch` or `stac-fastapi-opensearch` | Optional |
136
- | `STAC_FASTAPI_DESCRIPTION` | Description of the API in the documentation. | N/A | Optional |
137
- | `STAC_FASTAPI_VERSION` | API version. | `2.1` | Optional |
138
- | `STAC_FASTAPI_LANDING_PAGE_ID` | Landing page ID | `stac-fastapi` | Optional |
139
- | `APP_HOST` | Server bind address. | `0.0.0.0` | Optional |
140
- | `APP_PORT` | Server port. | `8080` | Optional |
141
- | `ENVIRONMENT` | Runtime environment. | `local` | Optional |
142
- | `WEB_CONCURRENCY` | Number of worker processes. | `10` | Optional |
143
- | `RELOAD` | Enable auto-reload for development. | `true` | Optional |
144
- | `STAC_FASTAPI_RATE_LIMIT` | API rate limit per client. | `200/minute` | Optional |
145
- | `BACKEND` | Tests-related variable | `elasticsearch` or `opensearch` based on the backend | Optional |
146
- | `ELASTICSEARCH_VERSION` | Version of Elasticsearch to use. | `8.11.0` | Optional | |
147
- | `OPENSEARCH_VERSION` | OpenSearch version | `2.11.1` | Optional
148
- | `ENABLE_DIRECT_RESPONSE` | Enable direct response for maximum performance (disables all FastAPI dependencies, including authentication, custom status codes, and validation) | `false` | Optional
149
- | `RAISE_ON_BULK_ERROR` | Controls whether bulk insert operations raise exceptions on errors. If set to `true`, the operation will stop and raise an exception when an error occurs. If set to `false`, errors will be logged, and the operation will continue. **Note:** STAC Item and ItemCollection validation errors will always raise, regardless of this flag. | `false` Optional |
150
- | `DATABASE_REFRESH` | Controls whether database operations refresh the index immediately after changes. If set to `true`, changes will be immediately searchable. If set to `false`, changes may not be immediately visible but can improve performance for bulk operations. If set to `wait_for`, changes will wait for the next refresh cycle to become visible. | `false` | Optional |
151
- | `ENABLE_TRANSACTIONS_EXTENSIONS` | Enables or disables the Transactions and Bulk Transactions API extensions. If set to `false`, the POST `/collections` route and related transaction endpoints (including bulk transaction operations) will be unavailable in the API. This is useful for deployments where mutating the catalog via the API should be prevented. | `true` | Optional |
152
-
153
- > [!NOTE]
154
- > The variables `ES_HOST`, `ES_PORT`, `ES_USE_SSL`, and `ES_VERIFY_CERTS` apply to both Elasticsearch and OpenSearch backends, so there is no need to rename the key names to `OS_` even if you're using OpenSearch.
155
-
156
- ## Interacting with the API
157
-
158
- To create a new Collection:
159
-
160
- ```shell
161
- curl -X "POST" "http://localhost:8080/collections" \
162
- -H 'Content-Type: application/json; charset=utf-8' \
163
- -d $'{
164
- "id": "my_collection"
165
- }'
166
- ```
167
-
168
- Note: this "Collections Transaction" behavior is not part of the STAC API, but may be soon.
169
-
170
- ## Configure the API
171
-
172
- By default the API title and description are set to `stac-fastapi-<backend>`. Change the API title and description from the default by setting the `STAC_FASTAPI_TITLE` and `STAC_FASTAPI_DESCRIPTION` environment variables, respectively.
173
-
174
- By default the API will read from and write to the `collections` and `items_<collection name>` indices. To change the API collections index and the items index prefix, change the `STAC_COLLECTIONS_INDEX` and `STAC_ITEMS_INDEX_PREFIX` environment variables.
175
-
176
- The application root path is left as the base url by default. If deploying to AWS Lambda with a Gateway API, you will need to define the app root path to be the same as the Gateway API stage name where you will deploy the API. The app root path can be defined with the `STAC_FASTAPI_ROOT_PATH` environment variable (`/v1`, for example)
177
-
178
- ## Collection pagination
179
-
180
- The collections route handles optional `limit` and `token` parameters. The `links` field that is
181
- returned from the `/collections` route contains a `next` link with the token that can be used to
182
- get the next page of results.
183
-
184
- ```shell
185
- curl -X "GET" "http://localhost:8080/collections?limit=1&token=example_token"
186
- ```
187
-
188
- ## Ingesting Sample Data CLI Tool
189
-
190
- ```shell
191
- Usage: data_loader.py [OPTIONS]
192
-
193
- Load STAC items into the database.
194
-
195
- Options:
196
- --base-url TEXT Base URL of the STAC API [required]
197
- --collection-id TEXT ID of the collection to which items are added
198
- --use-bulk Use bulk insert method for items
199
- --data-dir PATH Directory containing collection.json and feature
200
- collection file
201
- --help Show this message and exit.
202
- ```
203
-
204
- ```shell
205
- python3 data_loader.py --base-url http://localhost:8080
206
- ```
207
-
208
-
209
- ## Elasticsearch Mappings
210
-
211
- Mappings apply to search index, not source. The mappings are stored in index templates on application startup.
212
- These templates will be used implicitly when creating new Collection and Item indices.
213
-
214
-
215
- ## Managing Elasticsearch Indices
216
- ### Snapshots
217
-
218
- This section covers how to create a snapshot repository and then create and restore snapshots with this.
219
-
220
- Create a snapshot repository. This puts the files in the `elasticsearch/snapshots` in this git repo clone, as
221
- the elasticsearch.yml and compose files create a mapping from that directory to
222
- `/usr/share/elasticsearch/snapshots` within the Elasticsearch container and grant permissions on using it.
223
-
224
- ```shell
225
- curl -X "PUT" "http://localhost:9200/_snapshot/my_fs_backup" \
226
- -H 'Content-Type: application/json; charset=utf-8' \
227
- -d $'{
228
- "type": "fs",
229
- "settings": {
230
- "location": "/usr/share/elasticsearch/snapshots/my_fs_backup"
231
- }
232
- }'
233
- ```
234
-
235
- The next step is to create a snapshot of one or more indices into this snapshot repository. This command creates
236
- a snapshot named `my_snapshot_2` and waits for the action to be completed before returning. This can also be done
237
- asynchronously, and queried for status. The `indices` parameter determines which indices are snapshotted, and
238
- can include wildcards.
239
-
240
- ```shell
241
- curl -X "PUT" "http://localhost:9200/_snapshot/my_fs_backup/my_snapshot_2?wait_for_completion=true" \
242
- -H 'Content-Type: application/json; charset=utf-8' \
243
- -d $'{
244
- "metadata": {
245
- "taken_because": "dump of all items",
246
- "taken_by": "pvarner"
247
- },
248
- "include_global_state": false,
249
- "ignore_unavailable": false,
250
- "indices": "items_my-collection"
251
- }'
252
- ```
253
-
254
- To see the status of this snapshot:
255
-
256
- ```shell
257
- curl http://localhost:9200/_snapshot/my_fs_backup/my_snapshot_2
258
- ```
259
-
260
- To see all the snapshots:
261
-
262
- ```shell
263
- curl http://localhost:9200/_snapshot/my_fs_backup/_all
264
- ```
265
-
266
- To restore a snapshot, run something similar to the following. This specific command will restore any indices that
267
- match `items_*` and rename them so that the new index name will be suffixed with `-copy`.
268
-
269
- ```shell
270
- curl -X "POST" "http://localhost:9200/_snapshot/my_fs_backup/my_snapshot_2/_restore?wait_for_completion=true" \
271
- -H 'Content-Type: application/json; charset=utf-8' \
272
- -d $'{
273
- "include_aliases": false,
274
- "include_global_state": false,
275
- "ignore_unavailable": true,
276
- "rename_replacement": "items_$1-copy",
277
- "indices": "items_*",
278
- "rename_pattern": "items_(.+)"
279
- }'
280
- ```
281
-
282
- Now the item documents have been restored in to the new index (e.g., `my-collection-copy`), but the value of the
283
- `collection` field in those documents is still the original value of `my-collection`. To update these to match the
284
- new collection name, run the following Elasticsearch Update By Query command, substituting the old collection name
285
- into the term filter and the new collection name into the script parameter:
286
-
287
- ```shell
288
- curl -X "POST" "http://localhost:9200/items_my-collection-copy/_update_by_query" \
289
- -H 'Content-Type: application/json; charset=utf-8' \
290
- -d $'{
291
- "query": {
292
- "match_all": {}
293
- },
294
- "script": {
295
- "lang": "painless",
296
- "params": {
297
- "collection": "my-collection-copy"
298
- },
299
- "source": "ctx._source.collection = params.collection"
300
- }
301
- }'
302
- ```
303
-
304
- Then, create a new collection through the api with the new name for each of the restored indices:
305
-
306
- ```shell
307
- curl -X "POST" "http://localhost:8080/collections" \
308
- -H 'Content-Type: application/json' \
309
- -d $'{
310
- "id": "my-collection-copy"
311
- }'
312
- ```
313
-
314
- Voila! You have a copy of the collection now that has a resource URI (`/collections/my-collection-copy`) and can be
315
- correctly queried by collection name.
316
-
317
- ### Reindexing
318
- This section covers how to reindex documents stored in Elasticsearch/OpenSearch.
319
- A reindex operation might be useful to apply changes to documents or to correct dynamically generated mappings.
320
-
321
- The index templates will make sure that manually created indices will also have the correct mappings and settings.
322
-
323
- In this example, we will make a copy of an existing Item index `items_my-collection-lower_my-collection-hex-000001` but change the Item identifier to be lowercase.
324
-
325
- ```shell
326
- curl -X "POST" "http://localhost:9200/_reindex" \
327
- -H 'Content-Type: application/json' \
328
- -d $'{
329
- "source": {
330
- "index": "items_my-collection-lower_my-collection-hex-000001"
331
- },
332
- "dest": {
333
- "index": "items_my-collection-lower_my-collection-hex-000002"
334
- },
335
- "script": {
336
- "source": "ctx._source.id = ctx._source.id.toLowerCase()",
337
- "lang": "painless"
338
- }
339
- }'
340
- ```
341
-
342
- If we are happy with the data in the newly created index, we can move the alias `items_my-collection` to the new index `items_my-collection-lower_my-collection-hex-000002`.
343
- ```shell
344
- curl -X "POST" "http://localhost:9200/_aliases" \
345
- -h 'Content-Type: application/json' \
346
- -d $'{
347
- "actions": [
348
- {
349
- "remove": {
350
- "index": "*",
351
- "alias": "items_my-collection"
352
- }
353
- },
354
- {
355
- "add": {
356
- "index": "items_my-collection-lower_my-collection-hex-000002",
357
- "alias": "items_my-collection"
358
- }
359
- }
360
- ]
361
- }'
362
- ```
363
-
364
- The modified Items with lowercase identifiers will now be visible to users accessing `my-collection` in the STAC API.
365
-
366
-
367
- ## Auth
368
-
369
- Authentication is an optional feature that can be enabled through `Route Dependencies` examples can be found and a more detailed explanation in [examples/auth](examples/auth).
370
-
371
- ## Aggregation
372
-
373
- Aggregation of points and geometries, as well as frequency distribution aggregation of any other property including dates is supported in stac-fatsapi-elasticsearch-opensearch. Aggregations can be defined at the root Catalog level (`/aggregations`) and at the Collection level (`/<collection_id>/aggregations`). Details for supported aggregations can be found in [the aggregation docs](./docs/src/aggregation.md)
374
-
375
- ## Rate Limiting
376
-
377
- Rate limiting is an optional security feature that controls API request frequency on a remote address basis. It's enabled by setting the `STAC_FASTAPI_RATE_LIMIT` environment variable, e.g., `500/minute`. This limits each client to 500 requests per minute, helping prevent abuse and maintain API stability. Implementation examples are available in the [examples/rate_limit](examples/rate_limit) directory.