Skip to content

Commit 2c8ae68

Browse files
authored
Merge branch 'main' into extend_datetime_search
2 parents 14b5097 + 47ef97a commit 2c8ae68

File tree

10 files changed

+67
-37
lines changed

10 files changed

+67
-37
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
99

1010
### Changed
1111

12+
## [v3.2.3] - 2025-02-11
13+
1214
- Added note on the use of the default `*` use in route authentication dependecies. [#325](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/325)
15+
- Update item index naming and aliasing to allow capitalisation of collection ids [#329](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/329)
1316
- Bugfixes for the `IsNull` operator and datetime filtering [#330](https://github.com/stac-utils/stac-fastapi-elasticsearch-opensearch/pull/330)
1417

1518
## [v3.2.2] - 2024-12-15
@@ -289,7 +292,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
289292
- Use genexp in execute_search and get_all_collections to return results.
290293
- Added db_to_stac serializer to item_collection method in core.py.
291294

292-
[Unreleased]: https://github.com/stac-utils/stac-fastapi-elasticsearch/tree/v3.2.2...main
295+
[Unreleased]: https://github.com/stac-utils/stac-fastapi-elasticsearch/tree/v3.2.3...main
296+
[v3.2.3]: https://github.com/stac-utils/stac-fastapi-elasticsearch/tree/v3.2.2...v3.2.3
293297
[v3.2.2]: https://github.com/stac-utils/stac-fastapi-elasticsearch/tree/v3.2.1...v3.2.2
294298
[v3.2.1]: https://github.com/stac-utils/stac-fastapi-elasticsearch/tree/v3.2.0...v3.2.1
295299
[v3.2.0]: https://github.com/stac-utils/stac-fastapi-elasticsearch/tree/v3.1.0...v3.2.0

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,17 +267,17 @@ A reindex operation might be useful to apply changes to documents or to correct
267267

268268
The index templates will make sure that manually created indices will also have the correct mappings and settings.
269269

270-
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.
270+
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.
271271

272272
```shell
273273
curl -X "POST" "http://localhost:9200/_reindex" \
274274
-H 'Content-Type: application/json' \
275275
-d $'{
276276
"source": {
277-
"index": "items_my-collection-000001"
277+
"index": "items_my-collection-lower_my-collection-hex-000001"
278278
},
279279
"dest": {
280-
"index": "items_my-collection-000002"
280+
"index": "items_my-collection-lower_my-collection-hex-000002"
281281
},
282282
"script": {
283283
"source": "ctx._source.id = ctx._source.id.toLowerCase()",
@@ -286,7 +286,7 @@ curl -X "POST" "http://localhost:9200/_reindex" \
286286
}'
287287
```
288288

289-
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`.
289+
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`.
290290
```shell
291291
curl -X "POST" "http://localhost:9200/_aliases" \
292292
-h 'Content-Type: application/json' \
@@ -300,7 +300,7 @@ curl -X "POST" "http://localhost:9200/_aliases" \
300300
},
301301
{
302302
"add": {
303-
"index": "items_my-collection-000002",
303+
"index": "items_my-collection-lower_my-collection-hex-000002",
304304
"alias": "items_my-collection"
305305
}
306306
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
"""library version."""
2-
__version__ = "3.2.2"
2+
__version__ = "3.2.3"

stac_fastapi/elasticsearch/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
desc = f.read()
77

88
install_requires = [
9-
"stac-fastapi.core==3.2.2",
9+
"stac-fastapi.core==3.2.3",
1010
"elasticsearch[async]==8.11.0",
1111
"elasticsearch-dsl==8.11.0",
1212
"uvicorn",

stac_fastapi/elasticsearch/stac_fastapi/elasticsearch/database_logic.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,20 @@ def index_by_collection_id(collection_id: str) -> str:
156156
Returns:
157157
str: The index name derived from the collection id.
158158
"""
159-
return f"{ITEMS_INDEX_PREFIX}{''.join(c for c in collection_id.lower() if c not in ES_INDEX_NAME_UNSUPPORTED_CHARS)}"
159+
return f"{ITEMS_INDEX_PREFIX}{''.join(c for c in collection_id.lower() if c not in ES_INDEX_NAME_UNSUPPORTED_CHARS)}_{collection_id.encode('utf-8').hex()}"
160+
161+
162+
def index_alias_by_collection_id(collection_id: str) -> str:
163+
"""
164+
Translate a collection id into an Elasticsearch index alias.
165+
166+
Args:
167+
collection_id (str): The collection id to translate into an index alias.
168+
169+
Returns:
170+
str: The index alias derived from the collection id.
171+
"""
172+
return f"{ITEMS_INDEX_PREFIX}{''.join(c for c in collection_id if c not in ES_INDEX_NAME_UNSUPPORTED_CHARS)}"
160173

161174

162175
def indices(collection_ids: Optional[List[str]]) -> str:
@@ -172,7 +185,7 @@ def indices(collection_ids: Optional[List[str]]) -> str:
172185
if collection_ids is None or collection_ids == []:
173186
return ITEM_INDICES
174187
else:
175-
return ",".join([index_by_collection_id(c) for c in collection_ids])
188+
return ",".join([index_alias_by_collection_id(c) for c in collection_ids])
176189

177190

178191
async def create_index_templates() -> None:
@@ -231,11 +244,10 @@ async def create_item_index(collection_id: str):
231244
232245
"""
233246
client = AsyncElasticsearchSettings().create_client
234-
index_name = index_by_collection_id(collection_id)
235247

236248
await client.options(ignore_status=400).indices.create(
237249
index=f"{index_by_collection_id(collection_id)}-000001",
238-
aliases={index_name: {}},
250+
aliases={index_alias_by_collection_id(collection_id): {}},
239251
)
240252
await client.close()
241253

@@ -248,7 +260,7 @@ async def delete_item_index(collection_id: str):
248260
"""
249261
client = AsyncElasticsearchSettings().create_client
250262

251-
name = index_by_collection_id(collection_id)
263+
name = index_alias_by_collection_id(collection_id)
252264
resolved = await client.indices.resolve_index(name=name)
253265
if "aliases" in resolved and resolved["aliases"]:
254266
[alias] = resolved["aliases"]
@@ -288,7 +300,7 @@ def mk_actions(collection_id: str, processed_items: List[Item]):
288300
"""
289301
return [
290302
{
291-
"_index": index_by_collection_id(collection_id),
303+
"_index": index_alias_by_collection_id(collection_id),
292304
"_id": mk_item_id(item["id"], item["collection"]),
293305
"_source": item,
294306
}
@@ -449,7 +461,7 @@ async def get_one_item(self, collection_id: str, item_id: str) -> Dict:
449461
"""
450462
try:
451463
item = await self.client.get(
452-
index=index_by_collection_id(collection_id),
464+
index=index_alias_by_collection_id(collection_id),
453465
id=mk_item_id(item_id, collection_id),
454466
)
455467
except exceptions.NotFoundError:
@@ -900,7 +912,7 @@ async def prep_create_item(
900912
await self.check_collection_exists(collection_id=item["collection"])
901913

902914
if not exist_ok and await self.client.exists(
903-
index=index_by_collection_id(item["collection"]),
915+
index=index_alias_by_collection_id(item["collection"]),
904916
id=mk_item_id(item["id"], item["collection"]),
905917
):
906918
raise ConflictError(
@@ -937,7 +949,7 @@ def sync_prep_create_item(
937949
raise NotFoundError(f"Collection {collection_id} does not exist")
938950

939951
if not exist_ok and self.sync_client.exists(
940-
index=index_by_collection_id(collection_id),
952+
index=index_alias_by_collection_id(collection_id),
941953
id=mk_item_id(item_id, collection_id),
942954
):
943955
raise ConflictError(
@@ -963,7 +975,7 @@ async def create_item(self, item: Item, refresh: bool = False):
963975
item_id = item["id"]
964976
collection_id = item["collection"]
965977
es_resp = await self.client.index(
966-
index=index_by_collection_id(collection_id),
978+
index=index_alias_by_collection_id(collection_id),
967979
id=mk_item_id(item_id, collection_id),
968980
document=item,
969981
refresh=refresh,
@@ -989,7 +1001,7 @@ async def delete_item(
9891001
"""
9901002
try:
9911003
await self.client.delete(
992-
index=index_by_collection_id(collection_id),
1004+
index=index_alias_by_collection_id(collection_id),
9931005
id=mk_item_id(item_id, collection_id),
9941006
refresh=refresh,
9951007
)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
"""library version."""
2-
__version__ = "3.2.2"
2+
__version__ = "3.2.3"

stac_fastapi/opensearch/setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
desc = f.read()
77

88
install_requires = [
9-
"stac-fastapi.core==3.2.2",
9+
"stac-fastapi.core==3.2.3",
1010
"opensearch-py==2.4.2",
1111
"opensearch-py[async]==2.4.2",
1212
"uvicorn",

stac_fastapi/opensearch/stac_fastapi/opensearch/database_logic.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,20 @@ def index_by_collection_id(collection_id: str) -> str:
158158
Returns:
159159
str: The index name derived from the collection id.
160160
"""
161-
return f"{ITEMS_INDEX_PREFIX}{''.join(c for c in collection_id.lower() if c not in ES_INDEX_NAME_UNSUPPORTED_CHARS)}"
161+
return f"{ITEMS_INDEX_PREFIX}{''.join(c for c in collection_id.lower() if c not in ES_INDEX_NAME_UNSUPPORTED_CHARS)}_{collection_id.encode('utf-8').hex()}"
162+
163+
164+
def index_alias_by_collection_id(collection_id: str) -> str:
165+
"""
166+
Translate a collection id into an Elasticsearch index alias.
167+
168+
Args:
169+
collection_id (str): The collection id to translate into an index alias.
170+
171+
Returns:
172+
str: The index alias derived from the collection id.
173+
"""
174+
return f"{ITEMS_INDEX_PREFIX}{''.join(c for c in collection_id if c not in ES_INDEX_NAME_UNSUPPORTED_CHARS)}"
162175

163176

164177
def indices(collection_ids: Optional[List[str]]) -> str:
@@ -174,7 +187,7 @@ def indices(collection_ids: Optional[List[str]]) -> str:
174187
if collection_ids is None or collection_ids == []:
175188
return ITEM_INDICES
176189
else:
177-
return ",".join([index_by_collection_id(c) for c in collection_ids])
190+
return ",".join([index_alias_by_collection_id(c) for c in collection_ids])
178191

179192

180193
async def create_index_templates() -> None:
@@ -243,13 +256,14 @@ async def create_item_index(collection_id: str):
243256
244257
"""
245258
client = AsyncSearchSettings().create_client
246-
index_name = index_by_collection_id(collection_id)
247259
search_body: Dict[str, Any] = {
248-
"aliases": {index_name: {}},
260+
"aliases": {index_alias_by_collection_id(collection_id): {}},
249261
}
250262

251263
try:
252-
await client.indices.create(index=f"{index_name}-000001", body=search_body)
264+
await client.indices.create(
265+
index=f"{index_by_collection_id(collection_id)}-000001", body=search_body
266+
)
253267
except TransportError as e:
254268
if e.status_code == 400:
255269
pass # Ignore 400 status codes
@@ -267,7 +281,7 @@ async def delete_item_index(collection_id: str):
267281
"""
268282
client = AsyncSearchSettings().create_client
269283

270-
name = index_by_collection_id(collection_id)
284+
name = index_alias_by_collection_id(collection_id)
271285
resolved = await client.indices.resolve_index(name=name)
272286
if "aliases" in resolved and resolved["aliases"]:
273287
[alias] = resolved["aliases"]
@@ -307,7 +321,7 @@ def mk_actions(collection_id: str, processed_items: List[Item]):
307321
"""
308322
return [
309323
{
310-
"_index": index_by_collection_id(collection_id),
324+
"_index": index_alias_by_collection_id(collection_id),
311325
"_id": mk_item_id(item["id"], item["collection"]),
312326
"_source": item,
313327
}
@@ -476,7 +490,7 @@ async def get_one_item(self, collection_id: str, item_id: str) -> Dict:
476490
"""
477491
try:
478492
item = await self.client.get(
479-
index=index_by_collection_id(collection_id),
493+
index=index_alias_by_collection_id(collection_id),
480494
id=mk_item_id(item_id, collection_id),
481495
)
482496
except exceptions.NotFoundError:
@@ -930,7 +944,7 @@ async def prep_create_item(
930944
await self.check_collection_exists(collection_id=item["collection"])
931945

932946
if not exist_ok and await self.client.exists(
933-
index=index_by_collection_id(item["collection"]),
947+
index=index_alias_by_collection_id(item["collection"]),
934948
id=mk_item_id(item["id"], item["collection"]),
935949
):
936950
raise ConflictError(
@@ -967,7 +981,7 @@ def sync_prep_create_item(
967981
raise NotFoundError(f"Collection {collection_id} does not exist")
968982

969983
if not exist_ok and self.sync_client.exists(
970-
index=index_by_collection_id(collection_id),
984+
index=index_alias_by_collection_id(collection_id),
971985
id=mk_item_id(item_id, collection_id),
972986
):
973987
raise ConflictError(
@@ -993,7 +1007,7 @@ async def create_item(self, item: Item, refresh: bool = False):
9931007
item_id = item["id"]
9941008
collection_id = item["collection"]
9951009
es_resp = await self.client.index(
996-
index=index_by_collection_id(collection_id),
1010+
index=index_alias_by_collection_id(collection_id),
9971011
id=mk_item_id(item_id, collection_id),
9981012
body=item,
9991013
refresh=refresh,
@@ -1019,7 +1033,7 @@ async def delete_item(
10191033
"""
10201034
try:
10211035
await self.client.delete(
1022-
index=index_by_collection_id(collection_id),
1036+
index=index_alias_by_collection_id(collection_id),
10231037
id=mk_item_id(item_id, collection_id),
10241038
refresh=refresh,
10251039
)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
"""library version."""
2-
__version__ = "3.2.2"
2+
__version__ = "3.2.3"

stac_fastapi/tests/database/test_database.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111
COLLECTIONS_INDEX,
1212
ES_COLLECTIONS_MAPPINGS,
1313
ES_ITEMS_MAPPINGS,
14-
index_by_collection_id,
14+
index_alias_by_collection_id,
1515
)
1616
else:
1717
from stac_fastapi.elasticsearch.database_logic import (
1818
COLLECTIONS_INDEX,
1919
ES_COLLECTIONS_MAPPINGS,
2020
ES_ITEMS_MAPPINGS,
21-
index_by_collection_id,
21+
index_alias_by_collection_id,
2222
)
2323

2424

@@ -42,7 +42,7 @@ async def test_index_mapping_items(txn_client, load_test_data):
4242
api.Collection(**collection), request=MockRequest
4343
)
4444
response = await database.client.indices.get_mapping(
45-
index=index_by_collection_id(collection["id"])
45+
index=index_alias_by_collection_id(collection["id"])
4646
)
4747
if not isinstance(response, dict):
4848
response = response.body

0 commit comments

Comments
 (0)