基于相似兴趣的用户匹配算法实现方案问询(支持10万用户)
解决方案
针对你的需求,这里提供几个适配不同场景的实现方案,从原生MySQL适配到进阶优化都有覆盖:
一、原生MySQL+PHP实现(适配现有技术栈)
思路说明
通过计算目标用户与其他用户的加权共同兴趣得分排序:两人共同点赞的兴趣权重累加,得分越高兴趣相似度越高。
核心SQL(目标用户ID=123,分页每页20条)
SELECT u.user_id, u.name, SUM(i.weight) AS similarity_score FROM `like` l1 JOIN `like` l2 ON l1.interest_id = l2.interest_id AND l1.user_id = 123 -- 指定目标用户 AND l2.user_id != 123 -- 排除目标用户自身 JOIN interest i ON l1.interest_id = i.interest_id JOIN user u ON l2.user_id = u.user_id GROUP BY u.user_id, u.name ORDER BY similarity_score DESC, u.user_id ASC LIMIT 20 OFFSET 0; -- 分页参数,OFFSET对应(page-1)*20
性能优化(适配10万用户规模)
- 给
like表加两个联合索引:(user_id, interest_id)和(interest_id, user_id),这能让关联查询直接走索引,避免全表扫描 - 大偏移量分页时,别用LIMIT OFFSET(会扫描大量无关数据),改用游标分页:
-- 假设上一页最后一条数据的user_id是456,similarity_score是8 SELECT u.user_id, u.name, SUM(i.weight) AS similarity_score FROM `like` l1 JOIN `like` l2 ON l1.interest_id = l2.interest_id AND l1.user_id = 123 AND l2.user_id != 123 JOIN interest i ON l1.interest_id = i.interest_id JOIN user u ON l2.user_id = u.user_id GROUP BY u.user_id, u.name HAVING (similarity_score < 8) OR (similarity_score = 8 AND u.user_id > 456) ORDER BY similarity_score DESC, u.user_id ASC LIMIT 20;
二、预计算优化方案(适合高并发场景)
如果MySQL实时查询性能跟不上,可以提前计算好用户间的相似度:
- 建一张
user_similarity表,字段为user_id1、user_id2、similarity_score - 每天凌晨跑定时任务,批量计算所有用户对的加权相似度并存入该表
- 查询时直接从
user_similarity表按user_id1=目标ID排序分页,速度比实时计算快很多 - 注意:用户点赞兴趣变化时,要么实时更新相关相似度记录,要么接受短时间的数据延迟
三、向量数据库进阶方案(适合未来扩展)
如果后续兴趣种类增多,或者需要更灵活的相似度计算,可以用向量数据库:
- 把每个用户的兴趣转化为加权向量:每个兴趣对应一个维度,点赞的兴趣维度值设为对应权重,未点赞为0
- 用Milvus、Chroma这类向量数据库存储用户向量,通过余弦相似度快速检索最相似的用户
- PHP端调用向量数据库API拿到相似用户ID后,再关联
user表获取用户信息
内容的提问来源于stack exchange,提问作者AndyW
相关产品推荐
相关产品推荐

