Skip to content

Commit 5b3b145

Browse files
authored
Merge branch 'main' into #213-urlencode-next-href
2 parents c520f4e + 1f2700d commit 5b3b145

File tree

12 files changed

+214
-29
lines changed

12 files changed

+214
-29
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
99

1010
### Added
1111

12+
- use index templates for Collection and Item indices [#208](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/discussions/208)
1213
- Added API `title`, `version`, and `description` parameters from environment variables `STAC_FASTAPI_TITLE`, `STAC_FASTAPI_VERSION` and `STAC_FASTAPI_DESCRIPTION`, respectively. [#207](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/207)
1314

1415
### Changed
1516

1617
### Fixed
1718

1819
- URL encode next href: [#213](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/issues/213)
20+
- Do not overwrite links in Item and Collection objects before persisting in database [#210](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/issues/210)
1921

2022
## [v2.1.0]
2123

README.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,12 @@ make ingest
116116

117117
## Elasticsearch Mappings
118118

119-
Mappings apply to search index, not source.
119+
Mappings apply to search index, not source. The mappings are stored in index templates on application startup.
120+
These templates will be used implicitly when creating new Collection and Item indices.
120121

121122

122123
## Managing Elasticsearch Indices
124+
### Snapshots
123125

124126
This section covers how to create a snapshot repository and then create and restore snapshots with this.
125127

@@ -219,3 +221,52 @@ curl -X "POST" "http://localhost:8080/collections" \
219221

220222
Voila! You have a copy of the collection now that has a resource URI (`/collections/my-collection-copy`) and can be
221223
correctly queried by collection name.
224+
225+
### Reindexing
226+
This section covers how to reindex documents stored in Elasticsearch/OpenSearch.
227+
A reindex operation might be useful to apply changes to documents or to correct dynamically generated mappings.
228+
229+
The index templates will make sure that manually created indices will also have the correct mappings and settings.
230+
231+
In this example, we will make a copy of an existing Item index `items_my-collection-000001` but change the Item identifier to be lowercase.
232+
233+
```shell
234+
curl -X "POST" "http://localhost:9200/_reindex" \
235+
-H 'Content-Type: application/json' \
236+
-d $'{
237+
"source": {
238+
"index": "items_my-collection-000001"
239+
},
240+
"dest": {
241+
"index": "items_my-collection-000002"
242+
},
243+
"script": {
244+
"source": "ctx._source.id = ctx._source.id.toLowerCase()",
245+
"lang": "painless"
246+
}
247+
}'
248+
```
249+
250+
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-000002`.
251+
```shell
252+
curl -X "POST" "http://localhost:9200/_aliases" \
253+
-h 'Content-Type: application/json' \
254+
-d $'{
255+
"actions": [
256+
{
257+
"remove": {
258+
"index": "*",
259+
"alias": "items_my-collection"
260+
}
261+
},
262+
{
263+
"add": {
264+
"index": "items_my-collection-000002",
265+
"alias": "items_my-collection"
266+
}
267+
}
268+
]
269+
}'
270+
```
271+
272+
The modified Items with lowercase identifiers will now be visible to users accessing `my-collection` in the STAC API.

stac_fastapi/core/stac_fastapi/core/core.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
from stac_fastapi.types.config import Settings
3838
from stac_fastapi.types.conformance import BASE_CONFORMANCE_CLASSES
3939
from stac_fastapi.types.extension import ApiExtension
40-
from stac_fastapi.types.links import CollectionLinks
4140
from stac_fastapi.types.requests import get_base_url
4241
from stac_fastapi.types.search import BaseSearchPostRequest
4342
from stac_fastapi.types.stac import Collection, Collections, Item, ItemCollection
@@ -731,10 +730,9 @@ async def create_collection(
731730
ConflictError: If the collection already exists.
732731
"""
733732
base_url = str(kwargs["request"].base_url)
734-
collection_links = CollectionLinks(
735-
collection_id=collection["id"], base_url=base_url
736-
).create_links()
737-
collection["links"] = collection_links
733+
collection = self.database.collection_serializer.stac_to_db(
734+
collection, base_url
735+
)
738736
await self.database.create_collection(collection=collection)
739737

740738
return CollectionSerializer.db_to_stac(collection, base_url)
@@ -767,11 +765,9 @@ async def update_collection(
767765
"collection_id", collection["id"]
768766
)
769767

770-
collection_links = CollectionLinks(
771-
collection_id=collection["id"], base_url=base_url
772-
).create_links()
773-
collection["links"] = collection_links
774-
768+
collection = self.database.collection_serializer.stac_to_db(
769+
collection, base_url
770+
)
775771
await self.database.update_collection(
776772
collection_id=collection_id, collection=collection
777773
)

stac_fastapi/core/stac_fastapi/core/serializers.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,7 @@ def stac_to_db(cls, stac_data: stac_types.Item, base_url: str) -> stac_types.Ite
6060
Returns:
6161
stac_types.Item: The database-ready STAC item object.
6262
"""
63-
item_links = ItemLinks(
64-
collection_id=stac_data["collection"],
65-
item_id=stac_data["id"],
66-
base_url=base_url,
67-
).create_links()
63+
item_links = resolve_links(stac_data.get("links", []), base_url)
6864
stac_data["links"] = item_links
6965

7066
now = now_to_rfc3339_str()
@@ -111,6 +107,24 @@ def db_to_stac(cls, item: dict, base_url: str) -> stac_types.Item:
111107
class CollectionSerializer(Serializer):
112108
"""Serialization methods for STAC collections."""
113109

110+
@classmethod
111+
def stac_to_db(
112+
cls, collection: stac_types.Collection, base_url: str
113+
) -> stac_types.Collection:
114+
"""
115+
Transform STAC Collection to database-ready STAC collection.
116+
117+
Args:
118+
stac_data: the STAC Collection object to be transformed
119+
base_url: the base URL for the STAC API
120+
121+
Returns:
122+
stac_types.Collection: The database-ready STAC Collection object.
123+
"""
124+
collection = deepcopy(collection)
125+
collection["links"] = resolve_links(collection.get("links", []), base_url)
126+
return collection
127+
114128
@classmethod
115129
def db_to_stac(cls, collection: dict, base_url: str) -> stac_types.Collection:
116130
"""Transform database model to STAC collection.

stac_fastapi/elasticsearch/stac_fastapi/elasticsearch/app.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from stac_fastapi.elasticsearch.database_logic import (
1717
DatabaseLogic,
1818
create_collection_index,
19+
create_index_templates,
1920
)
2021
from stac_fastapi.extensions.core import (
2122
ContextExtension,
@@ -78,6 +79,7 @@
7879

7980
@app.on_event("startup")
8081
async def _startup_event() -> None:
82+
await create_index_templates()
8183
await create_collection_index()
8284

8385

stac_fastapi/elasticsearch/stac_fastapi/elasticsearch/database_logic.py

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,36 @@ def indices(collection_ids: Optional[List[str]]) -> str:
171171
return ",".join([index_by_collection_id(c) for c in collection_ids])
172172

173173

174+
async def create_index_templates() -> None:
175+
"""
176+
Create index templates for the Collection and Item indices.
177+
178+
Returns:
179+
None
180+
181+
"""
182+
client = AsyncElasticsearchSettings().create_client
183+
await client.indices.put_template(
184+
name=f"template_{COLLECTIONS_INDEX}",
185+
body={
186+
"index_patterns": [f"{COLLECTIONS_INDEX}*"],
187+
"mappings": ES_COLLECTIONS_MAPPINGS,
188+
},
189+
)
190+
await client.indices.put_template(
191+
name=f"template_{ITEMS_INDEX_PREFIX}",
192+
body={
193+
"index_patterns": [f"{ITEMS_INDEX_PREFIX}*"],
194+
"settings": ES_ITEMS_SETTINGS,
195+
"mappings": ES_ITEMS_MAPPINGS,
196+
},
197+
)
198+
await client.close()
199+
200+
174201
async def create_collection_index() -> None:
175202
"""
176-
Create the index for a Collection.
203+
Create the index for a Collection. The settings of the index template will be used implicitly.
177204
178205
Returns:
179206
None
@@ -184,14 +211,13 @@ async def create_collection_index() -> None:
184211
await client.options(ignore_status=400).indices.create(
185212
index=f"{COLLECTIONS_INDEX}-000001",
186213
aliases={COLLECTIONS_INDEX: {}},
187-
mappings=ES_COLLECTIONS_MAPPINGS,
188214
)
189215
await client.close()
190216

191217

192218
async def create_item_index(collection_id: str):
193219
"""
194-
Create the index for Items.
220+
Create the index for Items. The settings of the index template will be used implicitly.
195221
196222
Args:
197223
collection_id (str): Collection identifier.
@@ -206,8 +232,6 @@ async def create_item_index(collection_id: str):
206232
await client.options(ignore_status=400).indices.create(
207233
index=f"{index_by_collection_id(collection_id)}-000001",
208234
aliases={index_name: {}},
209-
mappings=ES_ITEMS_MAPPINGS,
210-
settings=ES_ITEMS_SETTINGS,
211235
)
212236
await client.close()
213237

stac_fastapi/opensearch/stac_fastapi/opensearch/app.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from stac_fastapi.opensearch.database_logic import (
2626
DatabaseLogic,
2727
create_collection_index,
28+
create_index_templates,
2829
)
2930

3031
settings = OpensearchSettings()
@@ -78,6 +79,7 @@
7879

7980
@app.on_event("startup")
8081
async def _startup_event() -> None:
82+
await create_index_templates()
8183
await create_collection_index()
8284

8385

stac_fastapi/opensearch/stac_fastapi/opensearch/database_logic.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,18 +173,44 @@ def indices(collection_ids: Optional[List[str]]) -> str:
173173
return ",".join([index_by_collection_id(c) for c in collection_ids])
174174

175175

176+
async def create_index_templates() -> None:
177+
"""
178+
Create index templates for the Collection and Item indices.
179+
180+
Returns:
181+
None
182+
183+
"""
184+
client = AsyncSearchSettings().create_client
185+
await client.indices.put_template(
186+
name=f"template_{COLLECTIONS_INDEX}",
187+
body={
188+
"index_patterns": [f"{COLLECTIONS_INDEX}*"],
189+
"mappings": ES_COLLECTIONS_MAPPINGS,
190+
},
191+
)
192+
await client.indices.put_template(
193+
name=f"template_{ITEMS_INDEX_PREFIX}",
194+
body={
195+
"index_patterns": [f"{ITEMS_INDEX_PREFIX}*"],
196+
"settings": ES_ITEMS_SETTINGS,
197+
"mappings": ES_ITEMS_MAPPINGS,
198+
},
199+
)
200+
await client.close()
201+
202+
176203
async def create_collection_index() -> None:
177204
"""
178-
Create the index for a Collection.
205+
Create the index for a Collection. The settings of the index template will be used implicitly.
179206
180207
Returns:
181208
None
182209
183210
"""
184211
client = AsyncSearchSettings().create_client
185212

186-
search_body = {
187-
"mappings": ES_COLLECTIONS_MAPPINGS,
213+
search_body: Dict[str, Any] = {
188214
"aliases": {COLLECTIONS_INDEX: {}},
189215
}
190216

@@ -203,7 +229,7 @@ async def create_collection_index() -> None:
203229

204230
async def create_item_index(collection_id: str):
205231
"""
206-
Create the index for Items.
232+
Create the index for Items. The settings of the index template will be used implicitly.
207233
208234
Args:
209235
collection_id (str): Collection identifier.
@@ -214,10 +240,8 @@ async def create_item_index(collection_id: str):
214240
"""
215241
client = AsyncSearchSettings().create_client
216242
index_name = index_by_collection_id(collection_id)
217-
search_body = {
243+
search_body: Dict[str, Any] = {
218244
"aliases": {index_name: {}},
219-
"mappings": ES_ITEMS_MAPPINGS,
220-
"settings": ES_ITEMS_SETTINGS,
221245
}
222246

223247
try:
@@ -335,7 +359,7 @@ async def get_all_collections(
335359
search_body["search_after"] = search_after
336360

337361
response = await self.client.search(
338-
index="collections",
362+
index=COLLECTIONS_INDEX,
339363
body=search_body,
340364
)
341365

stac_fastapi/tests/conftest.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from stac_fastapi.opensearch.database_logic import (
2424
DatabaseLogic,
2525
create_collection_index,
26+
create_index_templates,
2627
)
2728
else:
2829
from stac_fastapi.elasticsearch.config import (
@@ -32,6 +33,7 @@
3233
from stac_fastapi.elasticsearch.database_logic import (
3334
DatabaseLogic,
3435
create_collection_index,
36+
create_index_templates,
3537
)
3638

3739
from stac_fastapi.extensions.core import ( # FieldsExtension,
@@ -215,6 +217,7 @@ async def app():
215217

216218
@pytest_asyncio.fixture(scope="session")
217219
async def app_client(app):
220+
await create_index_templates()
218221
await create_collection_index()
219222

220223
async with AsyncClient(app=app, base_url="http://test-server") as c:

stac_fastapi/tests/database/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)