diff --git a/CHANGELOG.md b/CHANGELOG.md index e3420b4a..c1bf14a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Add `mapping_tool_id` slot to the `Mapping` and `MappingSet` classes ([issue](https://github.com/mapping-commons/sssom/issues/449)). - Add `record_id` slot to the `Mapping` class ([issue](https://github.com/mapping-commons/sssom/issues/359)). - Change all URI-typed slots to clarify that they expect _non-relative_ URIs as values ([issue](https://github.com/mapping-commons/sssom/issues/448)). +- Add `cardinality_scope` slot ([issue](https://github.com/mapping-commons/sssom/issues/467)). ## SSSOM version 1.0.0 diff --git a/examples/schema/cardinality-scope-empty.sssom.tsv b/examples/schema/cardinality-scope-empty.sssom.tsv new file mode 100644 index 00000000..2dc7613d --- /dev/null +++ b/examples/schema/cardinality-scope-empty.sssom.tsv @@ -0,0 +1,14 @@ +#curie_map: +# COMENT: https://example.com/entities/ +# NETENT: https://example.net/entities/ +# ORGENT: https://example.org/entities/ +# SRC: https://example.org/sources/ +#mapping_set_id: https://example.org/sets/cardinality-scope-empty +#license: https://creativecommons.org/licenses/by/4.0/ +subject_id subject_label predicate_id object_id object_label mapping_justification object_source mapping_cardinality +ORGENT:0001 alice skos:closeMatch COMENT:0011 alpha semapv:ManualMappingCuration SRC:com 1:n +ORGENT:0001 alice skos:closeMatch NETENT:0111 alpha semapv:ManualMappingCuration SRC:net 1:n +ORGENT:0002 bob skos:closeMatch COMENT:0012 beta semapv:ManualMappingCuration SRC:com 1:n +ORGENT:0002 bob skos:closeMatch NETENT:0112 bravo semapv:ManualMappingCuration SRC:net 1:n +ORGENT:0007 gavin skos:closeMatch NETENT:0117 golf semapv:ManualMappingCuration SRC:net 1:n +ORGENT:0007 gavin skos:exactMatch COMENT:0013 gamma semapv:ManualMappingCuration SRC:com 1:n diff --git a/examples/schema/cardinality-scope-predicate+object_source.sssom.tsv b/examples/schema/cardinality-scope-predicate+object_source.sssom.tsv new file mode 100644 index 00000000..68a2a6ee --- /dev/null +++ b/examples/schema/cardinality-scope-predicate+object_source.sssom.tsv @@ -0,0 +1,17 @@ +#curie_map: +# COMENT: https://example.com/entities/ +# NETENT: https://example.net/entities/ +# ORGENT: https://example.org/entities/ +# SRC: https://example.org/sources/ +#mapping_set_id: https://example.org/sets/cardinality-scope-predicate+object_source +#license: https://creativecommons.org/licenses/by/4.0/ +#cardinality_scope: +# - predicate_id +# - object_source +subject_id subject_label predicate_id object_id object_label mapping_justification object_source mapping_cardinality +ORGENT:0001 alice skos:closeMatch COMENT:0011 alpha semapv:ManualMappingCuration SRC:com 1:1 +ORGENT:0001 alice skos:closeMatch NETENT:0111 alpha semapv:ManualMappingCuration SRC:net 1:1 +ORGENT:0002 bob skos:closeMatch COMENT:0012 beta semapv:ManualMappingCuration SRC:com 1:1 +ORGENT:0002 bob skos:closeMatch NETENT:0112 bravo semapv:ManualMappingCuration SRC:net 1:1 +ORGENT:0007 gavin skos:closeMatch NETENT:0117 golf semapv:ManualMappingCuration SRC:net 1:1 +ORGENT:0007 gavin skos:exactMatch COMENT:0013 gamma semapv:ManualMappingCuration SRC:com 1:1 diff --git a/examples/schema/cardinality-scope-predicate.sssom.tsv b/examples/schema/cardinality-scope-predicate.sssom.tsv new file mode 100644 index 00000000..86bf8bde --- /dev/null +++ b/examples/schema/cardinality-scope-predicate.sssom.tsv @@ -0,0 +1,16 @@ +#curie_map: +# COMENT: https://example.com/entities/ +# NETENT: https://example.net/entities/ +# ORGENT: https://example.org/entities/ +# SRC: https://example.org/sources/ +#mapping_set_id: https://example.org/sets/cardinality-scope-predicate +#license: https://creativecommons.org/licenses/by/4.0/ +#cardinality_scope: +# - predicate_id +subject_id subject_label predicate_id object_id object_label mapping_justification object_source mapping_cardinality +ORGENT:0001 alice skos:closeMatch COMENT:0011 alpha semapv:ManualMappingCuration SRC:com 1:n +ORGENT:0001 alice skos:closeMatch NETENT:0111 alpha semapv:ManualMappingCuration SRC:net 1:n +ORGENT:0002 bob skos:closeMatch COMENT:0012 beta semapv:ManualMappingCuration SRC:com 1:n +ORGENT:0002 bob skos:closeMatch NETENT:0112 bravo semapv:ManualMappingCuration SRC:net 1:n +ORGENT:0007 gavin skos:closeMatch NETENT:0117 golf semapv:ManualMappingCuration SRC:net 1:1 +ORGENT:0007 gavin skos:exactMatch COMENT:0013 gamma semapv:ManualMappingCuration SRC:com 1:1 diff --git a/src/docs/spec-model.md b/src/docs/spec-model.md index 9baf58a8..cec4eb13 100644 --- a/src/docs/spec-model.md +++ b/src/docs/spec-model.md @@ -43,6 +43,7 @@ The latter are called “propagatable slots”. In the LinkML model, they are ma For convenience, here is the current list of propagatable slots: +* `cardinality_scope`, * `mapping_date`, * `mapping_provider`, * `mapping_tool`, @@ -128,6 +129,53 @@ The meaning of the NOT predicate modifier in a mapping that refers to `sssom:NoT When computing cardinality values (to fill the `mapping_cardinality` slot), mappings that refer to `sssom:NoTermFound` MUST be ignored. +## Mapping cardinality and cardinality scope + +The `mapping_cardinality` slot is somewhat special in that its value is +only meaningful within a given context, or “scope”: a mapping record in +itself does not have any cardinality – it only has one when it is part +of a larger set of records. + +Consider the following three records (set metadata, and in particular +prefix declarations, have been omitted for brevity): + +| `subject_id` | `predicate_id` | `object_id` | `object_source` | +| -------------- | ---------------- | ------------ | --------------- | +| UBERON:0000011 | skos:broadMatch | VHOG:0000755 | obo:VHOG | +| UBERON:0000011 | skos:narrowMatch | EHDAA:4655 | obo:EHDAA | +| UBERON:0000011 | skos:narrowMatch | NCIT:C12764 | obo:NCIT | + +Within that particular set, all three records have a cardinality of +`1:n` (one subject, UBERON:0000011, mapped to many objects). + +But cardinality can also be computed on smaller subsets. For example: + +* if we are only interested in records that have the same predicate, + then the first record has a cardinality of `1:1` (UBERON:0000011 is + mapped to only one object through a `skos:broadMatch` predicate), + while the other two still have a cardinality of `1:n` (UBERON:0000011 + is mapped to two different objects through a `skos:narrowMatch` + predicate); +* if we are only interested in records where the objects are from the + same source, then all three records have a cardinality of `1:1` + (UBERON:0000011 is mapped to only one object in each of the three + vocabularies VHOG, EHDAA, and NCIT). + +It is left to users and downstream applications of SSSOM to decide which +type of cardinality (relative to the entire set or relative to any of +the many possible subsets) will be the most useful to them. The +`cardinality_scope` slot is intended to allow them to specify which +cardinality they use. + +When computing cardinality values: + +* if the cardinality is computed on the entire set, the + `cardinality_scope` slot MUST be left empty (or absent); +* if the cardinality is computed on a subset, the `cardinality_scope` + slot MUST be filled with the list of slots that are used to define the + subset. + + ## Non-standard slots diff --git a/src/sssom_schema/schema/sssom_schema.yaml b/src/sssom_schema/schema/sssom_schema.yaml index d2f2c93a..72601bd5 100644 --- a/src/sssom_schema/schema/sssom_schema.yaml +++ b/src/sssom_schema/schema/sssom_schema.yaml @@ -584,6 +584,38 @@ slots: description: A one-to-one mapping. - value: "1:n" description: A one-to-many mapping. + see_also: + - https://github.com/mapping-commons/sssom/blob/master/examples/schema/cardinality-scope-empty.sssom.tsv + cardinality_scope: + description: A list of mapping slots that define the scope for the value found + in the mapping_cardinality slot. Mappings are considered to belong to the same + scope if they have the same value for all slots listed in the scope. If no + scope is defined, the default scope is empty, meaning that all mappings belong + to a single scope that is identical to the entire mapping set. + The behaviour if a value in the list does not correspond to a valid slot name + is undefined. + range: string + multivalued: true + instantiates: + - sssom:Propagatable + - sssom:Versionable + annotations: + propagated: true + added_in: "1.1" + examples: + - value: + - "predicate_id" + description: Indicates that mapping_cardinality is computed relatively to all + mappings that have the same predicate. + - value: + - "predicate_id" + - "object_source" + description: Indicates that mapping_cardinality is computed relatively to all + mappings that have the same predicate and the same object source. + see_also: + - https://github.com/mapping-commons/sssom/issues/467 + - https://github.com/mapping-commons/sssom/blob/master/examples/schema/cardinality-scope-predicate.sssom.tsv + - https://github.com/mapping-commons/sssom/blob/master/examples/schema/cardinality-scope-predicate+object_source.sssom.tsv mapping_tool: description: A reference to the tool or algorithm that was used to generate the mapping. Should be a URL pointing to more info about it, but can be free text. @@ -882,6 +914,7 @@ classes: - object_source_version - predicate_type - mapping_provider + - cardinality_scope - mapping_tool - mapping_tool_id - mapping_tool_version @@ -928,6 +961,7 @@ classes: - mapping_provider - mapping_source - mapping_cardinality + - cardinality_scope - mapping_tool - mapping_tool_id - mapping_tool_version