Облако тегов на PHP

Теги (ярлыки) — один из способов структурирования материала сайта. Веб-мастер при добавлении публикации на сайт присваивает ей несколько тегов — ключевых слов, которые позволяют понять ее тематику. Впоследствии на сайте возможен отбор и поиск материала по тегам.

Некоторые теги повторяются у различных статей, такие теги становятся популярными. На этом сайте, допустим, были бы популярны теги PHP и HTML.

Облако тегов — это блок с определенным количеством самых популярных тегов сайта. При чем, чем популярнее тег, тем больше визуально он выглядит в облаке.

Хранение тегов в базе данных

Для начала определимся, каким образом можно хранить теги для статей в базе данных. Просто хранить теги через запятую в текстовом поле для каждой статьи — плохое решение, так как реализация построения облака и поиска по тегам будет очень сложной и медленной. Самый оптимальный способ, я считаю — это связь "многие ко многим" между таблицами статей и тегов при помощи промежуточной таблицы.

В простейшем случае мы имеем таблицу со статьями articles следующей структуры:

id | alias | title | text

Таблица с тегами tags может выглядеть так:

id | alias | title

Поля alias нужны для создания читаемых URL с участием этих элементов (например /articles/hello, вместо использования числового идентификатора /articles/13).

Для установления связи между статьями и тегами создается промежуточная таблица articles_tags:

id | article_id | tag_id

В ней каждая запись описывает связь какого-то тега с какой-то статьей. Таким образом, любой из тегов может быть присвоен нескольким статьям. Нужно продумать алгоритм заполнения таблиц при добавлении новой публикации, но это уже выходит за пределы темы данной статьи.

Реализация облака тегов

Итак, предположим, что мы имеем вышеописанные три таблицы с заполненными данными. Нам нужно определить самые популярные теги и построить по ним облако. При помощи переменной зададим количество тегов, которое будет отображено в облаке:

$tags_count = 30; //--Кол-во тегов в облаке

Далее необходимо составить SQL-запрос для получения самых популярных тегов. Выглядеть он может следующим образом:

SELECT tags.title              AS title, 
       tags.alias              AS alias, 
       COUNT(tags_articles.id) AS cnt 
FROM   tags 
       INNER JOIN articles_tags
         ON ( articles_tags.tag_id = tags.id ) 
GROUP  BY tags.id 
ORDER  BY cnt DESC 
LIMIT  %tags_count%

В результате запрос возвратит таблицу с %tags_count% самых популярных тегов следующей структуры:

заголовок тега | алиас тега | количество упоминаний

Теги в ней будут отсортированы по популярности. В таком порядке построенное облако будет выглядеть не очень красиво, поэтому рекомендую отсортировать теги по заголовкам. Это можно сделать как на PHP, так и в момент запроса, доработав немного SQL-запрос:

SELECT * 
FROM   (SELECT tags.title              AS title, 
               tags.alias              AS alias, 
               COUNT(tags_articles.id) AS cnt 
        FROM   tags 
               INNER JOIN articles_tags
                 ON ( articles_tags.tag_id = tags.id ) 
        GROUP  BY tags.id 
        ORDER  BY cnt DESC 
        LIMIT  %tags_count%) AS subq
ORDER  BY title

Итак, у нас имеется список самых популярных тегов. Теперь необходимо отобразить их с разной величиной (размером шрифта) в зависимости от популярности. Критерием популярности служит параметр cnt (количество упоминаний). Но использовать этот параметр как размер шрифта нельзя. Во-первых, в большой базе он будет иметь большие значения. Во-вторых, у тегов эти параметры могут сильно отличаться, нарисовать один тег в тысячу раз больше другого — плохая идея.

Объявим две переменные, задающие минимальный и максимальный размер шрифта в облаке тегов:

$min_real = 8;  //--Минимальный размер тега (8pt)
$max_real = 22; //--Максимальный размер тега (22pt)

Предположим, что результат выполненного SQL-запроса хранится в переменной ret. Далее необходимо определить минимальное и максимальное значение параметра cnt:

$min_db = 999999;
$max_db = 0;
 
foreach ($ret as $tag)
{
    $min_db = min($min_db, $tag['cnt']);
    $max_db = max($max_db, $tag['cnt']);
}

Для чего все это нужно? Допустим, в результате выполнения запроса мы получили пять самых популярных тегов с параметрами cnt (значениями популярности) соответственно: 500, 170, 40, 111, 22. Нам необходимо отобразить эти теги шрифтом размером от 8 (min_real) до 22 (max_real). Мы определили максимальное (max_db = 500) и минимальное (min_db = 22) значения популярности. Для определения размера шрифта, которым необходимо отобразить тег со значением популярности cnt воспользуемся формулой:

(cnt - min_db) / (max_db - min_db) * (max_real - min_real) + min_real

В общем, сплошная математика. Даже она иногда пригождается в сайтостроении.

Код построения облака тегов, в итоге, может выглядеть примерно так:

$tagsarr = array();
foreach ($ret as $tag)
{
    $tagsarr[] = sprintf('<a style="font-size: %dpt;" title="%d" href="/articles/?tag=%s">%s</a>',
                         $min_db == $max_db ? $min_real : ( ($tag['cnt'] - $min_db) / ($max_db - $min_db) * ($max_real - $min_real) + $min_real ),
                         $tag['cnt'],
                         $tag['alias'],
                         $tag['title']
                 );
}
echo implode(', ', $tagsarr);

Участок

$min_db == $max_db ? $min_real : ...

описывает частный случай, когда максимальное и минимальное значение популярности равны, то есть все теги имеют одинаковую популярность. В этом случае отображаем их минимальным размером шрифта. Удачного кодинга!

Комментарии

Оставить комментарий »

 
Joker-jar
16 марта 2012, 17:24
#1
 

Кстати, есть в планах внедрение облака тегов на MyFirstSite. В комментариях на странице о проекте уже подымался вопрос о недостаточно удобной системе навигации по сайту.

sanina
9 августа 2012, 9:51
#2
 

Я сделал по другому немного исключил промежуточную таблицу хранения посчитал их не нужными

cblock_tags таблица хранения тегов и к чему они принадлежат
id_element это id новости tag текстовое значения тега например "Союз" группировку сделал по названию тега

id_cblock_g это как бы сказать группа категории новостей

cblock_element это таблица новостей id_element инкремент таблицы

$sql = "SELECT * 
				FROM   ( SELECT ct.tag, COUNT(ce.id_element) AS cnt 
						 FROM   cblock_tags ct 
							   INNER JOIN  cblock_element ce ON ( ce.id_element = ct.id_element AND ce.id_cblock_g = ".intval($group_id)." ) 
						GROUP BY  ct.tag
						ORDER  BY cnt DESC 
						LIMIT  ".$limit." ) AS subq
				ORDER  BY tag ASC";

при добавлении тега вставляется текст через запятую который через JS разбивается крассива использовал jQuery TegInput унего есть также погрузка вариантов тегов через ajax

sadex
21 июня 2013, 16:36
#3
 

Неплохой подход, мне понравился. На этом сайте облако тегов на основе этого скрипта реализовано?

Joker-jar
24 июня 2013, 14:25
#4
 

sadex, да, на нем.

bermuda
30 июня 2013, 14:46
#5
 

Можно примеры базы данных самый минимум пожалуйста!

Joker-jar
1 июля 2013, 2:26
#6
 

bermuda, ну я показал в статье примерную логическую структуру таблиц.

bermuda
1 июля 2013, 19:24
#7
 

хорошо это уже неважно.
Вот я вывел список тегов допустим названия тегов

original-mix
remix

а адрес этих тегов

www.site.ru/tags/original-mix/
www.site.ru/tags/remix/

то есть получается так что в корне сайта должна быть папка tags в которой есть папки original-mix и remix и в каждой из них еще по файлу index.php так?

или лучше осуществить таким образом?

www.site.ru/index.php?tags=original-mix
www.site.ru/index.php?tags=remix

Joker-jar
4 июля 2013, 1:16
#8
 

А, я понял. Нет, никакой папки tags не нужно, сами URL-адреса формируются при помощи механизмов, о которых можно почитать здесь:

http://www.myfirstsite.ru/qna/16
http://www.myfirstsite.ru/qna/2

bermuda
4 июля 2013, 17:32
#9
 

спасибо буду разбираться

vitalik-758153
27 июля 2013, 1:28
#10
 

Неплохой подход, мне понравился

Оставить комментарий

Ваше имя
 
Ваш e-mail
 
Комментарий