基于Tags完成內(nèi)容推薦的方法(代碼)
發(fā)表時(shí)間:2023-07-09 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]本篇文章給大家?guī)淼膬?nèi)容是關(guān)于基于Tags實(shí)現(xiàn)內(nèi)容推薦的方法(代碼),有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。原來為了簡(jiǎn)單方便,自己小網(wǎng)站上的文章頁的相關(guān)內(nèi)容推薦就是從數(shù)據(jù)庫里...
本篇文章給大家?guī)淼膬?nèi)容是關(guān)于基于Tags實(shí)現(xiàn)內(nèi)容推薦的方法(代碼),有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。
原來為了簡(jiǎn)單方便,自己小網(wǎng)站上的文章頁的相關(guān)內(nèi)容推薦就是從數(shù)據(jù)庫里隨機(jī)抽取數(shù)據(jù)來填充一個(gè)列表,所以一點(diǎn)相關(guān)性都沒有,更本沒有辦法引導(dǎo)用戶去訪問推薦內(nèi)容。
算法選擇
如何能做到相似內(nèi)容的推薦呢,礙于小網(wǎng)站還跑在虛擬主機(jī)上(對(duì)的,連一個(gè)自己完整可控的服務(wù)器都沒有),所以可以想的辦法不多,條件限制在 只能用PHP+MySql。所以我想到的辦法就是通過Tags來匹配相似文章進(jìn)行推薦。如果兩篇文章的TAGS 比較相似
比如:文章A 的TAGS為: [A,B,C,D,E]
文章B 的 TAGS 為:[A,D,E,F,G]
文章C 的 TAGS 為:[C,H,I,J,K]
通過眼睛我們能很方便的發(fā)現(xiàn),文章B和文章A更為相似,因?yàn)樗鼈冇腥齻(gè)關(guān)鍵字相同分別為:[A,D,E],哪如何用計(jì)算機(jī)來判斷它們的相似度呢,這里我們用jaccard相似度的最基本應(yīng)用來計(jì)算它們的相似度
jaccard相似度
給定兩個(gè)集合A,B,Jaccard 系數(shù)定義為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更為相似,有了這個(gè)算法,計(jì)算機(jī)就可以來判斷兩篇文章的相似度了。
具體的推薦思想
給定一篇文章,獲取該文章的關(guān)鍵字TAGS,然后通過以上算法去數(shù)據(jù)庫比對(duì)所有文章的相似度,獲取最相似的N篇文章進(jìn)行推薦。
實(shí)現(xiàn)過程
第一 TAGS的獲取
文章的TAGS是通過TF-IDF算法,提取文章中的高頻詞,選取N個(gè)作為TAGS,對(duì)于中文的文章來說還涉及到一個(gè)中文分詞的問題,因?yàn)槭翘摂M主機(jī)的關(guān)系,這步的工作我用python(為什么用Python ,jieba分詞,真香)在本地寫了一個(gè)程序,完成所有文章的分詞,詞頻統(tǒng)計(jì),生成TAGS,并寫回服務(wù)器的數(shù)據(jù)庫。由于本文是寫推薦的算法,所以分詞和建立TAGS的部分就不具體展開了,而且不同的系統(tǒng)有不同的TAGS建立方式。
第二 TAGS的存儲(chǔ)
建立兩張表,用于存儲(chǔ)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和文章的映身關(guān)系。
+-----------+------------+------+-----+---------+-------+
Field Type Null Key Default Extra
+-----------+------------+------+-----+---------+-------+
id bigint(20) NO PRI 0
articleid bigint(20) YES NULL
tagid int(11) YES NULL
+-----------+------------+------+-----+---------+-------+
tag_map存的數(shù)據(jù)類似如下:
+----+-----------+-------+
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
+----+-----------+-------+
其實(shí)做相似推薦的時(shí)候,只需要用到tag_map表就可以了,因?yàn)閠agid和tag name 是一一對(duì)應(yīng)的。
具體編碼
1.獲取所有文章對(duì)應(yīng)的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,可以一次性查詢所用文章,極其對(duì)應(yīng)的所有tag
在PHP,我們可以把tags變成數(shù)組。
public function getAllGroupByArticleId(){
//緩存查詢數(shù)據(jù),因?yàn)檫@個(gè)是全表數(shù)據(jù),而且不更新文章不會(huì)變化,便是每次推薦都要從數(shù)據(jù)庫里獲取一次數(shù)據(jù),對(duì)性能肯定會(huì)有影響,所以做個(gè)緩存。
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數(shù)組。
$result[$value['articleid']] = explode(",",$value['tags']);
}
CacheHelper::setCache($result, 86400);
return $result;
}
有了這個(gè)的返回結(jié)果,就比較好辦了,接下去的工作就是去應(yīng)用jaccard相似度這個(gè)算法了,具體就看代碼吧。
/**
* [更據(jù)指定文章返回相似的文章推薦]
* @param $articleid 指定的文章ID
* @param $top 要返回的推薦條數(shù)
* @return Array 推薦條目數(shù)組
*/
function getArticleRecommend($articleid, $top = 5){
if($cache = CacheHelper::getCache()){
return $cache;
}
try{
$articleid = intval($articleid);
$m = new TagMapModel();
$all_tags = $m->getAllGroupByArticleId();//調(diào)用上面的函數(shù)返回所有文章的tags
$finded = $all_tags[$articleid];//因?yàn)樯厦媸前形恼铝,所以肯定包含了?dāng)前文章。
unset($all_tags[$articleid]);//把當(dāng)前文章從數(shù)組中刪除,不然自己和自己肯定是相似度最高了。
$jaccard_arr = []; //用于存相似度
foreach ($all_tags as $key => $value) {
$intersect =array_intersect($finded, $value); //計(jì)算交集
$union = array_unique(array_merge($finded, $value)); //計(jì)算并集
$jaccard_arr[$key] = (float)(count($intersect) / count($union));
}
arsort($jaccard_arr); //按相似度排序,最相似的排最前面
$jaccard_keys = array_keys($jaccard_arr);//由于數(shù)組的key就是文章id,所以這里把key取出來就可以了
array_splice($jaccard_keys, $top);//獲取前N條推薦
//到這里我們就已經(jīng)得到了,最相似N篇文章的ID了,接下去的工作就是通過這幾個(gè)ID,從數(shù)據(jù)庫里把相關(guān)信息,查詢出來就可以了
$articleModels = new \Api\Model\ArticleModel();
$recommendArticles = $articleModels->getRecommendByTag($jaccard_keys);
CacheHelper::setCache($recommendArticles, 604800); //緩存7天
return $recommendArticles;
} catch (\Exception $e) {
throw new \Exception("獲取推薦文章錯(cuò)誤");
}
}
相關(guān)推薦:
PHP簡(jiǎn)單實(shí)現(xiàn)“相關(guān)文章推薦”功能的方法
以上就是基于Tags實(shí)現(xiàn)內(nèi)容推薦的方法(代碼)的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注php中文網(wǎng)其它相關(guān)文章!
學(xué)習(xí)教程快速掌握從入門到精通的SQL知識(shí)。