【问题标题】:Relational databse design to represent similarity between rows of same table关系数据库设计以表示同一表的行之间的相似性
【发布时间】:2020-03-16 21:29:35
【问题描述】:

出于背景目的:我将 PostgreSQL 与 SQLAlchemy (Python) 结合使用。

给定一个独特的references 表:

references_table
-----------------------
  id | reference_code
-----------------------
   1 | CODEABCD1
   2 | CODEABCD2
   3 | CODEWXYZ9
   4 | CODEPOIU0
...

在典型情况下,我会有一个单独的items 表:

items_table
-----------------------
  id | item_descr
-----------------------
   1 | `Some item A`
   2 | `Some item B`
   3 | `Some item C`
   4 | `Some item D`
...

在这种典型场景中,referencesitems 之间的多对多关系设置在联结表中:

references_to_items
-----------------------
  ref_id (FK) | item_id (FK)
-----------------------
   1          | 4
   2          | 1
   3          | 2
   4          | 1
...

在这种情况下,很容易建模并获取与同一项目关联的所有引用,例如,项目 1 具有上表中的引用 2 和 4。

但是,在我的场景中,没有 items_table。但我仍然想模拟一些参考引用相同(未表示的)项目的事实。

我看到了通过这样的多对多联结表(关联 references 表的 FK)来建模的可能性:

reference_similarities
-----------------------
  ref_id (FK) | ref_id_similar (FK)
-----------------------
   2          | 4
   2          | 8
   2          | 9
...

对于我的数据模型而言,ID 为 2、4、8 和 9 的引用将被视为“相似”。

但是,这里的不便之处在于,此类模型需要选择一个引用(在 id=2 之上)作为“枢轴”,而在reference_similarities 表中可以将多个其他引用声明为“相似”。参考 2 类似于 4,参考 2 类似于 8 ==> 因此 4 类似于 8。

所以问题是:有没有更好的设计不涉及上面的“枢轴”FK?

理想情况下,我会将“相似性”存储为 FK 数组,如下所示:

reference_similarities
------------------------
id  |  ref_ids (Array of FKs)
------------------------
  1 | [2, 4, 8, 9]
  2 | [1, 3, 5]

..但我从https://dba.stackexchange.com/questions/60132/foreign-key-constraint-on-array-member 了解到,目前不可能拥有foreign keys in PostgreSQL arrays。所以我试图为这个模型找出一个更好的设计。

【问题讨论】:

    标签: postgresql database-design sqlalchemy junction-table


    【解决方案1】:

    我可以理解您希望将项目分组到一个集合中,并且能够从其中的任何项目中查询该集合。

    您可以使用散列函数对集合进行散列,然后将散列用作枢轴值。 例如你有一组值(2,4,8,9),它会像这样被散列:

    哈希 = ((((31*1 + 2)*31 + 4)*31 + 8)*31 + 9

    您可以参考 Java 中的 Arrays.hashCode 以了解如何对值列表进行哈希处理。

            int result = 1;
    
            for (Object element : a)
                result = 31 * result + (element == null ? 0 : element.hashCode());
    

    表参考_相似度:

    reference_similarities
    -----------------------
      ref_id (FK) | hash_value
    -----------------------
       2          | hash(2, 4, 8, 9) = 987204
       4          | 987204
       8          | 987204
       9          | 987204
    

    要查询集合,可以先从ref_id查询hash_value,再从hash_value中获取所有的ref_id。

    此解决方案的缺点是每次向集合添加新值时,都必须重新散列集合。

    另一种解决方案是您可以在 Python 中编写一个函数,以便在创建新集合时生成唯一的 hash_value。

    【讨论】:

    • 有趣的解决方案!在接下来的几天里,我将尝试在 Python 中实现它,看看它是如何工作的(对于“散列”,我正在考虑在有序列表的 repr 上使用 Base64)。这种结构的替代方法是使用带有 ID 数组的 reference_similarities 表(不是 FK,因为不支持)[实际上我认为该数组甚至不是必需的],而不是具有哈希值,将references_similaritiesid 作为FK 插入references_table
    猜你喜欢
    • 2023-04-08
    • 2013-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-08
    • 1970-01-01
    相关资源
    最近更新 更多