资讯专栏INFORMATION COLUMN

基于Tags的简单内容推荐的实现

邱勇 / 2170人阅读

摘要:原来为了简单方便,自己小网站上的文章页的相关内容推荐就是从数据库里随机抽取数据来填充一个列表,所以一点相关性都没有,更本没有办法引导用户去访问推荐内容。

原来为了简单方便,自己小网站上的文章页的相关内容推荐就是从数据库里随机抽取数据来填充一个列表,所以一点相关性都没有,更本没有办法引导用户去访问推荐内容。

算法选择

如何能做到相似内容的推荐呢,碍于小网站还跑在虚拟主机上(对的,连一个自己完整可控的服务器都没有),所以可以想的办法不多,条件限制在 只能用PHP+MySql。所以我想到的办法就是通过Tags来匹配相似文章进行推荐。如果两篇文章的TAGS 比较相似

比如:文章A 的TAGS为: [A,B,C,D,E]
文章B 的 TAGS 为:[A,D,E,F,G]
文章C 的 TAGS 为:[C,H,I,J,K]

通过眼睛我们能很方便的发现,文章B和文章A更为相似,因为它们有三个关键字相同分别为:[A,D,E],哪如何用计算机来判断它们的相似度呢,这里我们用jaccard相似度的最基本应用来计算它们的相似度

jaccard相似度

给定两个集合A,B,Jaccard 系数定义为A与B交集的大小与A与B并集的大小的比值,定义如下:

文章A和文章B的交集为 [A,D,E],大小为3,并集为[A,B,C,D,E,F,G],大小为7,3/7=0.4285...
而文章A和文章C交集为 [C],大小为1,并集为[A,B,C,D,E,H,I,J,K],大小为9, 1/9=0.11111...

这样就可以得出文章A,B比文章A,C更为相似,有了这个算法,计算机就可以来判断两篇文章的相似度了。

具体的推荐思想

给定一篇文章,获取该文章的关键字TAGS,然后通过以上算法去数据库比对所有文章的相似度,获取最相似的N篇文章进行推荐。

实现过程 第一 TAGS的获取

文章的TAGS是通过TF-IDF算法,提取文章中的高频词,选取N个作为TAGS,对于中文的文章来说还涉及到一个中文分词的问题,因为是虚拟主机的关系,这步的工作我用python(为什么用Python ,jieba分词,真香)在本地写了一个程序,完成所有文章的分词,词频统计,生成TAGS,并写回服务器的数据库。由于本文是写推荐的算法,所以分词和建立TAGS的部分就不具体展开了,而且不同的系统有不同的TAGS建立方式。

第二 TAGS的存储

建立两张表,用于存储TAGS
tags,用于存所有tag的名称

+-------+------------+------+-----+---------+-------+
| Field | Type       | Null | Key | Default | Extra |
+-------+------------+------+-----+---------+-------+
| tag   | text       | YES  |     | NULL    |       |
| count | bigint(20) | YES  |     | NULL    |       |
| tagid | int(11)    | NO   | PRI | 0       |       |
+-------+------------+------+-----+---------+-------+

tag_map 建立tag和文章的映身关系。

+-----------+------------+------+-----+---------+-------+
| Field     | Type       | Null | Key | Default | Extra |
+-----------+------------+------+-----+---------+-------+
| id        | bigint(20) | NO   | PRI | 0       |       |
| articleid | bigint(20) | YES  |     | NULL    |       |
| tagid     | int(11)    | YES  |     | NULL    |       |
+-----------+------------+------+-----+---------+-------+

tag_map存的数据类似如下:

+----+-----------+-------+
| id | articleid | tagid |
+----+-----------+-------+
|  1 |       776 |   589 |
|  2 |       776 |   471 |
|  3 |       776 |  1455 |
|  4 |       776 |  1287 |
|  5 |       776 |    52 |
|  6 |       777 |  1386 |
|  7 |       777 |   588 |
|  8 |       777 |   109 |
|  9 |       777 |   603 |
| 10 |       777 |  1299 |
+----+-----------+-------+

其实做相似推荐的时候,只需要用到tag_map表就可以了,因为tagid和tag name 是一一对应的。

具体编码 1.获取所有文章对应的TAGID
mysql> select articleid, GROUP_CONCAT(tagid) as tags from tag_map GROUP BY articleid;
+-----------+--------------------------+
| articleid | tags                     |
+-----------+--------------------------+
|        12 | 1178,1067,49,693,1227    |
|        13 | 196,2004,2071,927,131    |
|        14 | 1945,713,1711,2024,49    |
|        15 | 35,119,9,1,1180          |
|        16 | 1182,1924,2200,181,1938  |
|        17 | 46,492,414,424,620       |
|        18 | 415,499,153,567,674      |
|        19 | 1602,805,691,1613,194    |
|        20 | 2070,1994,886,575,1149   |
|        21 | 1953,1961,1534,2038,1393 |
+-----------+--------------------------+

通过以上SQL,可以一次性查询所用文章,极其对应的所有tag
在PHP,我们可以把tags变成数组。

public function getAllGroupByArticleId(){
        //缓存查询数据,因为这个是全表数据,而且不更新文章不会变化,便是每次推荐都要从数据库里获取一次数据,对性能肯定会有影响,所以做个缓存。
        if($cache = CacheHelper::getCache()){
            return $cache;
        }
        $query_result = $this->query("select articleid, GROUP_CONCAT(tagid) as tags from tag_map GROUP BY articleid");

        $result = [];
        foreach($query_result as $key => $value){
            //用articleid 做key ,值是该id下的所有tagID数组。
            $result[$value["articleid"]] = explode(",",$value["tags"]);
        }

        CacheHelper::setCache($result, 86400);

        return $result;

    }

有了这个的返回结果,就比较好办了,接下去的工作就是去应用jaccard相似度这个算法了,具体就看代码吧。

/**
     * [更据指定文章返回相似的文章推荐]
     * @param  $articleid 指定的文章ID
     * @param  $top       要返回的推荐条数
     * @return Array      推荐条目数组
     */
function getArticleRecommend($articleid, $top = 5){
        if($cache = CacheHelper::getCache()){
            return $cache;
        }
        try{
            $articleid = intval($articleid);
            $m = new TagMapModel();
            $all_tags = $m->getAllGroupByArticleId();//调用上面的函数返回所有文章的tags
            $finded = $all_tags[$articleid];//因为上面是包含所有文章了,所以肯定包含了当前文章。

            unset($all_tags[$articleid]);//把当前文章从数组中删除,不然自己和自己肯定是相似度最高了。

            $jaccard_arr = []; //用于存相似度
            foreach ($all_tags as $key => $value) {
                $intersect =array_intersect($finded, $value); //计算交集
                $union = array_unique(array_merge($finded, $value)); //计算并集

                $jaccard_arr[$key] = (float)(count($intersect) / count($union));
            }

            arsort($jaccard_arr); //按相似度排序,最相似的排最前面

            $jaccard_keys = array_keys($jaccard_arr);//由于数组的key就是文章id,所以这里把key取出来就可以了
            array_splice($jaccard_keys, $top);//获取前N条推荐

            //到这里我们就已经得到了,最相似N篇文章的ID了,接下去的工作就是通过这几个ID,从数据库里把相关信息,查询出来就可以了
    
            $articleModels = new ApiModelArticleModel();
            $recommendArticles = $articleModels->getRecommendByTag($jaccard_keys);
            CacheHelper::setCache($recommendArticles, 604800); //缓存7天
            return $recommendArticles;
        } catch (Exception $e) {
            throw new Exception("获取推荐文章错误");
        }
    }

虽然简单,短短几条代码,但是效果还是可以的,推荐的文章有了一定的相似度,肯定可以带来更好的用户体验,实例 ,你们可以看看 https://www.wx2share.com/Arti...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/62030.html

相关文章

  • 基于Tags简单内容推荐实现

    摘要:原来为了简单方便,自己小网站上的文章页的相关内容推荐就是从数据库里随机抽取数据来填充一个列表,所以一点相关性都没有,更本没有办法引导用户去访问推荐内容。 原来为了简单方便,自己小网站上的文章页的相关内容推荐就是从数据库里随机抽取数据来填充一个列表,所以一点相关性都没有,更本没有办法引导用户去访问推荐内容。 算法选择 如何能做到相似内容的推荐呢,碍于小网站还跑在虚拟主机上(对的,连一个自...

    CrazyCodes 评论0 收藏0
  • 基于Tags简单内容推荐实现

    摘要:原来为了简单方便,自己小网站上的文章页的相关内容推荐就是从数据库里随机抽取数据来填充一个列表,所以一点相关性都没有,更本没有办法引导用户去访问推荐内容。 原来为了简单方便,自己小网站上的文章页的相关内容推荐就是从数据库里随机抽取数据来填充一个列表,所以一点相关性都没有,更本没有办法引导用户去访问推荐内容。 算法选择 如何能做到相似内容的推荐呢,碍于小网站还跑在虚拟主机上(对的,连一个自...

    smallStone 评论0 收藏0
  • 基于droneCI/CD,对接kubernetes,见证灵活与自由,CI/CD对接kubernet

    摘要:所以我们选一个仓库仓库比较多,我这里选用,都行,根据需求自行选择访问端口,然后就没有然后了功能没有那么强大,不过占用资源少,速度快,我们稳定运行了几年了。 kubernetes集群三步安装 CI 概述 用一个可描述的配置定义整个工作流 程序员是很懒的动物,所以想各种办法解决重复劳动的问题,如果你的工作流中还在重复一些事,那么可能就得想想如何优化了 持续集成就是可以帮助我们解决重复的代码...

    iOS122 评论0 收藏0
  • Node项目Gitlab自动部署实践(基于Docker)

    摘要:只要的项目有提交,相关就根据来决定是否跑自动部署的命令。项目的自动部署添加执行的注册命令,按照说明进行参数配置。至此,和服务都已经自动部署完成。 准备工作 说明 公司最近准备了一台新的开发服务器,正好用以实践docker的基本应用。docker的好处不再赘述,详情可参考阮一峰的这篇入门。(关于Docker最好的中文介绍,没有之一)。 公司目前主要使用了EggJs + ReactJS的技...

    oysun 评论0 收藏0
  • 使用hexo+github搭建免费个人博客详细教程

    摘要:如果实在不会安装可以去网上找教程。打开,跳转到刚刚创建的文件夹位置,运行命令然后会在你的文件夹中搭建好了环境配置配置修改一些你的博客名字描述作者等。基于我的个人经验,建议都开启开启标签页命令,在博客目录添加元数据开启分类页命令,在博 Windows环境下Git安装、配置SSH key、安装node.js npm、安装Hexo及配置、发布博客 前言 使用github pages服务搭建博客的...

    番茄西红柿 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<