我正在创建一个约会门户网站,我们将向用户询问大约 40-50 个问题,例如宗教、种姓、出生日期、食物偏好、吸烟/不吸烟。
我正在就年龄范围、宗教偏好、吸烟偏好等用户偏好提出类似的问题。
我有大约 30-40 个这样的偏好。
现在我想根据首选项集向用户显示匹配项。我想知道我应该如何设计 MySQL 表和索引。
我应该创建 1 个 user_preferences 大表并拥有所有首选项索引。应该是多列索引还是合并索引。
我应该在不同的表中保留一组问题并在获取数据时加入它们吗?米
我正在创建一个约会门户网站,我们将向用户询问大约 40-50 个问题,例如宗教、种姓、出生日期、食物偏好、吸烟/不吸烟。
我正在就年龄范围、宗教偏好、吸烟偏好等用户偏好提出类似的问题。
我有大约 30-40 个这样的偏好。
现在我想根据首选项集向用户显示匹配项。我想知道我应该如何设计 MySQL 表和索引。
我应该创建 1 个 user_preferences 大表并拥有所有首选项索引。应该是多列索引还是合并索引。
我应该在不同的表中保留一组问题并在获取数据时加入它们吗?米
我看到这样的事情:
questions
是要回答的问题列表。question_type
是一个枚举,指示期望的答案类型(例如从question_choices
、日期、数字、文本等查找) - 您希望输入的任何类型的数据。这与此表中的其他列一起,可以驱动您的输入表单。
question_answers
包含预定义的问题答案列表(例如预定义的宗教列表、头发颜色或眼睛颜色等)。这可用于在输入表单上构建值的下拉列表。
users
非常不言自明。
user_characteristics
包含我对调查问卷的回答列表。该weight
栏表明寻找我的人有相同的答案对我来说有多重要。question_choices_id
如果答案来自从表中构建的选择列表,则会填充question_choices
。否则question_choices_id
将为NULL。反之亦然value
。value
如果答案来自从表中构建的选择列表,则为 NULL question_choices
。否则value
将包含用户对问题的手工制作的答案。
user_preferences
包含我正在寻找的问卷的答案。该weight
栏表明我正在寻找的人有相同的答案对我来说有多重要。question_choices_id
和列的value
行为与表中的相同user_characteristics
。
查找我的匹配项的 SQL 可能类似于:
SELECT uc.id
,SUM(up.weight) AS my_weighted_score_of_them
,SUM(uc.weight) AS their_weighted_score_of_me
,SUM(up.weight) + SUM(uc.weight) AS combined_weighted_score
FROM user_preferences up
JOIN user_characteristics uc
ON uc.questions_id = up.questions_id
AND uc.question_choices_id = up.question_choices_id
AND uc.value = up.value
AND uc.users_id != up.users_id
WHERE up.users_id = me.id
GROUP BY uc.id
ORDER BY SUM(up.weight) + SUM(uc.weight) DESC
,SUM(up.weight) DESC
,SUM(uc.weight) DESC
出于性能原因,建议对 user_characteristics(id、question_id、question_choices_id、value 和 user_id) 使用索引和在 user_preferences(id、question_id、question_choices_id、value 和 user_id) 上使用索引。
请注意,上述 SQL 将为每个用户返回一行,但发出请求的用户除外。这当然是不可取的。因此,人们可能会考虑添加HAVING SUM(up.weight) + SUM(uc.weight) > :some_minimum_value
- 或其他方式来进一步过滤结果。
进一步的调整可能包括只返回与我一样重视答案的人(即他们的特征体重> =我的体重偏好权重。
我认为这可能是EAV的情况:
您应该能够按降序(从最匹配到最不匹配)获得匹配的用户对,类似于:
SELECT *
FROM (
SELECT U1.USER_ID, U2.USER_ID, COUNT(*) MATCH_COUNT
FROM USER U1
JOIN USER_PREFERENCE P1
ON (U1.USER_ID = P1.USER_ID)
JOIN USER_PREFERENCE P2
ON (P1.NAME = P2.NAME AND P1.VALUE = P2.VALUE)
JOIN USER U2
ON (P2.USER_ID = U2.USER_ID)
WHERE U1.USER_ID < U2.USER_ID -- To avoid matching the user with herself and duplicated pairs with flipped user IDs.
GROUP BY U1.USER_ID, U2.USER_ID
) Q
ORDER BY MATCH_COUNT DESC
这只是通过它们的确切值匹配偏好。您可能希望为范围或类似枚举的值创建额外的“首选项”表,并P1.VALUE = P2.VALUE
相应地进行替换。如果匹配的是 USER 表中的数据(例如用户的年龄是否属于其他用户的首选年龄范围),您可能还需要特殊处理。
{NAME, VALUE}
请注意旨在提供帮助的索引P1.NAME = P2.NAME AND P1.VALUE = P2.VALUE
。InnoDB 表是聚集的,一个后果是二级索引包含 PK 字段的副本——在这种情况下会导致索引I1
完全覆盖表。MySQL 是否会真正使用它是另一回事 - 一如既往地查看查询计划并衡量代表性数据......