存储用于推荐营销的分层数据 (MySQL)
我需要为网站注册的用户提供 5 级层次结构。每个用户都受到另一个用户的邀请,我需要知道一个用户的所有后代。还有用户的祖先。
我想到了2个解决方案。
- 以这种方式保持关系表。闭包表:
ancestor_id descendant_id distance
1 1 0
2 2 0
3 3 0
4 4 0
5 5 0
6 6 0
2 3 1
- 拥有此关系表。表中保存有5级祖先。 “祖先”表:
user_id ancestor_level1_id ancestor_level2_id ancestor_level3_id ancestor_level4_id ancestor_level5_id
10 9 7 4 3 2
9 7 4 3 2 1
这些是好主意吗?
我了解“邻接列表模型”和“修改后的先序树遍历算法”,但是这些对于“推荐”系统来说是很好的解决方案吗?
我需要在这棵树上执行的查询是:
- 当用户购买东西时经常添加新用户
- ,他们的推荐人获得百分比佣金
- 每个用户应该能够找出他们推荐了多少人(以及有多少人被推荐)由他们推荐的人推荐......)在每个级别
I need to have a 5 levels hierarchy for the users registered to a website. Every user is invited by another, and I need to know all descendants for a user. And also ancestors for a user.
I have in mind 2 solution.
- Keeping a table with relationships this way. A closure table:
ancestor_id descendant_id distance
1 1 0
2 2 0
3 3 0
4 4 0
5 5 0
6 6 0
2 3 1
- Having this table for relationships. Keeping in a table 5 levels ancestors. A "ancestors" table:
user_id ancestor_level1_id ancestor_level2_id ancestor_level3_id ancestor_level4_id ancestor_level5_id
10 9 7 4 3 2
9 7 4 3 2 1
Are these good ideas?
I know about "the adjacency list model" and "the modified preorder tree traversal algorithm", but are these good solutions for a "referral" system?
The queries that I need to perform on this tree are:
- frequently adding a new users
- when a user buys something, their referrers get a percentage commission
- every user should be able to find out how many people they've referred (and how many people were referred by people who they referred....) at each level
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
关闭表
要添加由用户 3 引用的用户 10。(我认为您不需要在这两个插入之间锁定表):
查找用户 3 引用的所有用户。
对这些用户进行计数按深度:
查找用户 10 的祖先。
此方法的缺点是该表将占用大量存储空间。
Closure Table
To add user 10, referred by user 3. (I don't think you need to lock the table between these two insertions):
To find all users referred by user 3.
To count those users by depth:
To find the ancestors of user 10.
The drawback to this method is amount of storage space this table will take.
使用 OQGRAPH 存储引擎。
您可能想要跟踪任意数量的级别,而不仅仅是 5 个级别。获取支持 QGRAPH 引擎 的 MySQL 分支之一(例如例如 MariaDB 或 OurDelta),并使用它来存储您的树。它实现了邻接表模型,但通过使用名为
latch
的特殊列向存储引擎发送命令,告诉它要执行哪种查询,您可以获得闭包表的所有优点无需在每次有人注册您的网站时进行簿记工作。以下是您在 OQGRAPH 中使用的查询。请参阅以下位置的文档:
http://openquery.com/graph-computation-engine-documentation
我们要去使用 origid 作为引用者,并使用 destid 作为引用者。
添加用户 11,由用户 10 引用
查找用户 3 引用的所有用户。 查找
用户 10 的祖先。
查找每个级别的用户数量,由用户 3 引用:
Use the OQGRAPH storage engine.
You probably want to keep track of an arbitrary number of levels, rather than just 5 levels. Get one of the MySQL forks that supports the QGRAPH engine (such as MariaDB or OurDelta), and use that to store your tree. It implements the adjacency list model, but by using a special column called
latch
to send a command to the storage engine, telling it what kind of query to perform, you get all of the advantages of a closure table without needing to do the bookkeeping work each time someone registers for your site.Here are the queries you'd use in OQGRAPH. See the documentation at
http://openquery.com/graph-computation-engine-documentation
We're going to use origid as the referrer, and destid as the referree.
To add user 11, referred by user 10
To find all users referred by user 3.
To find the ancestors of user 10.
To find the number of users at each level, referred by user 3:
管理 MySQL 中的分层数据
一般来说,我喜欢“嵌套集” ”,特别是。 MySQL 并没有真正提供对分层数据的语言支持。
它速度很快,但如果易于维护很重要,您需要确保您的开发人员阅读该文章。它非常灵活——这对于你的情况来说似乎并不重要。
这似乎很适合您的问题 - 在推荐模型中,您需要找到推荐人树,这在嵌套集合模型中速度很快;您还需要知道给定用户的 ~children@ 是谁,以及他们的关系深度;这也很快。
Managing Hierarchical Data in MySQL
In general, I like the "nested set", esp. in MySQL which doesn't really have language support for hierarchical data.
It's fast, but you'll need to make sure your developers read that article if ease of maintenance is a big deal. It's very flexible - which doesn't seem to matter much in your case.
It seems a good fit for your problem - in the referral model, you need to find the tree of referrers, which is fast in the nested set model; you also need to know who are the ~children@ of a given user, and the depth of their relationship; this is also fast.
祖先的分隔字符串
如果您强烈考虑使用 5 级关系表,则使用祖先的分隔字符串而不是 5 个单独的列可能会简化事情。
以下是您在此模型中使用的一些 SQL 命令:
添加用户 10 引用的用户 11
查找用户 3 引用的所有用户。(请注意,此查询不能使用索引。)
查找用户的祖先10. 您需要在客户端程序中分解字符串。在 Ruby 中,代码为ancestorscolumn.split(",").map{|x| x.to_i}。没有好的方法可以在 SQL 中分解字符串。
要查找用户 3 引用的每个级别的用户数量:
您可以使用
like concat( 来避免这些查询的
而是将用户号码的整数绑定到占位符。like '%,3,%'
部分中的 SQL 注入攻击'%,', ?, ',%')Delimited String of Ancestors
If you're strongly considering the 5-level relationship table, it may simplify things to use a delimited string of ancestors instead of 5 separate columns.
Here are some SQL commands you'd use with this model:
To add user 11, referred by user 10
To find all users referred by user 3. (Note that this query can't use an index.)
To find the ancestors of user 10. You need to break up the string in your client program. In Ruby, the code would be
ancestorscolumn.split(",").map{|x| x.to_i}
. There's no good way to break up the string in SQL.To find the number of users at each level, referred by user 3:
You can avoid SQL injection attacks in the
like '%,3,%'
parts of these queries by usinglike concat('%,', ?, ',%')
instead and binding the an integer for the user number to the placeholder.