最后,我们将讨论书签推荐脚本recommend.php。我们可以通过许多方法实现书签推荐。在此,我们决定应用“相似意向”的推荐。该推荐的含义是,查找与给定用户至少有一个相同书签的其他用户。其他用户的其他书签也对给定的用户有吸引力。
将“相似意向”应用到SQL查询最简单的方法是使用子查询。第一个子查询如下所示:
select distinct(b2.username)
from bookmark b1,bookmark b2
where b1.username='".$valid_user."'
and b1.username!=b2.username
and b1.bm_URL=b2.bm_URL)
这个查询使用别名将数据库表bookmark进行自身连接——这是一个很奇怪但是有时候又非常有用的概念。假设有两个书签表,b1和b2。在b1中,查询当前用户及其书签。在另一个表中,查询所有其他用户的书签。我们需要查找的是用户书签中有一个URL与当前用户相同(b1.bm_URL=b2.bm_URL)的其他用户(b2.username)。其他用户不包括当前用户(b1.username!=b2.username)。
该查询将给出一个与当前用户意向相似的人的列表。得到了这个用户列表后,可以用下面的查询搜索他们的其他书签了:
select bm_URL
from bookmark
where username in
(select distinct(b2.username)
from bookmark b1,bookmark b2
where b1.username='".$valid_user."'
and b1.username!=b2.username
and b1.bm_URL=b2.bm_URL)
可以添加第二个子查询来过滤当前用户的书签;如果用户已经有了这些书签,就不必再将该书签推荐给他。最后,对$popularity变量进行书签过滤。我们不希望推荐太个性化的URL,因此只将一定数量的其他用户做了书签的URL推荐给用户。最终的查询如下所示:
select bm_URL
from bookmark
where username in
(select distinct(b2.username)
from bookmark b1,bookmark b2
where b1.username='".$valid_user."'
and b1.username!=b2.username
and b1.bm_URL=b2.bm_URL)
and bm_URL not in
(select bm_URL
from bookmark
where username='".$valid_user."')
group by bm_url
having count(bm_url)>".$popularity;
如果我们期望许多用户使用我们的系统,可以调整变量$popularity,只推荐许多其他用户做了书签的URL。许多人做了书签的URL可能质量更高,这样的书签当然比一般的页面更大众化、更具吸引力。
实现书签推荐的完整脚本如程序清单27-26和程序清单27-27所示。推荐的主脚本称为recommend.php(请参阅程序清单27-26),它调用来自url_fns.php函数库(请参阅程序清单27-27)的函数recommend_urls。
程序清单27-26 recommend.php——推荐某一用户可能喜欢的书签
<?php
require_once('bookmark_fns.php');
session_start;
do_html_header('Recommending URLs');
try{
check_valid_user;
$urls=recommend_urls($_SESSION['valid_user']);
display_recommended_urls($urls);
}
catch(Exception$e){
echo$e->getMessage;
}
display_user_menu;
do_html_footer;
?>
程序清单27-27 url_fns.php文件中的recommend_urls函数——该脚本做出实际的推荐
function recommend_urls($valid_user,$popularity=1){
//We will provide semi intelligent recommendations to people
//If they have an URL in common with other users,they may like
//other URLs that these people like
$conn=db_connect;
//find other matching users
//with an url the same as you
//as a simple way of excluding people's private pages,and
//increasing the chance of recommending appealing URLs,we
//specify a minimum popularity level
//if$popularity=1,then more than one person must have
//an URL before we will recommend it
$query="select bm_URL
from bookmark
where username in
(select distinct(b2.username)
from bookmark b1,bookmark b2
where b1.username='".$valid_user."'
and b1.username!=b2.username
and b1.bm_URL=b2.bm_URL)
and bm_URL not in
(select bm_URL
from bookmark
where username='".$valid_user."')
group by bm_url
having count(bm_url)>".$popularity;
if(!($result=$conn->query($query))){
throw new Exception('Could not find any bookmarks to recommend.');
}
if($result->num_rows==0){
throw new Exception('Could not find any bookmarks to recommend.');
}
$urls=array;
//build an array of the relevant urls
for($count=0;$row=$result->fetch_object;$count++){
$urls[$count]=$row->bm_URL;
}
return$urls;
}
recommend.php的输出示例如图27-11所示。
图 27-11 脚本向该用户推荐了他可能喜欢的amazon.com,数据库中至少有两位用户将amazon.com作为他们的书签