>  기사  >  데이터 베이스  >  태그 기반 콘텐츠 추천 구현 방법(코드)

태그 기반 콘텐츠 추천 구현 방법(코드)

不言
不言원래의
2018-09-14 14:11:422374검색

이 글의 내용은 태그를 기반으로 콘텐츠 추천을 구현하는 방법(코드)에 대한 내용입니다. 필요한 친구들이 참고할 수 있기를 바랍니다.

간결함과 편리함을 위해 내 작은 웹사이트의 기사 페이지에 대한 관련 콘텐츠 추천은 데이터베이스에서 무작위로 데이터를 추출하여 목록을 채우는 것이므로 상관관계가 전혀 없으며 사용자에게 추천 콘텐츠에 접근하도록 안내할 방법이 없습니다.

알고리즘 선택

어떻게 유사한 콘텐츠를 추천할 수 있을까요? 소규모 웹사이트가 여전히 가상 호스트에서 실행되고 있기 때문에(예, 완전히 제어할 수 있는 서버도 없습니다) 생각할 수 있는 방법이 많지 않습니다. 조건은 PHP+MySql만 사용하도록 제한됩니다. 그래서 제가 생각한 방식은 태그를 활용해 유사한 기사를 매칭해 추천하는 것이었습니다. 두 기사의 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
태그를 저장하는 두 개의 테이블을 생성합니다.

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

tag_map을 사용하여 태그와 기사 간의 매핑 관계를 설정합니다.

+-----------+------------+------+-----+---------+-------+
| 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 |
+----+-----------+-------+

사실 유사한 추천을 할 때는 tagid와 태그 이름이 일대일 대응이기 때문에 tag_map 테이블만 사용하면 됩니다.

특정 코딩

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을 통해 한 번에 사용되는 모든 기사와 해당 태그를 모두 쿼리할 수 있습니다.
PHP에서는 태그를 배열로 변환할 수 있습니다.

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 \Api\Model\ArticleModel();
            $recommendArticles = $articleModels->getRecommendByTag($jaccard_keys);
            CacheHelper::setCache($recommendArticles, 604800); //缓存7天
            return $recommendArticles;
        } catch (\Exception $e) {
            throw new \Exception("获取推荐文章错误");
        }
    }

관련 추천:

PHP에서 "관련 기사 추천" 기능을 간단하게 구현하는 방법

위 내용은 태그 기반 콘텐츠 추천 구현 방법(코드)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.