【问题标题】:Showing users who liked an item in an item list显示喜欢项目列表中项目的用户
【发布时间】:2014-05-05 20:18:11
【问题描述】:

这是一个我认为实施起来不切实际的问题,但我希望得到一些反馈来确认。

我有一个产品和用户数据库,用户可以在其中喜欢产品,喜欢的数据存储在只有 pid 和 uid 的引用表中。

客户的要求是显示 3 位喜欢产品列表中每个产品的用户。

问题是,不可能在一次查询产品列表中获取此数据,

我曾经实施和随后取消实施的方式是在产品列表循环期间为喜欢产品的用户执行请求。

即。

foreach($prods as $row):
$likers = $this->model->get_likers($row->id);
endforeach;

这行得通,但显然不仅会导致产品列表超级慢,而且还会对数据库/cpu 造成很大压力。

最终实现的解决方案是只显示喜欢它的最新用户(这可以通过加入产品列表查询获得),并有一个链接显示有多少人喜欢,然后点击它, 打开喜欢的 ajax 列表。

所以我的问题是,真的有一种技术可以在产品列表上显示喜欢的人,还是根本无法实际执行?我注意到实际上对于大多数社交媒体网站,它们并没有在列表中显示所有喜欢的人,并且确实采用了“点击查看喜欢”的方法。但是,它们确实会在列表中显示每个项目的 cmets,这实际上涉及到相同的问题不是吗?

任何帮助/指导将不胜感激!

谢谢

编辑:附加在期望结果上的模型。每页将有 30 个产品。

【问题讨论】:

  • 您能否详细说明您想要获得的结果(包括样本数据/预期结果通常会有所帮助)?据我了解,您想要一个产品列表,并且对于每个产品,您想要 3 个人喜欢它?
  • 嗨,Alex,是的,您所理解的正是我的意思。这更多是一个概念/技术问题,所以实际的具体数据并不重要,除了我们有一个产品列表和一个用户列表,用户可以喜欢产品,这个用户产品关系是存储在交集表中。那么是否可以列出每页 50 个产品,并显示 X 数量的用户喜欢加载时间快且资源容易使用的产品?
  • 您是否正在寻找与 SQL 相关的解决方案,因为我认为 Pinterest 使用 Redis 来处理这些关系。

标签: php mysql database performance social


【解决方案1】:

问题

问题在于数据量。从您需要两个整数值作为答案的角度来看,您应该忘记从 nn 关系表构建繁重的查询。

解决方案

每次用户喜欢产品时,使用带有附加选项的 file_put_contents() 生成可存储的表示。我没有足够的空间在这里写课程。

public function export($file);

3D 数组格式

array[product][line][user]

例子:

$likes[1293][1][456]=1;
$likes[82][2][656]=1;
$likes[65][3][456]=1;
.
.
.

喜欢这个特定产品的用户数量:

$number_users_like_this_product = count($likes[$idProduct]);

所有喜欢此特定产品的 idUser:

$users_like_this_product = count($likes[$idProduct][$n]);

都喜欢

$all_likes = count($likes);

删除点赞

此循环将取消设置您想要的 $idProduct 和 $IdUser 的唯一行。由于所有变量都是无符号整数,所以速度非常快。

for($n=1, $n <= count($likes[$idProduct]), $n++)
{
 unset($likes[$idProduct][$n][$idUser]);
}

结论

获得所有喜欢将很容易:

include('likes.php');

P.S 如果你想试一试,我很乐意优化我的东西并分享它。我在 2012 年创建了这个类。

【讨论】:

    【解决方案2】:

    通过阅读您对 Alex.Ritna 的评论回复,是的,您可以获得 x 号。每个组的结果,使用GROUP_CONCAT()SUBSTRING_INDEX() 它将显示用逗号或您在查询中指定的任何分隔符分隔的喜欢者(我使用了||)。ORDER BY 子句可以在 group_concat 函数中使用。由于没有可用的架构信息,所以我假设您有一个产品表、一个用户表和一个连接表,该表维护用户和产品的关系。在子字符串函数中,我使用了 x=3

    SELECT p.*,
    COUNT(*) total_likes,
    SUBSTRING_INDEX(
    GROUP_CONCAT( CONCAT(u.firstname,'  ',u.lastname)  ORDER BY some_column DESC SEPARATOR '||'),
    '||',3) x_no_of_likers
    FROM product p
    LEFT JOIN junction_table jt ON(p.id=jt.product_id)
    INNER JOIN users u  ON(u.id=jt.user_id)
    GROUP BY p.id
    

    Fiddle

    现在在您的应用程序级别,您只需遍历产品并通过分隔符将 x_no_of_likers 拆分为每个产品的喜欢者

    foreach($prods as $row):
    $likers=explode('||',$row['x_no_of_likers']);
    $total_likes= $row['total_likes'];
        foreach($likers as $user):
        ....
        endforeach;
    endforeach;
    

    请注意,GROUP_CONCAT() 设置了默认的 1024 个字符限制,但您也可以按照 GROUP_CONCAT() 手册增加它

    从 cmets 编辑这是另一种获取每个组 n 个结果的方法,从中您可以从用户表中获取所有字段,我使用了一些变量来获取产品组的排名,使用junction_table 的子查询来获得排名,在外部选择中,我使用HAVING jt.user_rank &lt;=3 过滤了具有此排名的记录,因此它将为每个产品提供三个用户记录,我还对产品(SELECT * FROM product LIMIT 30 ) 使用子查询所以前30组每个将有 3 个结果,因为最后不能使用低于查询限制的结果,所以我在子查询中使用了

    SELECT p.id,p.title,u.firstname,u.lastname,u.thumbnail,jt.user_rank
    FROM 
    (SELECT * FROM `product` LIMIT 30 ) p
    LEFT JOIN 
     (  SELECT j.*,
       @current_rank:= CASE WHEN @current_rank = product_id THEN  @user_rank:=@user_rank +1 ELSE @user_rank:=1 END  user_rank,
       @current_rank:=product_id
        FROM `junction_table` j ,
        (SELECT @user_rank:=0,@current_rank:=0) r   
        ORDER BY product_id 
      ) jt ON(jt.product_id = p.id)
      LEFT JOIN `users` u ON (jt.`user_id` = u.`id`) 
      HAVING jt.user_rank <=3 
      ORDER BY p.id
    

    Fiddle n results per group

    【讨论】:

    • 您好,Khalid,感谢您的回答。如果我想要的不仅仅是喜欢者的名字怎么办?例如,我实际上需要用户名和缩略图字段。另外,您会使用相同的方法在每个产品上显示 cmets 吗? IE。 pinterest.com、facebook 等
    【解决方案3】:

    我假设这两个表的大小都非常大。您应该创建一个新表(例如LastThreeLikes),其中的列将是piduid_1uid_2uid_3,由pid 索引。此外,在您的产品表中添加一个名为 numLikes 的列。

    对于您在参考表中输入的每个“喜欢”,如果numLikes 小于 3,则创建一个触发器,该触发器也填充此 LastThreeLikes 表。您可以选择随机更新其中一个值,如果您想偶尔向新用户展示一次。

    在显示产品时,只需从该表中获取 uids 并将它们显示回来。

    请注意,您还需要为“Unlike”操作(如果有)维护一个触发器,以使用新的用户 ID 重新填充 LastThreeLikes 表。

    【讨论】:

      【解决方案4】:

      您应该能够使用此 sql 获得所有喜欢所有产品的用户的列表。

      select uid, 
             count(pid) as liked_products
        from product_user
       group by uid
      having liked_products = (select count(1) from products);
      

      但是随着数据的增长,这个查询会变慢。最好维护一个具有相似计数的表,该表通过触发器或单独维护。每次喜欢/不喜欢计数器都会更新。这样可以轻松显示每个产品的点赞数。然后,如果想要喜欢该产品的实际用户进行单独的调用(在用户交互时),获取一个产品的特定喜欢)。在实际请求之前,不要对页面上的所有产品执行此操作。

      【讨论】:

      • “那么,如果想要喜欢该产品的实际用户进行单独的调用(在用户交互中),获取一个产品的特定喜欢)。”实际上这是问题的主题,在产品列表页面上显示对所有产品的喜欢是否可行。所以你的建议是,除非有要求,否则永远不要这样做?
      • 正确。对于大量产品和大量客户来说,这是不可行的。最好在客户单击链接时“按需”执行此操作,或者当页面向下滚动到产品时变得非常受欢迎。
      猜你喜欢
      • 2016-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-07
      相关资源
      最近更新 更多