我正在开发一个可以支持线程注释的Web应用程序.我需要能够根据收到的投票数重新安排评论.(与reddit中的线程注释相同)
我很想听听SO社区对如何做到这一点的意见.
我该如何设计评论表?这是我现在使用的结构:
Comment id parent_post parent_comment author points
应该对这个结构做些什么改变?
如何从此表中获取详细信息以正确方式显示它们?(欢迎以任何语言实施.我只想知道如何以最好的方式做到这一点)
在实现此功能时我需要注意哪些事项,以便减少CPU /数据库的负载?
提前致谢.
在数据库中存储树是具有许多不同解决方案的主题.这取决于你是否也要检索子层次结构(所以项目X的所有子项)或者你只想获取整个层次结构集并使用字典以O(n)方式在内存中构建树.
您的表的优势在于您可以通过在父帖上过滤来一次性获取帖子上的所有评论.当你以教科书/天真的方式定义评论的父级时,你必须在内存中构建树(见下文).如果要从数据库中获取树,则需要一种不同的方式来存储树:请参阅我对基于预计算的方法的描述:http://www.llblgen.com/tinyforum/GotoMessage.aspx?MessageID = 17746&ThreadID = 3208 或使用CELKO描述的平衡树:
或另一种方法:http: //www.sqlteam.com/article/more-trees-hierarchies-in-sql
如果你在内存中获取层次结构中的所有内容并在那里构建树,那么由于查询非常简单,它可以更高效:select from from Comment where ParentPost = @id ORDER BY ParentComment ASC
在该查询之后,您只使用1个字典在内存中构建树,该字典跟踪元组CommentID - Comment.现在,您可以浏览结果集并动态构建树:您遇到的每个注释,您都可以在字典中查找其父注释,然后将当前处理的注释也存储在该字典中.
几件事也要考虑...
1)当您根据排名或日期说“类似reddit的排序”时,您是指顶层的还是整体的?
2)删除节点时,分支会发生什么?你重新父母吗?在我的实现中,我认为编辑者将决定-隐藏节点并将其与可见的子项一起显示为“隐藏的注释”,隐藏注释及其子项,或对整个树进行核对。重父母应该很容易(只需将孩子的父母设置为已删除父母的父母),但是涉及整个树的任何事情似乎很难在数据库中实现。
我一直在寻找PostgreSQL 的ltree模块。它应该使涉及树的部分的数据库操作更快一些。它基本上使您可以在表中设置如下所示的字段:
ltreetest=# select path from test where path <@ 'Top.Science'; path ------------------------------------ Top.Science Top.Science.Astronomy Top.Science.Astronomy.Astrophysics Top.Science.Astronomy.Cosmology
但是,它本身不能确保任何类型的参照完整性。换句话说,您可以具有“ Top.Science.Astronomy”的记录,而无需为“ Top.Science”或“ Top”记录。但是它可以让您做的事情是这样的:
-- hide the children of Top.Science UPDATE test SET hide_me=true WHERE path @> 'Top.Science';
要么
-- nuke the cosmology branch DELETE FROM test WHERE path @> 'Top.Science.Cosmology';
如果结合使用存储过程的传统“ comment_id” /“ parent_id”方法,我认为您可以兼得两者。您可以使用“路径”快速遍历数据库中的注释树,并仍通过“ comment_id” /“ parent_id”确保引用完整性。我正在设想类似的东西:
CREATE TABLE comments ( comment_id SERIAL PRIMARY KEY, parent_comment_id int REFERENCES comments(comment_id) ON UPDATE CASCADE ON DELETE CASCADE, thread_id int NOT NULL REFERENCES threads(thread_id) ON UPDATE CASCADE ON DELETE CASCADE, path ltree NOT NULL, comment_body text NOT NULL, hide boolean not null default false );
注释的路径字符串看起来像是
. . . .
因此,线程“ 102”的根注释的comment_id为“ 1”将具有以下路径:
102.1
一个其comment_id为“ 3”的孩子将是:
102.1.3
ID为“ 31”和“ 54”的“ 3”子代将是:
102.1.3.31 102.1.3.54
要隐藏节点“ 3”及其子节点,可以发出以下命令:
UPDATE comments SET hide=true WHERE path @> '102.1.3';
我不知道-这可能会增加不必要的开销。另外,我不知道ltree的维护情况如何。