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
How to handle relationships between agents? #12
Comments
@fosterlynn could you please provide two concrete examples in which you use this pattern? |
Agents: Enspiral, Mikey, Loomio AgentRelationships: If you would like them detailed out more in terms of properties, let me know.... or any other questions, just yell! |
{
"@context": [
"http://schema.org",
{ "superOrganization": { "@reverse": "subOrganization" } }
],
"@graph": [
{
"@id": "https://enspiral.com/",
"@type": "Organization",
"name": "Enspiral",
"member": [
"https://www.loomio.org/u/g48DQjS5/mikey-the-human"
],
"subOrganization": [
"http://loomio.org"
]
},
{
"@id": "https://www.loomio.org/u/g48DQjS5/mikey-the-human",
"@type": "Person",
"name": "Mikey",
"memberOf": [
"https://enspiral.com",
"https://loomio.org"
]
},
{
"@id": "https://loomio.org",
"@type": "Organization",
"name": "Loomio",
"member": [
"https://www.loomio.org/u/g48DQjS5/mikey-the-human"
],
"superOrganization": [
{ "@id": "https://enspiral.com" }
]
}
]
} same on JSON-LD playground: http://tinyurl.com/nofsrlc |
@elf-pavlik thanks! Another one (to use an example where people want to define their own relationships). (Don't worry about defining this one out, just for discussion's sake.) Agents: Driftless Herbal Network, Jane, Canyon Farm |
@elf-pavlik hehe, awesome! 🌷 in our case, we want more than just who is a member, we want information about the membership itself: when the person joined, whether they are active or not, what type of membership they have (member vs contributor). plus, we also have more relationships than just memberships, most exciting at the moment is our stewardship relationships (which is a great way we've learned to do networked human resources where each person in the group is a point of contact for another person in the group and meets with them once a month to check in about their life, see this and this for more info), which as @fosterlynn mentioned is not only between two people but also is only within the context of a group. here's the data so far in our "Enspiral directory": https://github.com/holodex/app/tree/master/data. an example API resource is up at http://holodex.enspiral.info/api/groups/enspiral-craftworks. this is all a work in progress (super pre-alpha), so missing a lot, but i hope it's helpful and i'd be happy to explain anything that is confusing or you want to know more about. 😋 |
@ahdinosaur super interesting, I love that you're working on this in a real situation! Now that I've seen the data, I understand more what you meant by keeping the ends of the relationships separate. It is actually more like having an entry for each direction of a relationship type. Does it have to do with an agent only having the basis to refer to the relationship from its perspective? |
@fosterlynn i'm glad being able to see the data is helpful. (hacked up YAML database for the win 🐱). yup, you got it. the purpose is for each agent to be in control of their own data and that means they must control their perspective of the relationship, which leads to some nice properties:
an open question is about conflicting meta-information ("the group says you joined at this time, but you say you joined at this other time"), but i reckon life is relative so why not our data. anyways, it's an experiment. 🔬 |
for distributed scenario, please check out my recent email to Credentials CG list @ahdinosaur @fosterlynn please also check out two videos embedded on http://opencreds.org/ I'll check your Enspiral examples and reply with some Role examples tomorrow! |
thanks @elf-pavlik 😸 |
as a cleaned up example, here's what we have right now: {
"@graph": [
{
"@id": "http://holodex.enspiral.info/api/groups/enspiral-craftworks",
"@type": "Group",
"name": "Enspiral Craftworks",
"image": "http://i.imgur.com/BFmaOxi.png",
"relationships": [
{
"@id": "http://holodex.enspiral.info/api/relationships/enspiral-craftworks-group-simon"
},
{
"@id": "http://holodex.enspiral.info/api/relationships/enspiral-craftworks-group-mikey"
}
]
},
{
"@type": "Person",
"name": "Mikey",
"handle": "ahdinosaur",
"url": "http://dinosaur.is",
"image": "http://gravatar.com/avatar/22ee24b84d0a2a9446fc9c0fe0652c46?s=512&d=identicon",
"relationships": [
{
"@id": "http://holodex.enspiral.info/api/relationships/mikey-member-enspiral-craftworks"
},
{
"@id": "http://holodex.enspiral.info/api/relationships/mikey-mentor-simon"
}
],
"@id": "http://holodex.enspiral.info/api/people/mikey"
},
{
"@type": "Person",
"name": "Simon",
"handle": "simontegg",
"image": "https://avatars0.githubusercontent.com/u/1574732?v=2&s=460",
"relationships": [
{
"@id": "http://holodex.enspiral.info/api/relationships/simon-member-enspiral-craftworks"
},
{
"@id": "http://holodex.enspiral.info/api/relationships/simon-mentee-mikey"
}
],
"@id": "http://holodex.enspiral.info/api/people/simon"
},
{
"@type": "Relationship",
"relationshipType": {
"@id": "http://holodex.enspiral.info/api/relationshipTypes/group"
},
"is": {
"@id": "http://holodex.enspiral.info/api/groups/enspiral-craftworks"
},
"has": {
"@id": "http://holodex.enspiral.info/api/people/simon"
},
"symmetric": {
"@id": "http://holodex.enspiral.info/api/relationships/simon-member-enspiral-craftworks"
},
"@id": "http://holodex.enspiral.info/api/relationships/enspiral-craftworks-group-simon"
},
{
"@type": "Relationship",
"relationshipType": {
"@id": "http://holodex.enspiral.info/api/relationshipTypes/group"
},
"is": {
"@id": "http://holodex.enspiral.info/api/groups/enspiral-craftworks"
},
"has": {
"@id": "http://holodex.enspiral.info/api/people/mikey"
},
"symmetric": {
"@id": "http://holodex.enspiral.info/api/relationships/mikey-member-enspiral-craftworks"
},
"@id": "http://holodex.enspiral.info/api/relationships/enspiral-craftworks-group-mikey"
},
{
"@type": "Relationship",
"relationshipType": {
"@id": "http://holodex.enspiral.info/api/relationshipTypes/member"
},
"is": {
"@id": "http://holodex.enspiral.info/api/people/simon"
},
"has": {
"@id": "http://holodex.enspiral.info/api/groups/enspiral-craftworks"
},
"symmetric": {
"@id": "http://holodex.enspiral.info/api/relationships/enspiral-craftworks-group-simon"
},
"@id": "http://holodex.enspiral.info/api/relationships/simon-member-enspiral-craftworks"
},
{
"@type": "Relationship",
"relationshipType": {
"@id": "http://holodex.enspiral.info/api/relationshipTypes/member"
},
"is": {
"@id": "http://holodex.enspiral.info/api/people/mikey"
},
"has": {
"@id": "http://holodex.enspiral.info/api/groups/enspiral-craftworks"
},
"symmetric": {
"@id": "http://holodex.enspiral.info/api/relationships/enspiral-craftworks-group-mikey"
},
"@id": "http://holodex.enspiral.info/api/relationships/mikey-member-enspiral-craftworks"
},
{
"@type": "Relationship",
"relationshipType": {
"@id": "http://holodex.enspiral.info/api/relationshipTypes/mentee"
},
"is": {
"@id": "http://holodex.enspiral.info/api/people/simon"
},
"has": {
"@id": "http://holodex.enspiral.info/api/people/mikey"
},
"symmetric": {
"@id": "http://holodex.enspiral.info/api/relationships/mikey-mentor-simon"
},
"context": {
"@id": "http://holodex.enspiral.info/api/groups/enspiral-craftworks"
},
"@id": "http://holodex.enspiral.info/api/relationships/simon-mentee-mikey"
},
{
"@type": "Relationship",
"relationshipType": {
"@id": "http://holodex.enspiral.info/api/relationshipTypes/mentor"
},
"is": {
"@id": "http://holodex.enspiral.info/api/people/mikey"
},
"has": {
"@id": "http://holodex.enspiral.info/api/people/simon"
},
"symmetric": {
"@id": "http://holodex.enspiral.info/api/relationships/simon-mentee-mikey"
},
"context": {
"@id": "http://holodex.enspiral.info/api/groups/enspiral-craftworks"
},
"@id": "http://holodex.enspiral.info/api/relationships/mikey-mentor-simon"
},
{
"@type": "RelationshipType",
"name": "group",
"pluralName": "groups",
"description": "A group has constituent members",
"label": "is group of",
"inverseLabel": "has group",
"symmetric": {
"@id": "http://holodex.enspiral.info/api/relationshipTypes/member"
},
"@id": "http://holodex.enspiral.info/api/relationshipTypes/group"
},
{
"@type": "RelationshipType",
"name": "member",
"pluralName": "members",
"description": "A member is part of a group",
"label": "is member of",
"inverseLabel": "has member",
"symmetric": {
"@id": "http://holodex.enspiral.info/api/relationshipTypes/group"
},
"@id": "http://holodex.enspiral.info/api/relationshipTypes/member"
},
{
"@type": "RelationshipType",
"name": "mentee",
"pluralName": "mentees",
"description": "A mentee is mentored by a mentor.",
"label": "is mentee of",
"inverseLabel": "has mentee",
"symmetric": {
"@id": "http://holodex.enspiral.info/api/relationshipTypes/mentor"
},
"@id": "http://holodex.enspiral.info/api/relationshipTypes/mentee"
},
{
"@type": "RelationshipType",
"name": "mentor",
"pluralName": "mentors",
"description": "A mentor mentors a mentee.",
"label": "is mentor of",
"inverseLabel": "has mentor",
"symmetric": {
"@id": "http://holodex.enspiral.info/api/relationshipTypes/mentee"
},
"@id": "http://holodex.enspiral.info/api/relationshipTypes/mentor"
}
]
} i'm wondering about how to make these into a more credential-like form. the examples linked to are one authority agent making a claim about another agent, so would each side make a symmetric claim (A says that "A is X of B" and B says that "B is X' of A") or is there only one claim being made with two signatures (both A and B say that "A is X of B")? |
@ahdinosaur let's see - "using schema:Role with inverse properties?" |
See also parallel discussions going on here: |
@elf-pavlik OK, here is my first attempt (very newbie, sorry for syntax errors, etc!) to sketch the context for agent relationships and relationship types. Lots of questions. Some of them how to define something, like values to a code. Lots of questions how to find and decide what vocab to use for existing concepts. @ahdinosaur you'll notice a few changes to what you have in the ovn vocab and holodex, also some additions based on recent discussions. All to be worked out.... Oops, need to add startDate and endDate to AgentRelationship. |
Please take a look at this gist https://gist.github.com/elf-pavlik/029917ccc535e889f693 which we discuss in 1EdTech/openbadges-specification#32 This week I will try to write similar but with MembershipCredential instead of AchievementCredential. Then we can also discuss mutual credentials! EDIT: I suggested such use case here https://lists.w3.org/Archives/Public/public-credentials/2015Apr/0006.html |
@ahdinosaur have you considered @prefix : <http://example.net/ns#>
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
:Relationship a owl:Class .
:relationship a owl:ObjectProperty ;
rdfs:domain foaf:Agent ;
rdfs:range :Relationship .
:Mentorship rdfs:subClassOf :Relationship .
:mentor a owl:ObjectProperty ;
rdfs:label "mentor"@en ;
rdfs:domain [
a owl:Class ;
owl:unionOf ( foaf:Person :Relationship )
] ;
rdfs:range [
a owl:Class ;
owl:unionOf ( foaf:Person :Relationship )
] .
To my understanding linked data best practices discourage plural names for properties (so relationship not relationships) as well as defining inverse properties on vocabulary level. Instead of doing that JSON-LD context would preferably define {
"@context": {
"mentee": { "@reverse": "mentor", "@type": "@id" }
}
} www.w3.org/TR/json-ld/#reverse-properties {
"@context": { ... },
"@id": "http://holodex.enspiral.info/api/relationships/mikey-mentor-simon",
"@type": "Mentorship",
"mentor": "http://holodex.enspiral.info/api/people/simon",
"mentee": "http://holodex.enspiral.info/api/people/mikey",
"context": "http://holodex.enspiral.info/api/groups/enspiral-craftworks",
"sameAs": "http://holodex.enspiral.info/api/relationships/simon-mentee-mikey"
} but you can also use mentor/mentee as not Qualified Relaton {
"@context": { ... },
"@id": "http://holodex.enspiral.info/api/people/mikey",
"@type": "Person",
"name": "Mikey",
"mentor": "http://holodex.enspiral.info/api/people/simon",
} {
"@context": { ... },
"@id": "http://holodex.enspiral.info/api/people/simon",
"@type": "Person",
"name": "Simon",
"mentee": "http://holodex.enspiral.info/api/people/mikey",
} |
@elf-pavlik thanks for the resources. 😸 i'm gonna need some time to chew on what you've shared and also give an update on our current data structure for holodex. |
@ahdinosaur maybe you could setup http://linkeddatafragments.org/software/ (server + client) so that we always test data you model with some real world queries! |
@elf-pavlik Question: It looks like both of your examples (subclass and like a property) imply that the relationship types (e.g. mentor) have to be defined somewhere in the vocabulary itself. Does this preclude or make it harder to allow user definition of relationship types? Or can people just throw them out there as needed? Any issues with collision of same named relationship types if so? |
@fosterlynn nothing requires that terms used for example as owl:Class, owl:ObjectProperty or owl:DataProperty come from a static vocabulary. One can publish them using some dynamic CMS like system and it will work just fine. When it comes to name collisions, everything has its own namespace. Already you can find examples where foaf:name doesn't have exactly the same definition as schema:name. On the other side, Linked Data comes handy when you want to integrate data from multiple sources. In such case it can come handy if people reuse existing terms instead recreating new ones for the same concepts. Of course you can map them with constructs like rdfs:subclassOf, owl:equivalentClass, rdfs:subPropertyOf, owl:equivalentProperty but then you need to use reasoning (inference) which may raise a bar in possibly quite significant way. |
@fosterlynn @ahdinosaur please also publish context you work on directly on github and test them on http://json-ld.org/playground/ using http://rawgit.com/ proxy for links (to avoid CORS issues) e.g. http://tinyurl.com/me47rs8 (both context and data served directly from github repos via rawgit!) |
Please notice recent addition to Activity Streams 2.0 Vocabulary |
This is continuing the discussion today (2015-01-28) in the PLP hangout. @elf-pavlik provided these links:
http://patterns.dataincubator.org/book/qualified-relation.html
http://blog.schema.org/2014/06/introducing-role.html
Yes, these are both to the point, exactly.
In our object model in NRP which we were mostly using as starting point for openvocab, we have Agent, AgentRelationship, and AgentRelationshipRole. When we say Agent, we mean the superclass of Person or Organization. In no particular notation:
AgentRelationshipRole:
identifier = text
name = text
plural_name = text
association_behavior = child, member, customer, and some others....
description = text
label = text
inverse_label = text
AgentRelationship:
"An association between 2 agents, defining a role in relationship to each other."
is_associate = reference to an Agent
has_associate = reference to an Agent
relationship_type = reference to an AgentRelationshipRole
description = text
state = active, potential, inactive (and/or could be dates)
At some point @ahdinosaur asked could we put the ends of the relationship on the Agent itself (instead of using the AgentRelationship object). This has been at least partially implemented in openvocab I think. I don't know what might be "standard" for this type of situation in LOD land. I get one problem: If you have a separate class, and the data is distributed, how do you decide where the relationship lives?
Question: What is the best way to represent this concept in LOD? And I suppose, before that, do people agree with including something like this in PLP?
The text was updated successfully, but these errors were encountered: