New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Model for 2 directions of a relationship #11
Comments
we're gonna try out the vocab i proposed in #10 with bi-directional relationships, i'll report back on how it goes. |
@ahdinosaur sounds good. |
although to be fair, our data only records one direction of the relationship, so i'm actually not sure what we'll do yet. i'm thinking either automatically generate the reverse or have a way to infer the obverse relationship, as i do think many relationshipTypes do make sense to have an obverse (especially to specify obverse labels, but also as a way to link in with query labels). |
@ahdinosaur - what does obverse mean to you? |
@bhaugen corresponding, from the other side, symmetric, counterpart, ... idk. i wasn't sure what word to pick, so i went with 'obverse'. better suggestions welcome, it might be easiest to go with 'reverse' which is an existing term, but it didn't feel semantically adequate and i'd rather alias to that later on. |
That does not seem to be its dictionary definition. I had never encountered the word before, which is why I looked it up. |
ah i must have been under a wrong impression. what's a better word then? i'm not tied to obverse. |
@ahdinosaur I'm wondering if the reason you are thinking of Relationship as 2 instances, one for each direction, is that you are thinking the 2 agents might reside on different platforms and possibly different servers? So from the perspective of the target (or object) agent, the relationship would be reversed? And the relationship might exist in duplicate anyhow, depending on the caching of that info. |
@fosterlynn nah, i've realized having multiples sources of truth is separate from bi-directional relationships. the reason for bi-directional relationships, in my mind, is for semantic reasons. for a relationship like "mentors", it's important to be able to answer "what is the relationship between the mentee and the mentor" (i.e. "is mentored by")? i'm not saying we necessarily need to store separate objects for each direction, but i do think we should at least have RelationshipTypes in each direction and from there be able to infer Relationships in each direction. our approach in Holodex so far has been to make bi-directional RelationshipTypes only when we feel the relationship is actually bi-directional (e.g. membership), so maybe we'll continue with that, but it's an open question as to which relationships needs two directions. |
although, if we look at @elf-pavlik's most recent example, even a uni-directional relationship like 'follows' has reverse RelationshipType (denoted by |
related references (for my own notes): |
Once again, why do you need to create sub classes of Relationship (rdfs:Class/owl:Class)? Let's also make sure that we alwasy distinguish concept of classes in Object Oriented programming and classes in RDFS/OWL |
Or more precisely, every relationship type label has a reverse label? This makes sense to me, because even in a one way relationship like follows, you might want to display all the followers of someone. |
Sounds good. This should flesh out where we might want 2 things (objects, whatever).
I don't think anyone is advocating for subclasses, as far as I can tell? Ha ha, remember all that early discussion on type classes vs subclasses for proliferating user-defined things? I'm glad to find a way we can do it without subclasses. Although I freely admit I do not get all the LOD think yet! Still learning! |
i'm not very learned about rdf or owl, so i'm mostly thinking in terms of logical models independent of how to formalize them with existing linked data specs. in my limited understanding, it seems like what you're suggesting is exactly our intention.
here's an attempt to model in JSON-LD the relationship of @fosterlynn mentoring me within OpenVocab: {
"@context": {
"open": "http://openvocab.is/#",
"schema": "http://schema.org/"
"ex": "http://holodex.example.com/api/",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"owl": "http://www.w3.org/2002/07/owl#"
},
"@graph": [{
"@id": "ex:agentTypes/agent",
"@type": "AgentType"
}, {
"@id": "ex:agentTypes/person",
"@type": "AgentType"
}, {
"@id": "ex:agentTypes/group",
"@type": "AgentType"
}, {
"@id": "ex:relationshipTypes/mentors",
"@type": "RelationshipType",
"schema:name": "mentors",
"open:sourceAgentType": "ex:agentTypes/person",
"open:targetAgentType": "ex:agentTypes/person",
"open:contextAgentType": "ex:agentTypes/group",
"rdfs:label": "{source} mentors {target}",
"owl:inverseOf": {
"rdfs:label": "{target} is mentored by {source}"
}
}, {
"@id": "ex:agents/mikey",
"@type": "Agent",
"open:agentType": "ex:agentTypes/person",
"schema:name": "Mikey"
}, {
"@id": "ex:agents/lynn",
"@type": "Agent",
"open:agentType": "ex:agentTypes/person",
"schema:name": "Lynn"
}, {
"@id": "ex:agents/openvocab",
"@type": "Agent",
"open:agentType": "ex:agentTypes/group",
"schema:name": "OpenVocab"
}, {
"@id": "ex:relationships/b4dc56a7-2e07-411b-9bb7-794ed6ccb516",
"@type": "Relationship",
"open:relationshipType": "ex:relationshipTypes/mentors",
"open:sourceAgent": "ex:agents/lynn",
"open:targetAgent": "ex:agents/mikey",
"open:contextAgent": "ex:agents/openvocab"
}]
} |
here's a another attempt to model in JSON-LD the relationship of me as a member of Enspiral: {
"@context": {
"open": "http://openvocab.is/#",
"schema": "http://schema.org/"
"ex": "http://holodex.example.com/api/",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"owl": "http://www.w3.org/2002/07/owl#"
},
"@graph": [{
"@id": "ex:agentTypes/agent",
"@type": "AgentType"
}, {
"@id": "ex:agentTypes/person",
"@type": "AgentType"
}, {
"@id": "ex:agentTypes/group",
"@type": "AgentType"
}, {
"@id": "ex:relationshipTypes/is-member-of",
"@type": "RelationshipType",
"schema:name": "is member of",
"open:sourceAgentType": "ex:agentTypes/agent",
"open:targetAgentType": "ex:agentTypes/group",
"rdfs:label": "{source} is member of {target}",
"owl:inverseOf": "ex:relationshipTypes/has-member"
}, {
"@id": "ex:relationshipTypes/has-member",
"@type": "RelationshipType",
"schema:name": "has member",
"open:sourceAgentType": "ex:agentTypes/group",
"open:targetAgentType": "ex:agentTypes/agent",
"rdfs:label": "{source} has member {target}",
"owl:inverseOf": "ex:relationshipTypes/is-member-of"
}, {
"@id": "ex:agents/mikey",
"@type": "Agent",
"open:agentType": "ex:agentTypes/person",
"schema:name": "Mikey"
}, {
"@id": "ex:agents/enspiral",
"@type": "Agent",
"open:agentType": "ex:agentTypes/group",
"schema:name": "Enspiral"
}, {
"@id": "ex:relationships/8604bd82-a4b7-4aba-ba16-3c4917e7df48",
"@type": "Relationship",
"open:relationshipType": "ex:relationshipTypes/is-member-of",
"open:sourceAgent": "ex:agents/mikey",
"open:targetAgent": "ex:agents/enspiral"
}]
} |
thanks @ahdinosaur! what do you think about {
"@context": {
"open": "http://openvocab.is/#",
"schema": "http://schema.org/",
"as": "http://www.w3.org/ns/activitystreams",
"foaf": "http://xmlns.com/foaf/0.1/",
"ex": "http://holodex.example.com/api/",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"owl": "http://www.w3.org/2002/07/owl#",
"rdfs:label": { "@container": "@language" },
"open:labelTemplate": { "@container": "@language" }
},
"@graph": [{
"@id": "open:mentor",
"@type": "rdf:Property",
"rdfs:label": {
"en": "mentors",
},
"open:labelTemplate": {
"en": "{subject} mentors {object}",
},
"owl:inverseOf": {
"rdfs:label": {
"en": "is mentored by",
},
"open:labelTemplate": {
"en": "{subject} is mentored by {object}"
}
}
}, {
"@id": "schema:member",
"@type": "rdf:Property",
"rdfs:label": {
"en": "has member",
},
"open:labelTemplate": {
"en": "{subject} has member {object}",
},
"owl:inverseOf": {
"rdfs:label": {
"en": "is member of",
},
"open:labelTemplate": {
"en": "{subject} is member of {object}"
}
}
}, {
"@id": "ex:agents/mikey",
"@type": ["foaf:Person", "foaf:Agent"],
"schema:name": "Mikey"
}, {
"@id": "ex:agents/lynn",
"@type": ["foaf:Person", "foaf:Agent"],
"schema:name": "Lynn"
}, {
"@id": "ex:agents/openvocab",
"@type": ["foaf:Group", "foaf:Agent"],
"schema:name": "OpenVocab"
}, {
"@id": "ex:agents/enspiral",
"@type": ["foaf:Group", "foaf:Agent"],
"schema:name": "Enspiral"
}, {
"@id": "ex:relationships/b4dc56a7-2e07-411b-9bb7-794ed6ccb516",
"@type": "as:Relationship",
"as:relationship": "open:mentor",
"as:subject": "ex:agents/lynn",
"as:object": "ex:agents/mikey",
"open:relationshipContext": "ex:agents/openvocab"
}, {
"@id": "ex:relationships/8604bd82-a4b7-4aba-ba16-3c4917e7df48",
"@type": "as:Relationship",
"as:relationship": "schema:member",
"as:subject": "ex:agents/enspiral",
"as:object": "ex:agents/mikey"
} ]
} reason for using blank nodes and not giving URI for reverse/inverse properties: |
nice work @elf-pavlik. 😄 it's good to know that our logical model is such that we'd easily be able to translate to that format if we want to output data compatible with these LOD specs. thanks heaps for your help with this, i'd have no idea how to interface with these LOD specs. i notice the change back to use
so the translation might lose some information but that's fine. that being said using |
@ahdinosaur we had discussion with @fosterlynn that one can define in very flexible way (eg. via CMS style interface) new instances of rdfs:Class and rdf:Property. I see impression of needing to 'restrict' to existing established vocabularies as misunderstanding of how Linked Data works. No one stops you from using {
"@id": "ex:agents/openvocab",
"@type": [
"foaf:Group",
"foaf:Agent",
"ex:agentTypes/group",
"ex:snowflakeTypes/486739ba-c497-4aff-8c55-509322d07ce0"],
"schema:name": "OpenVocab"
} |
@elf-pavlik ah sweet. is it possible for you to give an example |
@ahdinosaur you can start by simply assigning for each property and class a HTTP URI in namespace which you control. Even if you to get started just respond with HTTP 404 it doesn't matter, you can use those terms in your data already! {
"@context": {
"ex": "http://circus.example/ns/"
},
"@graph": [
{
"@id": "ex:roles/juggler"
},
{
"@id": "ex:relationships/impersonate"
}
]
} Later you can provide HTML(+RDFa) / JSON-LD / Turtle etc. definitions with some more useful information. {
"@context": {
"ex": "http://circus.example/ns/",
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"owl": "http://www.w3.org/2002/07/owl#",
"foaf": "http://xmlns.com/foaf/0.1/",
"rdfs:label": { "@container": "@language" }
},
"@graph": [
{
"@id": "ex:roles/juggler",
"@type": "rdfs:Class",
"rdfs:subClassOf": "foaf:Agent",
"rdfs:label": {
"en": "Juggler"
},
},
{
"@id": "ex:relationships/impersonate",
"@type": "rdf:Propery",
"rdfs:label": {
"en": "impersonates"
},
"owl:inverseOf": {
"rdfs:label": {
"en": "impersonated by"
}
}
}
]
} But once again YOU DO NOT NEED IT just to start using classes and properties uniquely identified by those URIs in your data! We don't deal with Object Oriented Programming classes and properties here + preferably we keep in mind https://en.wikipedia.org/wiki/Open-world_assumption |
@elf-pavlik makes sense, |
@elf-pavlik @ahdinosaur Great discussion, thanks to both of you for getting really concrete on this!! 😄 |
per - #11 (comment) - #11 (comment) - #15
per - #11 (comment) - #11 (comment) - #15
@elf-pavlik @ahdinosaur I'm doing research on how other vocabs handle agent relationships. I'm now leaning towards separating the directions, based on getting more of a feel for how it tends to be done. And, I think you guys lean that way too so also happy to move toward agreement! I think this would apply to the "relationship type" and the relationship. The relationship would be how elf has suggested, just reverse the subject and object and use the inverse relationship type. Some nice examples: A note: Some relationships define their inverse (Mikey's old obverse - now renamed - relationship on his diagram). Some relationships say they are symmetrical. Maybe this would be hard to implement for user defined? Or maybe not, like in NRP if the label and inverse label are the same, it is symmetrical. |
maybe if the relationship type is symmetrical then |
I have impression that we mix class definition with instances and reified statements (which we can further qualify) For different types(?) of relationships we define as an instance of rdf:Property (eg. role:member) which we can use as label for an edge. Such labeled edge (~ instance of 'direction relationship', labeled with instance of rdf:Property) we can reify and use as value of relationship (let's rename it to 'property' to avoid even more confusions #46 ? ) when we want to qualify this particular edge and make it an instance of (Qualified)Relationship. We can use owl:inverseOf to formalize that two instances of rdf:Property act as inverse relationships e.g. {
"@context": [
"https://w3id.org/valueflows/",
{ "org": "http://www.w3.org/ns/org#" }
],
"@id": "org:isMemberOf",
"owl:inverseOf": "org:hasMember"
} But the obverse property, to my understanding addresses #7 and links two instances of (Qualified)Relationships. In most likely same way as mirror label used in this diagram please compare with use of owl:inverseOf in this one In short, we can use owl:inverseOf to formalize for example role:friend as symmetric relationship. But we would use proposed oberese or mirror to link to independently published statements, where in each a person expresses having relationship of type (property) friend with the other. Same with groups, I gave example here of using owl:inverseOf in cases where vocab defines two separate directions sharing exactly same semantics. But an organization and a person will publish independently #7 two statements where in each one of the sides expresses having such relationship with the other side. |
@elf-pavlik so to recap my understanding: you think we should have two separate properties:
and the reason for separating these is:
? i suppose that makes sense. i've been using the same property (obverse, inverse, reverse, ...) for both relationship type (class) or instance, since i like to reduce the number of concepts in my mind and whether it's a relationship type (class) or instance doesn't seem to change the general concept of it being the inverse, although maybe it does. |
formal definition of owl:inverseOf (in turtle syntax copied from http://www.w3.org/2002/07/owl.ttl ) owl:inverseOf a rdf:Property ;
rdfs:label "inverseOf" ;
rdfs:comment "The property that determines that two given properties are inverse." ;
rdfs:domain owl:ObjectProperty ;
rdfs:isDefinedBy <http://www.w3.org/2002/07/owl#> ;
rdfs:range owl:ObjectProperty . If one uses it on an instance of vf:Relationship, that would imply (when running RDFS reasoner which can infer based on rdfs:domain) that it's also an instance of owl:ObjectProperty (itself rdfs:subClassOf rdf:Property as defined in same .ttl file), which I don't think we intend. To make statements about relation(ship) between two instances of vf:Relationship (or vf:QualifiedRelation to avoid overloading relationship term). We need to define (or find already defined elsewhere) different instance of rdf:Propery - vf:mirror or vf:obverse or vf:sameStatementButMadeByAnotherParty/vf:equivalentStatementButMadeByAnotherParty (same/equivalent depending on resolution of valueflows/valueflows#52) ...
I think we will need to keep discussing those issues, as well as continue our conversation about mixing types with instances. I believe best if we do it based on .... concrete, real world examples, which we can illustrate in non ambiguous way with colorful drawings of directed labeled graphs and serialize in machine readable way as JSON-LD |
Actually, I didn't get that out of it, @ahdinosaur , although you may well be right! I got that mirror would handle the situation of different assertions of something, which may or may not match - the old multiple sources of truth thing. @elf-pavlik you'll have to clarify for us. IF it is the multiple sources of truth, I'd suggest we leave that out for now. I think it can be added on later without disruption to the vocab, is that true? If it is not the multiple sources of truth, and nobody is suggestion handling multiple sources of truth, then please disregard this comment! |
I think @ahdinosaur understood clearly what I tried to explain
Yeah, we can wait with that a bit. I will just add to data I publish relation from me to enspiral network as role:boss, this will give us chance to look at how apps could at some point weed out such one sided claims. |
@elf-pavlik role:boss, why not? Somebody's gotta do it..... Seriously though, I don't get the "role:" thing. I get it in the agent - resource relationship (conceptually more the right word), but not here really. Is that related to the list of roles you defined? (Can't find the link, maybe in w3id?) |
@fosterlynn I just used it as playful example of someone stating nonsense, and while we integrate data from multiple sources from all over the web, we will need a way to automatically verify such claims. At the same time I agree that we better focus on other things first... (BTW second link on http://prefix.cc/role ) |
dense article by ssb folks: "Using Reputation Systems to Create Shared Function-critical Datastructures in Open Networks" |
We have moved the ValueFlows organization from GitHub to https://lab.allmende.io/valueflows. This issue has been closed here, and all further discussion on this issue can be done at If you have not done so, you are very welcome to register at https://lab.allmende.io and join the ValueFlows organization there. |
In issue #9 we discussed the obverse relationship and obverse relationship type, see that for the history of this discussion. I'm starting a new issue so we can continue to discuss while finalizing the minimum core Agent model and JSON-LD recommendations.
My concern: It really is only one relationship in many cases. Perhaps Friend is an exception? But in all the use cases we are dealing with in a value network, both have to agree for the relationship to exist, and the relationship is merely recorded. Activities could be recorded if wanted, such as Request to Join and Request Approved, or something like that. Or if it is a question of verification, some type of credentials could be added to the model to verify from both direction. But these things would relate to the relationship, not be a reverse direction relationship.
@ahdinosaur Thoughts?
The text was updated successfully, but these errors were encountered: