是否有一种优雅的方式来存储双重关系(即用户 1 和用户 2 是朋友)

Posted

技术标签:

【中文标题】是否有一种优雅的方式来存储双重关系(即用户 1 和用户 2 是朋友)【英文标题】:Is there an elegant way to store a dual relationship (i.e. user 1 and user 2 are friends) 【发布时间】:2012-01-10 19:06:07 【问题描述】:

这个月我在两份不同的工作中遇到了同样的问题:

Version 1: User 1 & User 2 are friends
Version 2: Axis 1 & Axis 2 when graphed should have the quadrants colored...

问题是,我没有看到一种优雅的方式,使用 RDBMS 来存储和查询这些信息。

有两种明显的方法:

方法一:

store the information twice (i.e. two db rows rows per relationship):
u1, u2, true 
u2, u1, true
u..n, u..i, true
u..i, u..n, true

have rules to always look for the inverse on updates: 
on read, no management needed
on create, create inverse
on delete, delete inverse
on update, update inverse

Advantage:    management logic is always the same.
Disadvantage: possibility of race conditions, extra storage (which is admittedly cheap, but feels wrong)

方法二:

store the information once (i.e. one db row per relationship)
u1, u2, true
u..n, u..i, true

have rules to check for corollaries:
on read, if u1, u2 fails, check for u2, u1 
on create u1, u2: check for u2, u1, if it doesn't exist, create u1, u2
on delete, no management needed
on update, optionally redo same check as create

Advantage: Only store once
Disadvantage: Management requires different set of cleanup depending on the operation

我想知道是否有第三种方法可以遵循“使用 f(x,y) 的键,其中 f(x,y) 对于每个 x,y 组合都是唯一的,而 f(x,y) === f(y,x)"

我的直觉告诉我,应该有一些按位运算的组合可以满足这些要求。类似于两列的东西:

key1 = x && y key2 = x + y

我希望那些在数学系花更多时间而在社会学系花更少时间的人已经看到了这种可能性或不可能性的证据,并且可以提供一个快速的“[你这个白痴]它很容易证明(im)possible, see this link"(名字调用可选)

任何其他优雅的方法也将受到欢迎。

谢谢

【问题讨论】:

你不能使用基于图形的数据库吗?例如 Neo4j。这将允许您完全捕获您的图形关系。您还可以使用 Mongo 并将其全部存储在 Json 对象中。 这甚至不是“面向文档”又名“NoSQL”数据库的优雅支持。 @steve 是的,Neo4j 是一个真正的选择(尽管我不是他们许可证的忠实粉丝)。 Neo4j 对此进行了抽象,但他们必须以某种方式解决基本问题。我想知道怎么做。 【参考方案1】:

还有一种方法可以通过添加额外的约束来使用第二种方法。检查u1 < u2:

CREATE TABLE User
( Name VARCHAR(10) NOT NULL
, PRIMARY KEY (Name)
) ;

CREATE TABLE MutualFriendship
( u1 VARCHAR(10) NOT NULL
, u2 VARCHAR(10) NOT NULL
, PRIMARY KEY (u1, u2)
, FOREIGN KEY (u1) 
    REFERENCES User(Name)
, FOREIGN KEY (u2) 
    REFERENCES User(Name)
, CHECK (u1 < u2) 
) ;

读取、创建、插入或更新的规则必须使用(LEAST(u1,u2), GREATEST(u1,u2))

【讨论】:

+1 好答案。检查在 mysql 中不起作用,可以使用 Trigger 代替。 @santiagobasulto:Thnx,这个问题与 DBMS 无关。在 MySQL 中实现起来并不容易(特别是如果一个人不喜欢触发器......) @ypercube 是的!你是对的。我只是提到它。确实,触发器也会变得困难。【参考方案2】:

在 SQL 中,很容易实现约束来支持您的第一种方法:

CREATE TABLE MutualFriendship
(u1 VARCHAR(10) NOT NULL,
 u2 VARCHAR(10) NOT NULL,
 PRIMARY KEY (u1,u2),
 FOREIGN KEY (u2,u1) REFERENCES MutualFriendship (u1,u2));

INSERT INTO MutualFriendship VALUES
('Alice','Bob'),
('Bob','Alice');

【讨论】:

【参考方案3】:

对于任何感兴趣的人,我玩弄了一些按位运算,发现以下似乎满足 f(x,y) 的条件:

#Python, returns 3 tuple
def get_hash(x, y):
  return (x & y, x | y, x * y)

不过,我无法证明。

【讨论】:

如果 x 和 y 是整数(或属于可以完全排序的集合),您可以使用(min(x,y), max(x,y)) @ypercube,你说得对。甚至我上的数学课也应该让我看到这一点。再次感谢。 不过,您的哈希函数提出了一个有趣的数学问题。是否有两个 (x,y) 对具有相同的哈希值?【参考方案4】:

“x 是 y 的朋友”。

定义一个 (x,y) 对的表并强制执行规范形式,例如x

将视图创建为 SELECT x,y FROM FRIENDS UNION SELECT x as y, y as x FROM FRIENDS。

针对基表进行更新(缺点:更新者必须了解强制规范形式),针对视图进行查询。

【讨论】:

【参考方案5】:

您似乎将朋友的数量限制为 1。如果是这种情况,那么我会使用类似的东西 u1,u2 u2,u1 u3,空 u4,u5 u5,u4

u3 没有朋友。

【讨论】:

不,每个 u1、u2 组合都是一行。 n 个用户可以有 n-1 个朋友(如果您没有明确禁止自我交友,则可以有 n 个朋友)

以上是关于是否有一种优雅的方式来存储双重关系(即用户 1 和用户 2 是朋友)的主要内容,如果未能解决你的问题,请参考以下文章

是否有一种可移植的方式来获取 Python 中的当前用户名?

是否有一种无头的方式来导入项目和刷新工作区?

核心数据对象比较

是否有一种优雅的内置方法可以在 R 中进行模索引?

存储用户权限的最佳方式?

是否有一种优雅的方法可以为多租户应用程序克隆具有所有配置(客户端和角色)的 Keycloak 领域?