Conversation
Quite often dataset are updated on a regular basis and new versions are released and past ones are flagged as superseded/deprecated/archived. Some users have a need of being able to get an overview of all versions of a datasets. So far, one way to get that overview was to group all versions in a collection but that adds extra work to encode and organize the collection properly eg. https://sdi.eea.europa.eu/catalogue/srv/eng/catalog.search#/metadata/3ccf2fe3-40e3-4968-a54c-5a59510fa5a3 The catalogue is also able to navigate to the next revision of record when a `revisionOf` association is created between 2 records. The main goal is to be able to list for a dataset all versions and more easily navigate to next/previous versions using the API. The API provide an endpoint for retrieving verions: * GET `/records/{metadataUuid}/associated?type=versions` returns all past and more recent versions * GET `/records/{metadataUuid}/associated?type=next` * GET `/records/{metadataUuid}/associated?type=previous` Those associations can also be retrieved when searching using `relatedType` parameter. In ISO19115-3, associated resource can link to revision using the association type `revisionOf` link. Encoding is made using: ```xml <mri:associatedResource> <mri:MD_AssociatedResource> <mri:associationType> <mri:DS_AssociationTypeCode codeList="http://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#DS_AssociationTypeCode" codeListValue="revisionOf"/> </mri:associationType> <mri:metadataReference uuidref="65d546c6-3577-4938-8322-5d95188779a1"/> </mri:MD_AssociatedResource> </mri:associatedResource> ``` In the index, this information is stored in `agg_associated_revisionOf`. if v3 revisionOf v2 revisionOf v1 and v2 is not public, versions will not list v2 if anonymous but the relationship will be resolved. It is recommended to have all versions in the same publication status. The catalogue allows to link to remote records using a URL. Those are ignored in the version resolution (because it would require to have parsable record where revision can be extracted which is usually not the case). Most of remote records link are pointing to HTML document.
Add specific layout in related component to display the list of versions with: * link to each version * edition in any * publication date if any * status if any The version list is added to the lineage section.
f1be5ff to
5239c62
Compare
|
| "- `next`: immediate next item in version ordering.\n" + | ||
| "- `previous`: immediate previous item in version ordering.\n" + |
There was a problem hiding this comment.
The names are fairly generic and, in theory, could be used for any type of relationship that can be paginated. But, are far as are documented, I suppose they’re fine.
| for (AssociatedRecord record : entry.getValue()) { | ||
| Element relation = new Element(entry.getKey().name()); | ||
| relation.setAttribute("uuid", record.getUuid()); | ||
| relation.setAttribute("uuid", record.getUuid() == null ? "" : record.getUuid()); |
There was a problem hiding this comment.
Maybe the check for null to return an empty string can be added directly to AssociatedRecord.getUuid, so any place using it, doesn't get null value?
| } | ||
|
|
||
| Map<String, AssociatedRecord> recordsByUuid = new LinkedHashMap<>(); | ||
| for (AssociatedRecord record : records) { |
There was a problem hiding this comment.
Please check the Sonarcloud suggestion to rename record as it is a restricted identifier.
|
|
||
| List<AssociatedRecord> reordered = new ArrayList<>(); | ||
| for (String uuid : orderedRecords) { | ||
| AssociatedRecord record = recordsByUuid.remove(uuid); |
There was a problem hiding this comment.
Please check the Sonarcloud suggestion to rename record as it is a restricted identifier.
| String uuid = String.valueOf(value).trim(); | ||
| if (StringUtils.isNotEmpty(uuid)) { | ||
| values.add(uuid); | ||
| } |
There was a problem hiding this comment.
| String uuid = String.valueOf(value).trim(); | |
| if (StringUtils.isNotEmpty(uuid)) { | |
| values.add(uuid); | |
| } | |
| String textValue = String.valueOf(value).trim(); | |
| if (StringUtils.isNotEmpty(textValue)) { | |
| values.add(textValue); | |
| } |
This seems a generic method, uuid doesn't seem a good name.
| .andExpect(jsonPath("$.versions[1]._source.uuid").value(VERSION_MIDDLE)) | ||
| .andExpect(jsonPath("$.versions[2]._source.uuid").value(VERSION_OLDEST)); | ||
|
|
||
| mockMvc.perform(get("/srv/api/records/" + VERSION_OLDEST + "/associated?type=versions") |
There was a problem hiding this comment.
Should be checked also VERSION_MIDDLE?
| RelatedTypeDetails versionDetails, String currentUuid, boolean isNext) { | ||
| List<String> orderedRecords = versionDetails.getOrderedRecords(); | ||
|
|
||
| if (orderedRecords == null || orderedRecords.isEmpty()) { |
| result); | ||
| } | ||
|
|
||
| private static Set<String> extractFieldValues(Object fieldValue) { |
There was a problem hiding this comment.
If EsSearchManager.getDocument would return a class IndexRecord class wrapping Map<String, Object>, the methods extractFieldValues, addFieldValue could be added there, improving cohesion, but that will require quite some changes and probably out of the scope of the PR.
| * Remote records are not supported because they may not be XML document | ||
| * so we can't assume that we will be able to extract revisionOf records. | ||
| */ | ||
| private static RelatedTypeDetails getAllVersions(EsSearchManager searchMan, String metadataUuid) throws Exception { |
There was a problem hiding this comment.
I'm worried because I'm not sure whether circular relationships can be created that might lead to infinite loops.
Perhaps it can't happen, but I'm not sure.
| /** | ||
| * For versions, order is based on the version graph. | ||
| */ | ||
| private static List<AssociatedRecord> reorderIndexDocBasedOnOrderedRecords(List<AssociatedRecord> records, List<String> orderedRecords) { |
There was a problem hiding this comment.
I think it would be a good idea to move all these methods related to retrieving versions into a custom class called MetadataVersions or MetadataRelatedVersions or something similar. This would make the code cleaner.


Quite often datasets are updated on a regular basis and new versions are released and past ones are flagged as superseded/deprecated/archived. Some users have a need of being able to get an overview of all versions of a datasets.
So far, one way to get that overview was to group all versions in a collection but that adds extra work to encode and organize the collection properly eg. https://sdi.eea.europa.eu/catalogue/srv/eng/catalog.search#/metadata/3ccf2fe3-40e3-4968-a54c-5a59510fa5a3
The catalogue is also able to navigate to the next revision of record when a
revisionOfassociation is created between 2 records. eg. https://sdi.eea.europa.eu/catalogue/srv/eng/catalog.search#/metadata/607a6413-b3bf-456f-9ed2-6537006c4771The main goal is to be able to list for a dataset all versions and more easily navigate to next/previous versions using the API. first/next/previous/last are also concept used in DCAT3 so this can help on the mapping.
AI/LLM tools were used in this contribution.
API for navigating in versions
The API provide an endpoint for retrieving verions:
/records/{metadataUuid}/associated?type=versionsreturns all past and more recent versions/records/{metadataUuid}/associated?type=next/records/{metadataUuid}/associated?type=previousThose associations can also be retrieved when searching using
relatedTypeparameter.Encoding of revision
In ISO19115-3, associated resource can link to revision using the association type
revisionOflink. Encoding is made using:In the index, this information is stored in
agg_associated_revisionOf.So versions are only supported in ISO19115-3.
Versions navigation
The record view allows to navigate from version to version (as before)
and also display the full list in the lineage section:
Test data
See
related-versions-test.zipCorner cases
Dealing with record privileges
if v3 revisionOf v2 revisionOf v1 and v2 is not public, versions will not list v2 if anonymous but the relationship will be resolved. It is recommended to have all versions in the same publication status.
Remote records
The catalogue allows to link to remote records using a URL. Those are ignored in the version resolution (because it would require to have parsable record where revision can be extracted which is usually not the case. Most of remote records link are pointing to HTML document).
Related work
Checklist
mainbranch, backports managed with labelREADME.mdfilespom.xmldependency management. Update build documentation with intended library use and library tutorials or documentationFunded by Ifremer