Releases: mbari-org/annosaurus
annosaurus 0.12.3
Code cleanup and Raziel integration
Full Changelog: 0.12.2...0.12.3
annosaurus 0.12.2
This release upgrades Java from 11 to 17 (the latest long-term release)
There is a also a new endpoint for checking health of the server:
/health
Demo setup
docker run -p 8080:8080 -e BASICJWT_CLIENT_SECRET=foo -e BASICJWT_SIGNING_SECRET=bar mbari/annosaurus
Request
GET http://localhost:8080/v1/health
Response
HTTP/1.1 200 OK
Date: Tue, 30 Nov 2021 21:55:07 GMT
Content-Type: text/plain;charset=utf-8
Transfer-Encoding: chunked
Connection: close
Content-Encoding: gzip
{
"jdkVersion": "17.0.1+12-39",
"availableProcessors": 2,
"freeMemory": 40227408,
"maxMemory": 4294967296,
"totalMemory": 94371840,
"application": "annosaurus"
}
Full Changelog: 0.12.1...0.12.2
annosaurus 0.12.1
This release adds additional parameters to a query to constrain using missionContacts
, missionId
, and platformName
. Some examples:
Search by platformName (e.g. ROV name) and a missionContact (e.g. A Chief Scientist)
In this query, we're searching for all annotations on dives by the ROV Doc Ricketts when Bruce Robison was the Chief Scientist. Because there's 1,019,079 annotations that match that query, we'll limit the number of returned annotations to 2 for this example.
Request
POST http://dsg.mbari.org/anno/v1/fast/
Content-Type: application/json
{
"platformName": "Doc Ricketts",
"missionContacts": ["Bruce Robison"],
"limit": 2
}
Response
HTTP/1.1 200 OK
Server: nginx/1.20.1
Date: Tue, 09 Nov 2021 20:07:17 GMT
Content-Type: application/json;charset=utf-8
Transfer-Encoding: chunked
Connection: close
Access-Control-Allow-Origin: *
Content-Encoding: gzip
{
"query_constraints": {
"video_reference_uuids": [],
"concepts": [],
"observers": [],
"groups": [],
"activities": [],
"limit": 2,
"offset": 0,
"data": false,
"mission_contacts": [
"Bruce Robison"
],
"platform_name": "Doc Ricketts"
},
"content": [
{
"observation_uuid": "b8bec2c2-f755-4140-ff65-00000e76b81e",
"concept": "Aegina",
"observer": "mbassett",
"observation_timestamp": "2021-03-17T20:39:30.920Z",
"video_reference_uuid": "8e963a90-a7f0-49fc-8af6-1b0a23b2dd3a",
"imaged_moment_uuid": "3fb36025-abe4-408a-a06c-18000e76b81e",
"timecode": "09:56:04:27",
"recorded_timestamp": "2013-11-12T00:42:59Z",
"group": "ROV",
"associations": [],
"image_references": []
},
{
"observation_uuid": "72c8cbba-4664-4296-a51f-0000285cb073",
"concept": "Aegina",
"observer": "svonthun",
"observation_timestamp": "2014-02-10T20:09:00Z",
"video_reference_uuid": "12948865-0f9e-4edc-8c88-db34746ea74e",
"imaged_moment_uuid": "c6c36eb2-e833-4f9d-b4d4-60bd2c2ab5be",
"timecode": "02:26:04:23",
"recorded_timestamp": "2012-10-27T23:14:00Z",
"group": "ROV",
"associations": [],
"image_references": []
}
]
}
Search by missionId
A missionId is a unique id for the mission or deployment. (In VampireSquid, this is a deploymentId). In this query, we're searching for Ventana's 1234 dive.
Request
POST http://dsg.mbari.org/anno/v1/fast/
Content-Type: application/json
{
"missionId": "Ventana 1234",
"limit": "2"
}
Response
HTTP/1.1 200 OK
Server: nginx/1.20.1
Date: Tue, 09 Nov 2021 20:14:12 GMT
Content-Type: application/json;charset=utf-8
Transfer-Encoding: chunked
Connection: close
Access-Control-Allow-Origin: *
Content-Encoding: gzip
{
"query_constraints": {
"video_reference_uuids": [],
"concepts": [],
"observers": [],
"groups": [],
"activities": [],
"limit": 2,
"offset": 0,
"data": false,
"mission_contacts": [],
"mission_id": "Ventana 1234"
},
"content": [
{
"observation_uuid": "fcbc98db-4ac0-4dd0-9ad8-014e5cc8811f",
"concept": "Solmissus",
"observer": "unknown",
"observation_timestamp": "1970-01-01T00:00:00Z",
"video_reference_uuid": "aefee7f8-53e1-4106-bcd0-e33f800e0bcb",
"imaged_moment_uuid": "42ebf9cb-7d51-4262-9099-a926eea47a75",
"timecode": "02:39:23:14",
"recorded_timestamp": "1997-04-11T19:21:40Z",
"group": "ROV",
"associations": [
{
"link_name": "suspect-navigation-ctd-other-data",
"link_value": "No CTD data",
"to_concept": "self",
"mime_type": "text/plain",
"uuid": "389672bc-b023-4ca0-9c52-3d4211d9280d"
}
],
"image_references": []
},
{
"observation_uuid": "06515cd5-21d4-445b-8958-02a165dc018f",
"concept": "Nanomia bijuga",
"observer": "unknown",
"observation_timestamp": "1970-01-01T00:00:00Z",
"video_reference_uuid": "aefee7f8-53e1-4106-bcd0-e33f800e0bcb",
"imaged_moment_uuid": "545a814f-141b-4b1e-9a9e-18f386ec2389",
"timecode": "02:39:16:12",
"recorded_timestamp": "1997-04-11T19:21:31Z",
"group": "ROV",
"associations": [
{
"link_name": "suspect-navigation-ctd-other-data",
"link_value": "No CTD data",
"to_concept": "self",
"mime_type": "text/plain",
"uuid": "3932da8c-2358-4754-8a30-3301c0cc6346"
}
],
"image_references": []
}
]
}
annosaurus 0.11.1
This is a minor bug fix release. It addresses an issue where an observation without an observation_timestamp would cause calls to "fast" endpoints to fail.
annosaurus 0.11.0
MBARI is revamping our Deep-sea Guide. In order to support it, we're adding some basic analysis endpoints to annosaurus. This release allows add hoc queries to generate data histograms. Here's an example to get a frequency histogram for annotations with the matching concepts and observer. (Note that ?size=50
sets the vertical depth bin size to 50 meters)
Request
POST http://dsg.mbari.org/anno/v1/analysis/histogram/depth?size=50
Content-Type: application/json
{
concepts: ["Nanomia", "Nanomia bijuga"],
observers: ["schlin"]
}
Response
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Wed, 14 Apr 2021 23:21:31 GMT
Content-Type: application/json;charset=utf-8
Transfer-Encoding: chunked
Connection: close
Access-Control-Allow-Origin: *
Content-Encoding: gzip
{
"query_constraints": {
"video_reference_uuids": [],
"concepts": [
"Nanomia",
"Nanomia bijuga"
],
"observers": [
"schlin"
],
"groups": [],
"activities": [],
"limit": 5000,
"offset": 0,
"data": false
},
"content": {
"bins_min": [
0,
50,
100,
150,
200,
250,
300,
350,
400,
450,
500,
550,
600,
650,
700,
750,
800,
850,
900,
950,
1000,
1050,
1100,
1150,
1200,
1250,
1300,
1350,
1400,
1450,
1500,
1550,
1600,
1650,
1700,
1750,
1800,
1850,
1900,
1950,
2000,
2050,
2100,
2150,
2200,
2250,
2300,
2350,
2400,
2450,
2500,
2550,
2600,
2650,
2700,
2750,
2800,
2850,
2900,
2950,
3000,
3050,
3100,
3150,
3200,
3250,
3300,
3350,
3400,
3450,
3500,
3550,
3600,
3650,
3700,
3750,
3800,
3850,
3900,
3950
],
"bins_max": [
50,
100,
150,
200,
250,
300,
350,
400,
450,
500,
550,
600,
650,
700,
750,
800,
850,
900,
950,
1000,
1050,
1100,
1150,
1200,
1250,
1300,
1350,
1400,
1450,
1500,
1550,
1600,
1650,
1700,
1750,
1800,
1850,
1900,
1950,
2000,
2050,
2100,
2150,
2200,
2250,
2300,
2350,
2400,
2450,
2500,
2550,
2600,
2650,
2700,
2750,
2800,
2850,
2900,
2950,
3000,
3050,
3100,
3150,
3200,
3250,
3300,
3350,
3400,
3450,
3500,
3550,
3600,
3650,
3700,
3750,
3800,
3850,
3900,
3950,
4000
],
"values": [
3313,
3755,
3953,
5136,
7181,
7772,
8253,
6784,
6304,
5741,
2626,
1341,
816,
278,
66,
9,
6,
28,
4,
16,
25,
2,
4,
1,
68,
0,
0,
2,
0,
0,
0,
4,
1,
2,
1,
0,
0,
0,
1,
5,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
]
}
}
annosaurus 0.10.0
This release adds a query to look up the geographic range of observations. It returns the max latitude, longitude and depth extents for annotations that match the query constraints provided. For example:
Request
POST http://dsg.mbari.org/anno/v1/fast/georange
Content-Type: application/json
{
concepts: ["Pandalus", "Pandalus platyceros"]
}
Response
HTTP/1.1 200 OK
Server: nginx/1.16.1
Date: Fri, 09 Apr 2021 17:32:18 GMT
Content-Type: application/json;charset=utf-8
Transfer-Encoding: chunked
Connection: close
Access-Control-Allow-Origin: *
Content-Encoding: gzip
{
"query_constraints": {
"video_reference_uuids": [],
"concepts": [
"Pandalus",
"Pandalus platyceros"
],
"observers": [],
"groups": [],
"activities": [],
"limit": 5000,
"offset": 0,
"data": false
},
"content": {
"min_latitude": 0.0,
"max_latitude": 40.4352,
"min_longitude": -126.414553,
"max_longitude": 0.0,
"min_depth_meters": 59.1,
"max_depth_meters": 2648.38
}
}
annosaurus 0.9.2
I've added a new endpoint (as requested by CSIRO) for retrieving imagedMoments
that have at least one image (i.e. ImageReference
) and that have an Association
that matches the user-provided toConcept
. The endpoint is:
http://my.annosaurus.org/anno/v1/fast/imagedmoments/toconcept/images/{to_concept}
It returns a list of ImagedMoment UUIDS:
[
"9c1cef8a-aed6-469d-accb-04c3aa82e3b1",
"70f807b7-1cdd-4023-8c32-0ee3d80a4f32",
"43e02cd8-41dd-4b97-a437-0f34a9cb3daf",
"c8d54faa-91be-410a-9d2a-1c6ea2b8fa90",
"ee26d184-4759-4fe4-a47f-3a621878fdc5"
]
This release also includes a bug fix for a rare NullPointerException
that could occur if an association was missing a linkValue.
annosaurus 0.8.0
Added new endpoints for flexible queries:
- POST
/anno/v1/fast/
- Retrieve annotations - POST
/anno/v1/fast/count
- Retrieve a count of the annotations that match the query
Both of these accept a json body that defines various constraints. Any of these constraints can be omitted. Full examples are:
camelCase
{
"videoReferenceUuids": [
"43c8e033-eb22-4905-b39b-0a3e66a0075b"
],
"concepts": [
"Aegina",
"Aegina citrea"
],
"groups": [
"ROV"
],
"activities": [
"descent",
"transect"
],
"observers": [
"kwalz"
],
"minDepth": 200,
"maxDepth": 300,
"minLatitude": 35.0,
"maxLatitude": 37.0,
"minLongitude": -122.7,
"maxLongitude": -122.0,
"minTimestamp": "1998-01-01T00:00:00Z",
"maxTimestamp": "2021-01-07T00:53:32.757470Z",
"linkName": "eating",
"linkValue": "nil",
"limit": 5000,
"offset": 0,
"data": true
}
snake_case
{
"video_reference_uuids": [
"43c8e033-eb22-4905-b39b-0a3e66a0075b"
],
"concepts": [
"Aegina",
"Aegina citrea"
],
"groups": [
"ROV"
],
"activities": [
"descent",
"transect"
],
"observers": [
"kwalz"
],
"min_depth": 200,
"max_depth": 300,
"min_latitude": 35.0,
"max_latitude": 37.0,
"min_longitude": -122.7,
"max_longitude": -122.0,
"min_timestamp": "1998-01-01T00:00:00Z",
"max_timestamp": "2021-01-07T00:53:32.757470Z",
"link_name": "eating",
"link_value": "nil",
"limit": 5000,
"offset": 0,
"data": true
}
The response will be JSON in the form like:
{
"query_constraints": {
"video_reference_uuids": [
"43c8e033-eb22-4905-b39b-0a3e66a0075b"
],
"concepts": [
"Aegina",
"Aegina citrea"
],
"observers": [
"kwalz"
],
"groups": [
"ROV"
],
"activities": [
"descent",
"transect"
],
"min_depth": 200.0,
"max_depth": 300.0,
"min_timestamp": "1998-01-01T00:00:00Z",
"max_timestamp": "2021-01-07T00:53:32.757470Z",
"link_name": "eating",
"link_value": "nil",
"limit": 5000,
"offset": 0,
"data": true
},
"content": [
{
"ancillary_data": {
"oxygen_ml_l": 1.125,
"depth_meters": 299.3599853515625,
"latitude": 36.701864,
"temperature_celsius": 8.234999656677246,
"theta": 3.799999952316284,
"longitude": -122.050932,
"phi": -3.299999952316284,
"psi": 235.0,
"pressure_dbar": 303.1000061035156,
"salinity": 34.1609992980957,
"altitude": 78.11000061035156,
"light_transmission": 79.2699966430664,
"uuid": "c34c0113-3aaa-4648-a704-3472f3f0f42d"
},
"observation_uuid": "5281db41-5914-4929-a298-48de0d26782d",
"concept": "Physonectae",
"observer": "kwalz",
"observation_timestamp": "2013-11-25T19:52:38.957Z",
"video_reference_uuid": "43c8e033-eb22-4905-b39b-0a3e66a0075b",
"imaged_moment_uuid": "ab905fde-a8a1-4f23-b4bd-d28bf92a062e",
"timecode": "00:45:56:04",
"recorded_timestamp": "2013-11-08T15:11:58Z",
"group": "ROV",
"activity": "transect",
"associations": [
{
"link_name": "eating",
"link_value": "nil",
"to_concept": "Aegina",
"mime_type": "text/plain",
"uuid": "07a76fdb-11ff-437b-b2e4-4f7e312e806a"
},
{
"link_name": "comment",
"link_value": "wuzzle?",
"to_concept": "self",
"mime_type": "text/plain",
"uuid": "99fb539a-4578-46d2-aa8c-8a43e40e168f"
}
],
"image_references": []
}
]
}
Here's a an example using curl:
curl --header "Content-type: application/json" \
--request POST \
--data '{"concepts": ["Aegina", "Aegina citrea"], "link_name": "eating", "limit": 5000, "offset": 0, "data": true}' \
http://m3.shore.mbari.org/anno/v1/fast/
Notes
SQL expansion
Under the hood, concepts: ["Aegina", "Aegina citrea"]
is expanded to the SQL (observation.concept IN ('Aegina', 'Aegina citrea') OR association.to_concept IN ('Aegina', 'Aegina citrea')
{concept: ["Aegina"], link_name: "eating"}
is expanded to the SQL:
(
observation.concept IN ('Aegina') OR
association.to_concept IN ('Aegina')
)
AND association.link_name = "eating"
Min params like minDepth
are inclusive and so become AND ancillary_data.depth_meters >= minDepth
in SQL. Max params are exclusive, i.e. maxDepth becomes AND ancillary_data.depth_meters < maxDepth
annosaurus 0.7.0
The following changes were added:
- Upgrade to scala 2.13 and Scalatra 2.7.0.
- Added colorized logging
- Added
anno/v1/observations/delete/duration/{:uuid}
endpoint.
annosaurus 0.6.3
Added support for message publishing when an Association is created or updated. ZeroMq subscribers will see a message like:
{
"observation_uuid": "e7bcf8d6-880e-4ead-3763-7b3185e7a51e",
"link_name": "eating",
"to_concept": "Pandalus platyceros",
"link_value": "nil",
"mime_type": "text/plain",
"object_type": "Association"
}