diff --git a/model/ontology.ttl b/model/ontology.ttl new file mode 100644 index 00000000..7661538b --- /dev/null +++ b/model/ontology.ttl @@ -0,0 +1,587 @@ +@prefix icar: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . + +# icar item +icar:Resource + a rdfs:Class ; + rdfs:label "Resource" . + +icar:meta + a rdf:Property ; + rdfs:label "meta" ; + rdfs:range icar:Meta . + +icar:location + a rdf:Property ; + rdfs:label "location" ; + rdfs:range rdfs:Resource . + +icar:Meta + a rdfs:Class ; + rdfs:label "Meta" . + +icar:source + a rdf:Property ; + rdfs:label "source" ; + rdfs:range rdfs:Resource . + +icar:isDeleted + a rdf:Property ; + rdfs:label "isDeleted" ; + rdfs:range xsd:boolean . + +icar:modified + a rdf:Property ; + rdfs:label "modified" ; + rdfs:range icar:DateTime . + +icar:created + a rdf:Property ; + rdfs:label "created" ; + rdfs:range icar:DateTime . + +icar:creator + a rdf:Property ; + rdfs:label "creator" ; + rdfs:range xsd:string . + +icar:validFrom + a rdf:Property ; + rdfs:label "validFrom" ; + rdfs:range icar:DateTime . + +icar:validTo + a rdf:Property ; + rdfs:label "validTo" ; + rdfs:range icar:DateTime . + +icar:ResourceShape + a sh:NodeShape ; + sh:targetClass icar:Resource ; + sh:label "Resource Shape" ; + sh:description "Constraints for representing a resource." ; + sh:property [ + sh:path icar:meta ; + sh:name "meta" ; + sh:class icar:Meta ; + sh:nodeKind sh:IRI ; + sh:minCount 1 ; + sh:description "Metadata about the resource." . + ]; + sh:property [ + sh:path icar:location ; + sh:name "location" ; + sh:datatype xsd:anyURI ; + sh:minCount 0 ; + sh:description "Location of the resource." . + ]; + sh:property [ + sh:path icar:isDeleted ; + sh:name "isDeleted" ; + sh:datatype xsd:boolean ; + sh:minCount 1 ; + sh:description "Indicates if the resource is deleted." . + ]; + sh:property [ + sh:path icar:modified ; + sh:name "modified" ; + sh:datatype icar:DateTime ; + sh:minCount 1 ; + sh:description "Date and time of the last modification." . + ]; + sh:property [ + sh:path icar:created ; + sh:name "created" ; + sh:datatype icar:DateTime ; + sh:minCount 1 ; + sh:description "Date and time of the creation." . + ]; + sh:property [ + sh:path icar:creator ; + sh:name "creator" ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:description "Person or entity responsible for the creation." . + ]; + sh:property [ + sh:path icar:validFrom ; + sh:name "validFrom" ; + sh:datatype icar:DateTime ; + sh:minCount 0 ; + sh:description "Date and time from which the resource is valid." . + ]; + sh:property [ + sh:path icar:validTo ; + sh:name "validTo" ; + sh:datatype icar:DateTime ; + sh:minCount 0 ; + sh:description "Date and time until which the resource is valid." . + ] . + + + +# Animal Class +icar:Animal + a rdfs:Class ; + rdfs:subClassOf icar:Resource ; + rdfs:label "Animal" . + +# Identifiers would not be done like this, but instead as URLs +icar:hasIdentifier + a rdf:Property ; + rdfs:label "identifier" ; + rdfs:range icar:AnimalIdentifierType . + +icar:hasAlternativeIdentifier + a rdf:Property ; + rdfs:label "alternativeIdentifiers" ; + rdfs:range rdfs:Resource . + +# Properties +icar:hasSpecie + a rdf:Property ; + rdfs:label "specie" ; + rdfs:range icar:AnimalSpecie . + +icar:hasSpecie + a rdf:Property ; + rdfs:label "specie" ; + rdfs:range icar:AnimalSpecie . + +# Note we remove the form Type from the class names. +icar:hasGender + a rdf:Property ; + rdfs:label "gender" ; + rdfs:range icar:AnimalGenderType . + +icar:hasBirthDate + a rdf:Property ; + rdfs:label "birthDate" ; + rdfs:range icar:DateTime . + +# This could become just a URI +icar:hasPrimaryBreed + a rdf:Property ; + rdfs:label "primaryBreed" ; + rdfs:range icar:BreedIdentifier . + +icar:hasBreedFractions + a rdf:Property ; + rdfs:label "breedFractions" ; + rdfs:range icar:BreedFractions . + +icar:hasCoatColor + a rdf:Property ; + rdfs:label "coatColor" ; + rdfs:range xsd:string . + +icar:hasCoatColorIdentifier + a rdf:Property ; + rdfs:label "coatColorIdentifier" ; + rdfs:range icar:CoatColorIdentifier . + +icar:hasManagementTag + a rdf:Property ; + rdfs:label "managementTag" ; + rdfs:range xsd:string . + +icar:hasName + a rdf:Property ; + rdfs:label "name" ; + rdfs:range xsd:string . + +icar:hasOfficialName + a rdf:Property ; + rdfs:label "officialName" ; + rdfs:range xsd:string . + +icar:hasProductionPurpose + a rdf:Property ; + rdfs:label "productionPurpose" ; + rdfs:range icar:ProductionPurpose . + +icar:hasStatus + a rdf:Property ; + rdfs:label "status" ; + rdfs:range icar:AnimalStatus . + +icar:hasReproductionStatus + a rdf:Property ; + rdfs:label "reproductionStatus" ; + rdfs:range icar:AnimalReproductionStatus . + +icar:hasLactationStatus + a rdf:Property ; + rdfs:label "lactationStatus" ; + rdfs:range icar:AnimalLactationStatus . + +icar:hasParentage + a rdf:Property ; + rdfs:label "parentage" ; + rdfs:range icar:Parentage . + +icar:memberOf + a rdf:Property ; + rdfs:label "memberOf" ; + rdfs:range icar:AnimalSet . + +icar:hasHealthStatus + a rdf:Property ; + rdfs:label "healthStatus" ; + rdfs:range icar:AnimalHealthStatus . + + +# Define the Animal class as a SHACL shape +icar:AnimalShape + a sh:NodeShape ; + sh:targetClass icar:Animal ; + sh:label "Animal Shape" ; + sh:description "Constraints for representing an animal." ; + sh:property [ + sh:path icar:hasIdentifier ; + sh:name "identifier" ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:description "Identifier of the animal." . + ]; + sh:property [ + sh:path icar:hasAlternativeIdentifier ; + sh:name "alternativeIdentifiers" ; + sh:datatype xsd:string ; + sh:minCount 0 ; + sh:description "Alternative identifiers of the animal." . + ]; + sh:property [ + sh:path icar:hasSpecie ; + sh:name "specie" ; + sh:nodeKind sh:IRI ; + sh:minCount 1 ; + sh:description "Specie of the animal." . + ] ; + sh:property [ + sh:path icar:memberOf ; + sh:class icar:AnimalSet ; + sh:nodeKind sh:IRI ; + sh:minCount 1 ; + sh:description "Animal is a member of animal set." . + ] . + +# Event +icar:Event + a rdfs:Class ; + rdfs:subClassOf icar:Resource ; + rdfs:label "EventCore" . + +icar:eventDateTime + a rdf:Property ; + rdf:description "RFC3339 UTC date and time (see https://ijmacd.github.io/rfc3339-iso8601/)." ; + rdfs:label "eventDateTime" ; + rdfs:range icar:DateTime . + +icar:traitLabel + a rdf:Property ; + rdfs:description "If the event represents a formal trait, identifies the recording system and trait." ; + rdfs:label "traitLabel" ; + rdfs:range xsd:string . + +icar:responsible + a rdf:Property ; + rdfs:label "responsible" ; + rdfs:range xsd:string . + +icar:contemporaryGroup + a rdf:Property ; + rdfs:label "contemporaryGroup" ; + rdfs:range xsd:string . + +icar:remark + a rdf:Property ; + rdfs:label "remarks" ; + rdfs:range xsd:string . + +icar:EventShape + a sh:NodeShape ; + sh:targetClass icar:Event ; + sh:label "Event Shape" ; + sh:description "Constraints for representing an event." ; + sh:property [ + sh:path icar:eventDateTime ; + sh:name "eventDateTime" ; + sh:datatype icar:DateTime ; + sh:minCount 1 ; + sh:description "Date and time of the event." . + ]; + sh:property [ + sh:path icar:traitLabel ; + sh:name "traitLabel" ; + sh:datatype xsd:string ; + sh:minCount 0 ; + sh:description "If the event represents a formal trait, identifies the recording system and trait." . + ]; + sh:property [ + sh:path icar:responsible ; + sh:name "responsible" ; + sh:datatype xsd:string ; + sh:minCount 0 ; + sh:description "Person or entity responsible for the event." . + ]; + sh:property [ + sh:path icar:contemporaryGroup ; + sh:name "contemporaryGroup" ; + sh:datatype xsd:string ; + sh:minCount 0 ; + sh:description "Group of animals that are managed together and are exposed to the same environmental conditions." . + ]; + sh:property [ + sh:path icar:remark ; + sh:name "remark" ; + sh:datatype xsd:string ; + sh:minCount 0 ; + sh:description "Additional information about the event." . + ] . + +# AnimalEvent +icar:AnimalEvent + a rdfs:Class ; + rdfs:label "AnimalEvent" ; + rdfs:subClassOf icar:Event . + +icar:animal + a rdf:Property ; + rdfs:label "animal" ; + rdfs:range icar:Animal . + +icar:AnimalEventShape + a sh:NodeShape ; + sh:targetClass icar:AnimalEvent ; + sh:label "Animal Event Shape" ; + sh:description "Constraints for representing an animal event." ; + sh:property [ + sh:path icar:eventDateTime ; + sh:name "eventDateTime" ; + sh:datatype icar:DateTime ; + sh:minCount 1 ; + sh:description "Date and time of the event." . + ]; + sh:property [ + sh:path icar:animal ; + sh:name "animal" ; + sh:datatype xsd:anyURI ; + sh:minCount 1 ; + sh:description "Animal involved in the event." . + ] . + +icar:AnimalSet + a rdfs:Class ; + rdfs:subClassOf icar:Resource ; + rdfs:label "AnimalSet" . + +icar:name + a rdf:Property ; + rdfs:label "name" ; + rdfs:range xsd:string . + +icar:purpose + a rdf:Property ; + rdfs:label "purpose" ; + rdfs:range icar:AnimalSetPurpose . + +icar:members + a rdf:Property ; + rdfs:label "members" ; + rdfs:range icar:Animal ; + owl:inverseOf icar:partOf . + +icar:AnimalSetShape + a sh:NodeShape ; + sh:targetClass icar:AnimalSet ; + sh:label "Animal Set Shape" ; + sh:description "Constraints for representing an animal set." ; + sh:property [ + sh:path icar:name ; + sh:name "name" ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:description "Name of the animal set." . + ]; + sh:property [ + sh:path icar:purpose ; + sh:name "purpose" ; + sh:nodeKind sh:IRI ; + sh:minCount 1 ; + sh:description "Purpose of the animal set." . + ]; + sh:property [ + sh:path icar:members ; + sh:name "members" ; + sh:nodeKind sh:IRI ; + sh:minCount 1 ; + sh:description "Members of the animal set." . + ] . + + +icar:AnimalSetJoinEvent + a rdfs:Class ; + rdfs:label "AnimalSetJoinEvent" ; + rdfs:subClassOf icar:AnimalEvent . + +icar:animalSet + a rdf:Property ; + rdfs:label "animalSet" ; + rdfs:range icar:AnimalSet . + +icar:AnimalSetJoinEventShape + a sh:NodeShape ; + rdfs:subClassOf icar:AnimalEventShape ; + sh:targetClass icar:Animal ; + sh:label "Animal Set Join Event Shape" ; + sh:description "Constraints for representing an animal set join event." ; + sh:property [ + sh:path icar:animalSet ; + sh:class icar:AnimalSet ; + sh:nodeKind sh:IRI ; + sh:minCount 1 ; + sh:description "Animal set that has been joined." . + ] . + +icar:AnimalSetLeaveEvent + a rdfs:Class ; + rdfs:label "AnimalSetLeaveEvent" ; + rdfs:subClassOf icar:AnimalEvent . + +icar:AnimalSetLeaveEventShape + a sh:NodeShape ; + rdfs:subClassOf icar:AnimalEventShape ; + sh:targetClass icar:Animal ; + sh:label "Animal Set Leave Event Shape" ; + sh:description "Constraints for representing an animal set leave event." ; + sh:property [ + sh:path icar:animalSet ; + sh:class icar:AnimalSet ; + sh:nodeKind sh:IRI ; + sh:minCount 1 ; + sh:description "Animal set that has been left." . + ] . + + +icar:BreedingValue + a rdfs:Class ; + rdfs:label "Breeding Value" ; + rdfs:subClassOf icar:Resource . + +icar:animal + a rdf:Property ; + rdfs:label "animal" ; + rdfs:range icar:Animal . + +icar:base + a rdf:Property ; + rdfs:label "base" ; + rdfs:range rdfs:Resource . + +icar:version + a rdf:Property ; + rdfs:label "version" ; + rdfs:range xsd:string . + +icar:breedingValues + a rdf:Property ; + rdfs:label "breedingValues" ; + rdfs:range icar:BreedingValueValue . + +icar:BreedingValueShape + a sh:NodeShape ; + sh:targetClass icar:BreedingValue ; + sh:label "Breeding Value Shape" ; + sh:description "Constraints for representing a breeding value." ; + sh:property [ + sh:path icar:animal ; + sh:name "animal" ; + sh:datatype icar:Animal ; + sh:minCount 1 ; + sh:description "Animal for which the breeding value is calculated." . + ]; + sh:property [ + sh:path icar:base ; + sh:name "base" ; + sh:class rdfs:Resource ; + sh:minCount 1 ; + sh:description "Base of the breeding value." . + ]; + sh:property [ + sh:path icar:version ; + sh:name "version" ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:description "Version of the breeding value." . + ]; + # this can probably be expressed as a list + sh:property [ + sh:path icar:breedingValues ; + sh:name "breedingValues" ; + sh:class icar:BreedingValueValue ; + sh:minCount 0 ; + sh:description "Breeding values." . + ] . + +icar:BreedingValueValue + a rdfs:Class ; + rdfs:label "Breeding Value Value" . + +icar:trait + a rdf:Property ; + rdfs:label "trait" ; + rdfs:range rdfs:Resource . + +icar:calculationType + a rdf:Property ; + rdfs:label "calculationType" ; + rdfs:range icar:BreedValueCalculationType . + +icar:breadingValue + a rdf:Property ; + rdfs:label "breadingValue" ; + rdfs:range xsd:float . + +icar:breedingValueResolution + a rdf:Property ; + rdfs:label "breedingValueResolution" ; + rdfs:range xsd:float . + +icar:BreedingValueValueShape + a sh:NodeShape ; + sh:targetClass icar:BreedingValueValue ; + sh:label "Breeding Value Value Shape" ; + sh:description "Constraints for representing a breeding value value." ; + sh:property [ + sh:path icar:trait ; + sh:name "trait" ; + sh:datatype rdfs:Resource ; + sh:minCount 1 ; + sh:description "Trait for which the breeding value is calculated." . + ]; + sh:property [ + sh:path icar:calculationType ; + sh:name "calculationType" ; + sh:datatype icar:BreedValueCalculationType ; + sh:minCount 1 ; + sh:description "Calculation type of the breeding value." . + ]; + sh:property [ + sh:path icar:breadingValue ; + sh:name "breadingValue" ; + sh:datatype xsd:float ; + sh:minCount 1 ; + sh:description "Breeding value." . + ]; + sh:property [ + sh:path icar:breedingValueResolution ; + sh:name "breedingValueResolution" ; + sh:datatype xsd:float ; + sh:minCount 1 ; + sh:description "Breeding value resolution." . + ] . + + diff --git a/model/readme.md b/model/readme.md new file mode 100644 index 00000000..c28cf162 --- /dev/null +++ b/model/readme.md @@ -0,0 +1,274 @@ +# Information Model for Dairy Data Model - Dairy Information Model + +The json schema and API define the exchange syntax for the Dairy Data Model. While this structures allude to the underlying data model they do not fully describe or explain it fully. Examples of this are properties that are the Ids of other constructs, references between events and animals, or for example lineage relationships. + +This document describes the logical data model that underpins the JSON serialisations. Its goal is to communicate less ambiguously the relationships and structures of the model. + +The model is defined here using Semantic Technologies to formalise the diiferent constructs, their properties and relationships. + +A formal model as defined here can further be used to generate visual diagrams and also as the basis for defining how API operations are expected to work. E.g. defining an initial state of a 'location', then an operation, and then the expected new state. + +# Example + +The following example shows how basic constructs are represented with RDF and SHACL. + +We take a core construct such as Animal + +``` json + +{ + "description": "Core schema for representing animal", + + "allOf": [{ + "$ref": "../resources/icarResource.json" + }, + { + "type": "object", + + "required": [ + "identifier", + "specie", + "gender" + ], + + "properties": { + "identifier": { + "$ref": "../types/icarAnimalIdentifierType.json", + "description": "Unique animal scheme and identifier combination." + }, + "alternativeIdentifiers": { + "type": "array", + "items": { + "$ref": "../types/icarAnimalIdentifierType.json" + }, + "description": "Alternative identifiers for the animal. Here, also temporary identifiers, e.g. transponders or animal numbers, can be listed." + }, + "specie": { + "$ref": "../enums/icarAnimalSpecieType.json", + "description": "Species of the animal." + }, + "gender": { + "$ref": "../enums/icarAnimalGenderType.json", + "description": "Gender of the animal." + }, + "birthDate": { + "$ref": "../types/icarDateTimeType.json", + "description": "RFC3339 UTC date/time of birth (see https://ijmacd.github.io/rfc3339-iso8601/ for how to use)." + }, + "primaryBreed": { + "$ref": "../types/icarBreedIdentifierType.json", + "description": "ICAR Breed code for the animal." + }, + "breedFractions": { + "$ref": "../types/icarBreedFractionsType.json", + "description": "Breed fractions for the animal." + }, + "coatColor": { + "type": "string", + "description": "Colour of the animal's coat, using the conventions for that breed." + }, + "coatColorIdentifier": { + "$ref": "../types/icarCoatColorIdentifierType.json", + "description": "Colour of the animal's coat using a national or breed-defined scheme and identifier combination." + }, + "managementTag": { + "type": "string", + "description": "The identifier used by the farmer in day to day operations. In many cases this could be the animal number." + }, + "name": { + "type": "string", + "description": "Name given by the farmer for this animal." + }, + "officialName": { + "type": "string", + "description": "Official herdbook name." + }, + "productionPurpose": { + "$ref": "../enums/icarProductionPurposeType.json", + "description": "Primary production purpose for which animals are bred." + }, + "status": { + "$ref": "../enums/icarAnimalStatusType.json", + "description": "On-farm status of the animal (such as alive, dead, off-farm)." + }, + "reproductionStatus": { + "$ref": "../enums/icarAnimalReproductionStatusType.json", + "description": "Reproduction status of the animal." + }, + "lactationStatus": { + "$ref": "../enums/icarAnimalLactationStatusType.json", + "description": "Lactation status of the animal." + }, + "parentage": { + "type": "array", + "items": { + "$ref": "../types/icarParentageType.json", + "description": "Array of parents." + } + }, + "healthStatus": { + "$ref": "../enums/icarAnimalHealthStatusType.json", + "description": "Health status of the animal (such as Healthy, Suspicious, Ill, InTreatment, ToBeCulled)." + } + } + } + ] +} +``` + +And systematically we can create the RDF version of this: + +``` turtle + +@prefix icar: . +@prefix rdf: . +@prefix rdfs: . + +# Animal Class +icar:Animal + a rdfs:Class ; + rdfs:label "Core schema for representing animal" . + + +# Identifiers would not be done like this, but instead as URLs +icar:hasIdentifier + a rdf:Property ; + rdfs:label "identifier" ; + rdfs:range icar:AnimalIdentifierType . + +icar:hasAlternativeIdentifiers + a rdf:Property ; + rdfs:label "alternativeIdentifiers" ; + rdfs:range icar:AnimalIdentifierType . + +# Properties +icar:hasSpecie + a rdf:Property ; + rdfs:label "specie" ; + rdfs:range icar:AnimalSpecie . + +icar:hasSpecie + a rdf:Property ; + rdfs:label "specie" ; + rdfs:range icar:AnimalSpecie . + +# Note we remove the form Type from the class names. +icar:hasGender + a rdf:Property ; + rdfs:label "gender" ; + rdfs:range icar:AnimalGenderType . + +icar:hasBirthDate + a rdf:Property ; + rdfs:label "birthDate" ; + rdfs:range icar:DateTime . + +# This could become just a URI +icar:hasPrimaryBreed + a rdf:Property ; + rdfs:label "primaryBreed" ; + rdfs:range icar:BreedIdentifier . + +icar:hasBreedFractions + a rdf:Property ; + rdfs:label "breedFractions" ; + rdfs:range icar:BreedFractions . + +icar:hasCoatColor + a rdf:Property ; + rdfs:label "coatColor" ; + rdfs:range xsd:string . + +icar:hasCoatColorIdentifier + a rdf:Property ; + rdfs:label "coatColorIdentifier" ; + rdfs:range icar:CoatColorIdentifier . + +icar:hasManagementTag + a rdf:Property ; + rdfs:label "managementTag" ; + rdfs:range xsd:string . + +icar:hasName + a rdf:Property ; + rdfs:label "name" ; + rdfs:range xsd:string . + +icar:hasOfficialName + a rdf:Property ; + rdfs:label "officialName" ; + rdfs:range xsd:string . + +icar:hasProductionPurpose + a rdf:Property ; + rdfs:label "productionPurpose" ; + rdfs:range icar:ProductionPurpose . + +icar:hasStatus + a rdf:Property ; + rdfs:label "status" ; + rdfs:range icar:AnimalStatus . + +icar:hasReproductionStatus + a rdf:Property ; + rdfs:label "reproductionStatus" ; + rdfs:range icar:AnimalReproductionStatus . + +icar:hasLactationStatus + a rdf:Property ; + rdfs:label "lactationStatus" ; + rdfs:range icar:AnimalLactationStatus . + +icar:hasParentage + a rdf:Property ; + rdfs:label "parentage" ; + rdfs:range icar:Parentage . + +icar:hasHealthStatus + a rdf:Property ; + rdfs:label "healthStatus" ; + rdfs:range icar:AnimalHealthStatus . + +``` + +As well as these basic declarations we can also add constraints. It is these constraints that add further rigour to the model. + +``` +@prefix icar: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . + +# Define the Animal class as a SHACL shape +icar:AnimalShape + a sh:NodeShape ; + sh:targetClass icar:Animal ; + sh:label "Animal Shape" ; + sh:description "Constraints for representing an animal." ; + sh:property [ + sh:path icar:hasIdentifier ; + sh:name "identifier" ; + sh:datatype xsd:anyURI ; + sh:minCount 1 ; + sh:description "Unique animal scheme and identifier combination." . + ]; + sh:property [ + sh:path icar:hasAlternativeIdentifiers ; + sh:name "alternativeIdentifiers" ; + sh:datatype xsd:anyURI ; + sh:minCount 0 ; + sh:description "Alternative identifiers for the animal." . + ]; + sh:property [ + sh:path icar:hasHealthStatus ; + sh:name "healthStatus" ; + sh:datatype xsd:string ; + sh:minCount 1 ; + sh:description "Health status of the animal." . + ] . + + +``` + +With the model defined formally like this it is possible to reason about the model and also to define one or more syntactic mappings to the model. So for example it would be possible to represent instance data in RDF and correcly be able to map it to and from the JSON representation. +