hackers4peace / plp-docs

Portable Linked Profiles documentation
26 stars 2 forks source link

How to handle relationships between agents? #12

Open fosterlynn opened 9 years ago

fosterlynn commented 9 years ago

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?

elf-pavlik commented 9 years ago

@fosterlynn could you please provide two concrete examples in which you use this pattern?

fosterlynn commented 9 years ago

@elf-pavlik

Agents: Enspiral, Mikey, Loomio AgentRelationshipRoles: Child, Member

AgentRelationships: Loomio is child of Enspiral (also can be stated Enspiral is parent of Loomio) Mikey is member of Enspiral (also can be stated Enspiral has member Mikey)

If you would like them detailed out more in terms of properties, let me know.... or any other questions, just yell!

elf-pavlik commented 9 years ago
{
  "@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

fosterlynn commented 9 years ago

@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 AgentRelationshipRoles: Harvester, Grower, Administrator, Contact AgentRelationships: Canyon Farm is grower for Driftless Herbal Network Jane is harvester for Driftless Herbal Network Jane is administrator for Driftless Herbal Network Jane is contact for Canyon Farm (interestingly, this only is within the context of Driftless Herbal Network, another data point that Mikey identified last week in his work on the Enspiral directory)

ahdinosaur commented 9 years ago

@elf-pavlik hehe, awesome! :tulip:

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. :yum:

fosterlynn commented 9 years ago

@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?

ahdinosaur commented 9 years ago

@fosterlynn i'm glad being able to see the data is helpful. (hacked up YAML database for the win :cat:).

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. :microscope:

elf-pavlik commented 9 years ago

one cannot create a bidirectional relationship without consent from both parties

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!

ahdinosaur commented 9 years ago

thanks @elf-pavlik :smile_cat:

ahdinosaur commented 9 years ago

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")?

elf-pavlik commented 9 years ago

@ahdinosaur let's see - "using schema:Role with inverse properties?" https://lists.w3.org/Archives/Public/public-vocabs/2015Mar/0089.html

fosterlynn commented 9 years ago

See also parallel discussions going on here: https://github.com/openvocab/holodex/issues/1 (roles) https://github.com/openvocab/holodex/issues/2 (types of relationships)

fosterlynn commented 9 years ago

@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....

relationshiptype

agentrelationship

Oops, need to add startDate and endDate to AgentRelationship.

elf-pavlik commented 9 years ago

Please take a look at this gist https://gist.github.com/elf-pavlik/029917ccc535e889f693 which we discuss in https://github.com/openbadges/openbadges-specification/issues/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

elf-pavlik commented 9 years ago

@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",
}
ahdinosaur commented 9 years ago

@elf-pavlik thanks for the resources. :smile_cat: 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.

elf-pavlik commented 9 years ago

@ahdinosaur maybe you could setup http://linkeddatafragments.org/software/ (server + client) so that we always test data you model with some real world queries!

fosterlynn commented 9 years ago

@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?

elf-pavlik commented 9 years ago

@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. BTW please take a look at very recent W3C Social IG ISSUE-4: management of 'living' vocabularies similar to microformats.org and schema.org

elf-pavlik commented 9 years ago

@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!)

elf-pavlik commented 9 years ago

Please notice recent addition to Activity Streams 2.0 Vocabulary