5

我正在尝试为在线商店建立一个穷人的推荐系统。我想实现这种亚马逊“购买此商品的客户也购买了”功能,我读了很多关于它的内容。我知道有 Apache Mahout 的东西,但我无法以这种方式调整服务器。然后会有谷歌预测 API,但它要花钱,所以我开始自己试验。

我有一个包含 250.000 多个项目的订单历史记录,我编写了一个嵌套的 MySQL 查询来查找包含当前文章的订单,对其他订单项目进行排名并对表进行排序以进行排名,所以我得到了一组其他人订购的产品以及当前文章。

问题是,查询可能需要 10 秒 - 所以不能直接使用。我想到了一个缓存表,但这个查询在 20 分钟后停止(有 60.000 个产品和 250.000 个订购项目)所以我无法填写该表。

我当前的解决方法如下:推荐 HTML 是通过 AJAX ondocumentready 加载的,因此会加载网站,而推荐会在后台加载。推荐数据被处理一次并存储在文件缓存(PEAR 简单缓存)中,因此下次加载速度更快。因此,如果有人访问该站点并存储一天或一周,则按需生成缓存。

我问自己和你,这是一种可以接受的方法,还是愚蠢和无能?将缓存的数据存储在数据库或文件中会更好(我考虑性能和并行命中)。我的意思是,在最坏的情况下,我最终会得到 60.000 个缓存文件。

我更喜欢一个包含所有数据的预先计算的表,但正如我所说,这需要很长时间,而且我不知道如何优化它。(等 SQL Dude 放假回来^^)

感谢您的任何提示,意见。

顺便提一句。这是查询:

SELECT c.ArtNr as artnr , count(c.ArtNr) as rank, s.ArtNr as parent_artnr
FROM (
SELECT a.ID_order, a.ArtNr
        FROM net_orderposition a
        WHERE a.ArtNr = 'TT-PV0005'
) s
JOIN net_orderposition c 
WHERE s.ID_order = c.ID_order AND s.ArtNr != c.ArtNr
GROUP BY c.ArtNr
ORDER BY rank DESC,c.Stamp DESC
LIMIT 10;

编辑:

我考虑了给定的答案,我认为它们与我最初的想法相似。上面的代码结果如下表:

ID,ParentID , ChildID  , Rank
1, TT-PV0005, TT-PV0040, 220
2, TT-PV0005, TT-PV0355, 135
3, TT-PV0005, TT-PV0450, 134
4, TT-PV0005, TT-PV0451, 89
5, TT-PV0005, RH-01V2  , 83
6, TT-PV0005, TT-PV0041, 83
7, TT-PV0005, TT-PV0353, 82
8, TT-PV0005, TT-PV0037, 80

ParentID 是当前项目,ChildID 是过去与 ParentID 一起订购的项目,Rank 是预计算的孩子订购当前项目的频率的计数。现在,我可以在每个新订单上更新或插入相关项目,并计算排名(如果它已经存在于数据库中)。我唯一担心的是,我最终会坐在一张非常大的桌子上。如果我每周离线一次预先计算,也许这应该不是问题?但随后我必须优化查询,以便每个项目不需要 10 秒。

你怎么看?

4

3 回答 3

3

查看easyrec,它具有您需要的功能并且是免费的。无需调整,您可以使用 Demo 实例,如谷歌分析。我认为使用这个免费的网络服务然后自己编写整个逻辑会容易得多。

在今天的一条推文中,他们提到他们支持对 easyrec 的完整 mahout 支持,因此您可以使用 easyrec。您可以使用 easyrec 的免费网络服务或在您的网络服务器上部署免费的 WAR 文件。

于 2011-10-12T14:38:12.113 回答
2

要添加到@GalacticCowboy 的答案并填写您的评论位置,@Marcus ...

完成此操作的一种模式是创建一个表,例如:

RelatedItems
RelatedItemsId
purchasedItemId
relatedItemId

然后,当订单完成(或根据您的要求查看)时,您会将记录写入 RelatedItems 表,其中购买的每件商品都会获得一条记录,其中该 id 是 purchaseItemId。然后所有其他项目将被写为relatedItemId。

例如,如果我购买了项目 5、9、12 和 19,我将有 12 条记录写入我的表中,如下所示:

RelatedItemId, PurchasedItemId, RelatedItemId
1, 5, 9
2, 5, 12
3, 5, 19
4, 9, 5
5, 9, 12
6, 9, 19
7, 12, 5
8, 12, 9
9, 12, 19
10, 19, 5
11, 19, 9
12, 19, 12

然后,您可以使用类似于 GalacticCowboy 的查询来获取通常与这些物品中的任何物品一起购买的前 10 件物品。

请注意,对于这样的任务,这不是最有效的模式,可以对其进行相当多的调整以减少冗余数据,但鉴于我们对您的系统和整体模式设计(以及看起来对一些 SQL 概念的理解不可靠)我不打算深入探讨。

于 2011-07-18T20:28:42.923 回答
0

每次有订单时,存储订单中不同商品之间的关系记录。然后执行以下操作:

SELECT ItemID, COUNT(RelatedItemID) AS RelatedItemCount
FROM RelatedItems
WHERE RelatedItemID = @viewingItemID
GROUP BY ItemID
ORDER BY RelatedItemCount DESC
LIMIT 10

您还可以使用通宵流程或其他方式对此进行预总结,并拥有一个仅包含每个项目 ID的前n 个相关项目的表。

于 2011-07-18T20:01:13.243 回答