使用图表对家庭关系建模

Modeling family relationships using a graph

我正在尝试将家庭关系建模为图表,以便我可以查询它们以查找关联关系和其他关系。这是为了练习,所以我不能使用现有的解决方案,如图形数据库等。

我正在尝试对类似这样的模型进行建模,其中相关对象之间存在边缘 entities(Person) 表示关系。

我就是这样开始的。

public class Person
{
    public string Name { get; set; }
    List<IEdge> Children { get; set; }
    IEdge Spouse { get; set; }
    IEdge Father { get; set; }
    IEdge Mother { get; set; }
}

public class Edge
{
    Person From { get; set; }
    Person To { get; set; }
    public string RelationshipType { get; set; }
}
public class Family
{
    Dictionary<string, Person> familyGraph = new Dictionary<string, Person>();
}

邻接表表示将存储在一个键值对中,一个人的所有边将存储在相应的 Person 节点中。

因此添加与此的关系很简单。

现在说到挽回关系,比如找兄弟姐妹,舅舅等等。我有点不得不手动导航边缘以找到适合每种关系的合适人选。对于每段关系,我都必须这样做。

例如,为了找到我的侄女,我必须遍历我妈妈找到我的兄弟姐妹并得到他们的 children,

为了找到我的婆婆。我必须穿越到我妻子那里去找她妈妈。 我在想这就是使用此数据结构的代码的样子

List<string> FindNeice(string username)
{
    currentPerson = GerPerson(username)
    siblings = currentPerson.Mother.Children;
    niece = siblings.Where(mbox => mbox.Gender == "F").SelectMany(m => m.Children);
}

所以这必须存在于每一段关系中。是的,有些可以重复使用,因为 Maternal/Paternal 关系与你和你妻子之间交换的起始人物相同。

我在想是否有更好的方法对此建模以及编写提取关系的更好方法。

家庭关系看似简单,却匆匆变复杂。你提到 in-law 关系(你是岳母),但更亲密的关系也很复杂。以兄弟姐妹为例。技术上:

  • 兄弟姐妹是指与您有同一个生母父亲的人。
  • 一个half-sibling是一个与你有相同生母父亲的人。
  • A step-sibling 是其生母或父亲与您的生母或父亲结婚的人。

甚至不要让我开始收养关系。

但是让我们暂时搁置这些复杂问题并假设一个没有 step-brothers、half-sisters 等的世界:一个简单的家谱。

对此进行建模的最灵活的方法是创建一个 Person 记录,其中包含有关此人的信息,但不包含任何关系的信息。例如,该信息可以是姓名、出生日期等。而且那个人有一个永远不会改变的唯一标识符。比方说,一个 64 位数字。您有 table 条 Person 条记录。

您还有 table 条 Relationship 条记录。每条记录都包含源、目标和关系类型。有两种类型的关系:Parent 和配偶。

(我故意将性别关系排除在这个简单的例子之外,因为包括它会增加不必要的复杂性,而当前关于性别认同的社会讨论使它变得更加复杂。)

因此,如果您的直系亲属包括您 (George)、您的 parent 夫妇(Mary 和 Dave)以及您的两个兄弟姐妹(Bob 和 Sally),则关系为:

Mary, George, Parent
Dave, George, Parent
Mary, Bob, Parent
Dave, Bob, Parent
Mary, Sally, Parent
Dave, Sally, Parent
Mary, Dave, Spouse
Dave, Mary, Spouse

读作 "Mary is George's Parent."

请注意,关于是否最好包括相互的配偶关系存在一些争论。我将它们包括在这里是因为这样更容易推理。

所以如果你想找到一个人的兄弟姐妹,你这样做:

  1. 查询关系 table 以查找该人 ID 为目标的所有关系,以及关系类型 Parent。这会为您提供此人的 parent 标识符列表。
  2. 查询关系 table 以获得其中 parent 的标识符之一是来源且关系类型为 parent 的所有关系。这为您提供了所有 parent 的 children 的列表。该列表将包括原始人,以及所有 parent 的 children:根据定义,原始人的兄弟姐妹。

然后您可以选择是要为更复杂的关系编写代码,还是为这些关系开发简单的 script-like 定义。考虑:

parents - intrinsic function
children - intrinsic function
spouse - intrinsic function
siblings - (parents children) (probably should be an intrinsic, to eliminate self)
grandparents - (parents parents)
uncles/aunts - (parents siblings)
cousins - (parents siblings children)
parents-in-law - (spouse parents)
siblings-in-law - (spouse siblings)
nieces/nephews - (siblings children) + (siblings-in-law children)

鉴于 parent/child 和 spouse/spouse 关系,您可以轻松编写查询脚本以查找任何其他类型的家庭关系。编写执行这些查询的代码非常简单,如果您尝试 hand-code 它们,您将消除所有可能遇到的问题。

编码变成了编写四个内部函数(ParentsChildrenSiblingsSpouse)的问题,每个函数都接受一个参数一个 IEnumerable<PersonId> 和 returns 一个 IEnumerable<PersonId>,然后组合这些函数。 Siblings 函数必须从结果中排除输入参数中的任何值。考辛斯成为:

var person = new List<PersonId> {personId};
var cousins = person.Parents().Siblings().Children();

编写代码以根据我描述的简单查询定义生成这些查询并不十分困难。或者,如果您更愿意使用静态关系,则可以为每个关系编写单独的函数。

现在,如果您想将其扩展到 step-siblings、half-siblings 等,您可以保持相同的基本关系并添加更多信息,例如关系 sub-type。您仍然会查询基本的 parent/child 关系,但如果需要,可以过滤掉 "steps" 和 "halfs" 或其他 sub-type。对于性别关系,只需在 Person 记录中添加性别。对于姐妹,查询兄弟姐妹并过滤结果以仅包含女性。

现在,如果您想扩展您的查询定义以包括性别,它会变成这样:

brother - (siblings male)
grandmother - (parents parents female)
maternal-uncle - (parents female siblings male)
spouse-step-sister - (spouse siblings step female)