Skip to content

The multiple links issue #236

@ashleysommer

Description

@ashleysommer

I'm not sure if this issue should be on prez, or prez-ui, or both.
I believe this is a bug/limitation with Prez, that affects the functionality of prez-ui.
Relevant issue in prez repo RDFLib/prez#441


This is an issue I've been struggling to articulate and demonstrate for a couple of months, and it is what has been making the BDR's Catalogues-of-Catalogues implementation very difficult.

Consider the following endpoints configuration:

customendpoints:catalogues-listing a ont:DynamicEndpoint, ont:ListingEndpoint ;
    rdfs:label "Catalogues Listing" ;
    ont:apiPath "/catalogues" ;
    ont:relevantShapes customendpoints:shape-R0-HL1 .

customendpoints:catalogues-object a ont:DynamicEndpoint, ont:ObjectEndpoint ;
    rdfs:label "Catalogues Object" ;
    ont:apiPath "/catalogues/{catalogueId}" ;
    ont:relevantShapes customendpoints:shape-R0-HL1 .

customendpoints:shape-R0-HL1 a sh:NodeShape ;
    sh:targetClass dcat:Catalog , schema:DataCatalog ;
    sh:property [
      sh:path [ sh:alternativePath ( [ sh:inversePath schema:isPartOf ] schema:hasPart )] ;
      sh:class schema:DataCatalog ;
    ] ;
    ont:hierarchyLevel 1 .

customendpoints:collections-listing a ont:DynamicEndpoint, ont:ListingEndpoint ;
    rdfs:label "Collections Listing" ;
    ont:apiPath "/catalogues/{catalogueId}/collections" ;
    ont:relevantShapes customendpoints:shape-R0-HL2 .

customendpoints:collections-object a ont:DynamicEndpoint, ont:ObjectEndpoint ;
    rdfs:label "Collections Object" ;
    ont:apiPath "/catalogues/{catalogueId}/collections/{recordsCollectionId}" ;
    ont:relevantShapes customendpoints:shape-R0-HL2 .

customendpoints:shape-R0-HL2 a sh:NodeShape ;
    sh:targetClass skos:Collection,
        skos:ConceptScheme,
        schema:Dataset ,
        schema:DataCatalog ;  #<-- DataCatalog can appear inside a parent DataCatalog
    sh:property [
      sh:path [ sh:alternativePath ( [ sh:inversePath schema:hasPart ] schema:isPartOf )] ;
      sh:class schema:DataCatalog ;
    ] ;
    ont:hierarchyLevel 2 .

I've omitted the HL3 Endpoints and NodeShapes because I don't think they are relevant (perhaps they are).

This is the a relevant snippet of data from the data graph:

<http://example.org/cats/vocab-cats> a schema:DataCatalogue ;
    schema:name "Catalogue of Vocabularies Catalogues (Top Level)"  ;
    schema:hasPart <http://example.org/cats/vocab-cat1> ;
    schema:hasPart <http://example.org/cats/vocab-cat2> .

<http://example.org/cats/vocab-cat1> a schema:DataCatalogue ;
    schema:name "A Catalogue of Vocabularies (Second Level)" ;
    schema:hasPart <http://example.org/vocabs/vocab1> ;
    schema:hasPart <http://example.org/vocabs/vocab2> .

<http://example.org/cats/vocab-cat2> a schema:DataCatalogue ;
    schema:name "Another Catalogue of Vocabularies (Second Level)" ;
    schema:hasPart <http://example.org/vocabs/vocab3> ;
    schema:hasPart <http://example.org/vocabs/vocab4> .

<http://example.org/vocabs/vocab1> a skos:ConceptScheme ;
    skos:prefLabel "Vocab1" ;
    skos:hasTopConcept <http://example.org/vocabs/vocab1/c1> .

<http://example.org/vocabs/vocab1/c1> a skos:Concept ;
    skos:prefLabel "Concept1" .

The intention with this endpoints config is that H1 objects are always schema:DataCatalog, but those catalogues can contain items that are also schema:DataCatalog. This is not an uncommon requirement.

When you request the H1 collection of Catalogues at the /catalogues endpoint, Prez includes prez:link links in the returned graph, that are used to create links to each of the catalogues.

Due to the nature of how Prez generates link annotations, it means in this configuration, prez can/will return two different links for some catalogues.

For example, when listing the set of catalogues, prez will return this response:

ex-cat:vocab-cats a schema:DataCatalog ;
    prez:identifier "ex-cat:vocab-cats" ;
    prez:label "Catalogue of Vocabularies Catalogues (Top Level)";
    prez:link "/catalogues/ex-cat:vocab-cats" ;
    prez:members "/catalogues/ex-cat:vocab-cats/collections" .

ex-cat:vocab-cat1 a schema:DataCatalog ;
    prez:identifier "ex-cat:vocab-cat1" ;
    prez:label "A Catalogue of Vocabularies (Second Level)" ;
    prez:link "/catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1",
        "/catalogues/ex-cat:vocab-cat1" ; # BOTH
    prez:members "/catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1/items" 
    # OR
    prez:members "/catalogues/ex-cat:vocab-cat1/collections"  
    .

ex-cat:vocab-cat2 a schema:DataCatalog ;
    prez:identifier "ex-cat:vocab-cat2" ;
    prez:label "Another Catalogue of Vocabularies (Second Level)" ;
    prez:link "/catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat2",
        "/catalogues/ex-cat:vocab-cat2" ; #BOTH
    prez:members "/catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat2/items" 
    # OR
    prez:members "/catalogues/ex-cat:vocab-cat2/collections"  
    .

As you can see, the first top-level catalogue has one prez:link, but others each have two valid links.
They both make sense.

  • ex-cat:vocab-cat1 is a schema:DataCatalog so it should appear in the catalogue level in the hierarchy, so the link rendered for that item should be /catalogues/ex-cat:vocab-cat1
  • ex-cat:vocab-cat1 is a member of ex-cat:vocab-cats, so it should appear in the second level in the hierarchy, so the link rendered for it should be /catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1.

I don't know how Prez-UI chooses which link URL to use. Perhaps it should always choose the longest one? Perhaps it should always be the shortest one?

Note, the Prez server does also generate two different prez:members links for these: "/catalogues/bdr-cat:datasets/collections" and "/catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1/items" . However there is a safeguard in the Prez server to only include one in the response. A complication is, this is non-deterministic. Sometimes the server will include the H2 members link, sometimes the H3 one. However once it uses one, it is cached. So Prez server will always use the same members link for that item until the server is restarted, then is is random once more.

When choosing which prez:link to use when rendering the listing at /catalogues, it doesn't really matter when Prez-UI uses /catalogues/ex-cat:vocab-cat1 or /catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1, they both render the Catalogue fine.
The problem comes when linking to the members of those.

When clicking on one of the catalogues in the listing, then clicking on "members" link of that catalog to view its contents, there are 4 different scenarios that can play out, stemming from the use of two different prez:link values, and two different prez:members values.
1.
a) first click takes you to /catalogues/ex-cat:vocab-cat1.
b) "members" click -> /catalogues/ex-cat:vocab-cat1/collections
c) This works fine. This is how I would expect it to always work.
2.
a) first click takes you to /catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1
b) "members" click -> /catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1/items
c) This throws an error, because the items are "ConceptScheme", and they cannot be rendered as third-level "Items", they only work as second level "Collections".
3.
a) first click takes you to /catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1.
b) "members" click -> /catalogues/ex-cat:vocab-cat1/collections
c) This works fine, because the collection gets hoisted to the catalogue level, to make room for the ConceptScheme as the collection.
4.
a) first click takes you to /catalogues/ex-cat:vocab-cat1.
b) "members" click -> /catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1/items
c) This rarely happens, but if it does, it breaks for the same reason as scenario 2.

The likelihood of each of these scenarious happening seems to be influenced by the version of Prez used.
Eg, when using Prez v4.14.2 (before the oxigraph serialization and many optimisations to link-generation), it is most likely to get Scenario 3.
After upgrading to Prez v4.22.0, I'm most likely to see Scenario 2. I believe this is due to the ordering of which triples are read first in the backend, when Prez runs its internal link lookup queries. This then influences a) which prez:members link to include (it only ever includes the first one it finds), and b) the order of the prez:link values in the response. That subsequently influences which links Prez-UI will use.

For an example, in using Prez backend server v4.22.0, the above example response looks like this:

ex-cat:vocab-cats a schema:DataCatalog .
ex-cat:vocab-cat1 a schema:DataCatalog .
ex-cat:vocab-cat2 a schema:DataCatalog .

ex-cat:vocab-cats prez:link "/catalogues/ex-cat:vocab-cats" ;
    prez:identifier "ex-cat:vocab-cats" ;
    prez:label "Catalogue of Vocabularies Catalogues (Top Level)";
    prez:members "/catalogues/ex-cat:vocab-cats/collections"  .

ex-cat:vocab-cat1 prez:link "/catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1" ;
    prez:identifier "ex-cat:vocab-cat1" ;
    prez:label "A Catalogue of Vocabularies (Second Level)" ;
    prez:link "/catalogues/ex-cat:vocab-cat1" ;
    prez:members "/catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1/items"  .

ex-cat:vocab-cat2  prez:link "/catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat2" ;
    prez:identifier "ex-cat:vocab-cat2" ;
    prez:label "Another Catalogue of Vocabularies (Second Level)" ;
    prez:link "/catalogues/ex-cat:vocab-cat2" ;
    prez:members "/catalogues/ex-cat:vocab-cats/collections/ex-cat:vocab-cat1/items"  .

Continued in comments in the prez thread:
RDFLib/prez#441

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions