Introduzione ai tag

La catalogazione tramite tag, con i suoi pregi, i suoi difetti, i suoi limiti e le sue potenzialità sta molto emergendo con l'avvento del così detto Web 2.0, ed è sempre più spesso il sistema adottato dai blog e dai sistemi di catalogazione folksonomica. La differenza concettuale di una catalogazione a tag rispetto ad una più "tradizionale", è che in questo tipo di catalogazione non ci sono gerarchie, ma relazioni. Ma qual'è la struttura di un database non gerarchico? E come si possono ricavarne relazioni? In questo articolo, dal taglio molto pratico, cercheremo di introdurre questo argomento.

Sommario:

Le tabelle

Semplificando, una struttura di tabelle di database per gestire una catalogazione tramite tag potrebbe essere come la seguente. La tabella posts, con i contenuti da catalogare:

post_id content
1 Un post su SQL, tags e PHP.
2 Un post su come creare una nuvola di tag con PHP e CSS.
3 Un menu carino con i CSS...

La tabella tags, con l'elenco dei tag utilizzati:

tag_id tag
1 SQL
2 PHP
3 Tags
4 CSS
5 Menu

La tabella posts2tags che mette in relazioni i post con i relativi tag associati:

rel_id post_id tag_id
1 1 1
2 1 2
3 1 3
4 2 2
5 2 3
6 2 4
7 3 4
8 3 5

Tag associati al contenuto

Riferendoci alle tabelle appena viste, la query per ricavare i tag associati al post con post_id uguale ad 1 è:

SELECT tags.tag 
FROM posts, tags, posts2tags 
WHERE posts2tags.post_id = posts.post_id 
 AND posts2tags.tag_id = tags.tag_id 
 AND posts2tags.post_id = 1 
ORDER BY tags.tag

Contenuti associati ai tag

Ricavare i contenuti associati ai tag è un po' più complicato, se i tag sono più di uno. Con la seguente query selezioneremo tutti i post associati al tag "SQL" e "tags":

SELECT posts.post_id, posts.content 
FROM posts, tags, posts2tags 
WHERE posts2tags.post_id = posts.post_id 
 AND posts2tags.tag_id = tags.tag_id 
 AND tags.tag IN ('SQL', 'tags') 
GROUP BY posts.post_id 
HAVING COUNT( posts2tags.post_id ) = 2

Come abbiamo detto, la query seleziona i post associati al tag SQL o a tags (tags.tag IN ('SQL', 'tags')) e, per restingere la selezione ai post associati ad entrambi i tag, anzichè ad uno soltanto, seleziona solo i post che appaiono 2 volte (HAVING COUNT( posts2tags.post_id ) = 2). 2 perché i tag sono 2, se i tag fossero stati tre sarebbe stato HAVING COUNT( posts2tags.post_id ) = 3 e così via...

Tag correlati

Quando si mostrano i post legati ad uno o più tag, è tipico mostrare anche i tag correlati a quelli correnti. Per individuarli, una volta selezionati gli ID dei contenuti (nel nostro caso i post_id) associati ai tag correnti, come descritto nel punto precedente, si avrà una query come questa:

SELECT tags.tag 
FROM tags, posts2tags 
WHERE posts2tags.tag_id = tags.tag_id 
 AND posts2tags.post_id IN (1,2) 
 AND tags.tag NOT IN ('SQL','tags') 
GROUP BY posts2tags.tag_id 
ORDER BY tags.tag

La query seleziona tutti i tag associati ai contenuti correnti (i post con post_id 1 e 2, in questo caso) escludento i tag "SQL" e "tags", dato che, essendo i tag correnti, sarebbe inutile mostrarli come tag correlati. DISTINCT serve per eliminare i "dopioni" ed avere solo l'elenco dei tag diversi tra loro.

Contenuti correlati

Per selezionare i contenuti che hanno più tag in comune con il contenuto corrente si può utilizzare una query come questa:

SELECT posts.*, count(posts2tags.post_id) as num 
FROM posts, tags, posts2tags 
WHERE posts2tags.post_id = posts.post_id 
 AND posts2tags.tag_id = tags.tag_id 
 AND tags.tag IN ('SQL','tags') 
 AND posts.post_id != 1 
GROUP BY posts2tags.post_id 
ORDER BY num DESC, content DESC

Con questa query abbiamo ottenuto i post ordinati in base al numero di tag in comune con il post corrente (quello con post_id uguale ad 1, in questo caso).

Ottimizzazione

Per ottimizzare lo schema o vederne di alternativi, potete far riferimento all'articolo sul Wiki MySQL Forge: TagSchema, in particolare alla sezione Recommended Architecture.