允许一个分类拥有多个父级,是否有意义?还有其他选择吗?

12

简短问题:如何管理出现在多个类别下的产品类别?这样做是不好的做法吗?

背景信息: 我们有一个类别如下的产品数据库:

Products

  -Arts and Crafts Supplies
    -Glue
    -Paper Clips
    -Construction Paper


  -Office Supplies
    -Glue
    -Paper Clips
请注意,胶水和纸夹被分配到两个不同的类别中。虽然它们出现在此类别树的不同位置,但它们在数据库中具有相同的类别ID。为什么?原因有两个:
  1. 类别被分配属性 - 例如,纸夹可以有重量、材料、颜色等属性。
  2. 分配给胶水类别的产品显示在艺术和工艺品以及办公用品下。这是可以预期的 - 它们实际上是数据库中相同的类别ID。

这使我们能够管理单个类别及其属性和分配的产品,但将其放置在类别树中的多个位置。

我们使用嵌套集模型,因此我们用于支持此模型的数据库结构如下:

Category
----------
CategoryID
CategoryName


CategoryTree
------------
CategoryTreeID
CategoryID
Lft
Rgt

因为在类别树中可以有同一类别的多个实例,所以Category和CategoryTree之间存在1:M关系。

是否有一种更简单的建模方式,允许产品类别显示在多个类别下?

4个回答

5
只要所有胶水都适用于办公用品和手工制作用品,我认为这没有任何问题。

如果不是呢?就像儿童胶棒一样,只用于艺术和手工活动。那么你真的需要创建一个单独的类别,同意吗?有什么建议吗?我很难想象每个类别中的产品都适用于两个位置的情况。我甚至不确定这种情况是否存在。 - Cory House
1
根据您的模型,是的,您需要创建一个单独的类别。我想您有两个选择,要么将显示分类与分类分类分开(使用另一个属性),要么使您的类别树成为从根到叶子的不同路径,然后将产品与这些树相关联。(尽管我还没有完全考虑过它的可扩展性) - Jacob G
Jacob,回复Cory之前我应该先看你的答案,因为你涵盖了很多相同的内容,而且通常更经济实惠。 - Steven Sudit

3
你的做法很好,但为什么不像这样简化第二个表格:

类别

ID 名称

子类别

ID 类别ID 子类别ID

尽管如此,在未来,我建议你注意不要在两个根类别之间共享子类别。有时为了一致性,更容易管理,也更容易为客户导航,最好为产品创建独特的分类。否则,如果你从办公用品进入胶水页面,那么你是否也要显示其他路径呢?如果不是,你将会拥有两个完全相同的页面,除了路径不同,这对SEO来说是一个问题。如果是,用户可能会感到困惑。

非常好的观点,eulerfx。我们正面临这个问题,这也是我提出这个问题的众多原因之一。 - Cory House
@eulerfx,你能否详细说明一下在网页层级结构中,除了父级不同之外,两个内容完全相同的页面会如何导致SEO问题? - Steven Sudit
我刚注意到你的子类别表建议描述了邻接模型。虽然我同意这是一个更简单的结构,最初理解起来并且使插入和更新变得容易,但嵌套集模型在选择方面的性能要优于它 - 在产品类别结构上,这占我们流量的99%以上。此外,查询嵌套集更简单。邻接模型需要为树中每个级别进行连接,在大型树上变得难以控制。 - Cory House
MS SQL Server有CTE,它允许有效的递归,我知道Oracle至少有同样强大的东西,所以不要因为可能存在性能问题而放弃一个好的解决方案。我还想补充一点,在高负载网站上显示目录是一个原型案例,这种情况下缓存网页本身可能是必要的。 - Steven Sudit
好的观点Steven,不过这个应用程序是在MySQL上的,我也不知道有没有等效的递归功能。而且,老实说,相对于邻接模型,我发现查询嵌套集的简单性和可扩展性更具吸引力。 - Cory House
显示剩余3条评论

2
最著名的例子是谷歌邮件,分类就是这样完成的。谷歌以产品的易用性而闻名...
我认为其他词语比“parent”更可取,它实际上只暗示了XToOne关系...
也许你可以说一个“产品”有多个“类别”,所以关系应该是ManyToMany。只有从类别开始显示才能到达产品...
这将突显一个问题:如果您不限制类别数量,并且显示带有子类别等的类别,则可能会得到:
- 一个巨大的类别和产品列表,其中有很多重复项 - 一个很大的深度(可能无法阅读)
有趣的部分是强调问题,然后想象一个对最终用户合适的解决方案。

1

一个类别可能需要有多个父级。但是,无论你在哪个父级下找到一个类别,它的子类别应该保持不变。

我见过真实的系统实现了这种逻辑,并且运行良好。

编辑

回答你的问题,我认为我提出的模型并不像你想象的那么限制。基本上,树的某个分支可以在多个父分支下找到,但无论在哪里找到,它都有相同的子节点。这并不妨碍你从一个分支中挑选一些子节点,并将它们作为另一个分支的子节点。

例如,您可以将胶水类别包括在办公用品和爱好用品两个分类下。如果您在胶水类别下添加了“疯狂胶水(栓剂版)”,它将同时出现在这两个分类下。如果您有一些逻辑上应该分组的物品,但需要按其用途分开,您仍然可以这样做。您可以将黏合剂和糊粘剂放在爱好粘合剂类别下,该类别属于爱好根目录,但不属于办公根目录。或者您可以这样做,并同时拥有一个由您的买家内部使用的组合类别。您不能忘记在将新类型的胶水添加到业务模型本体中所属的所有相关类别中。

简而言之,这种限制对您的损失很小,但可以获得一些结构,以帮助避免必须单独管理每个项目的问题。

编辑

假设我已经为模型本身提出了令人信服的论点,那么还存在实施问题。有很多选择,但以下是一种方法:

有一个CatalogItem表,包含一个合成主键、标签、可选的描述/详细文本和一个可选的SKU(或等效物)。然后你有一个多对多的CatalogItemJoin,具有子ID和父ID,两边都受到CatalogItemTable的限制。

作为父项出现的项目是一个类别,因此它不应该有SKU。只作为子项出现的项目是产品,因此它应该有SKU。任何项目都可以有多个父项;这意味着它在多个类别中。同样,每个父项可以有多个子项;这将是一个类别中有几个产品的典型情况。然而,给定一个类别的ID,它的子项将是相同的,无论哪个父类别带你到那里。另一个限制是要避免循环。


谢谢Steven - 你能解释一下为什么子类别应该保持不变吗?在我的例子中,结构并不需要它。把建筑纸放在办公用品下也没有意义。因此,解决方案是将产品分配到类别树中的一个位置,而不是类别ID,这会增加管理工作量,因为我必须将产品分配给树中两个胶类别的实例,但提供了更多的灵活性。 - Cory House
Cory,我添加了一个部分来尝试回答你的问题。它有用吗? - Steven Sudit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接