tags:

views:

56

answers:

3

Basically I want to setup a tagging system like stack overflow has for entries and trying to plan out how a relevance based search would work. I want to have an option to pull up similar tagged entries for a related entries section. Right now I am using two tables for tags, a table for each unique tag and a join table. I am trying to think if that will work for being able to generate a list of entries that share similar tags.

If anyone has any ideas, or links to articles I could read on it to get my brain heading in the right direction that would be amazing. Thank you!

+1  A: 

add one more field to entities table: tags. with string of comma separated tags, to prevent 2 more joins for selecting entities list.

zerkms
Are you saying to store it in both places, and just use the string for searches of related entries? Right now my plan of having the tags not in the entries table is for quick and easy searches by tag and for the use of auto completion in the tags entry field along with other potential uses.
gokujou
I'm talking about using string ONLY FOR retrieving entities, to make select query much more simple (and fast). Search will be more efficiency by join-table.
zerkms
+1  A: 

Perhaps you could have a separate table to store related entries.

EntryId RelatedEntryId

Then you could have a CRON job recompute the relationships periodically and update the table. It would be less expensive than trying to compute these relationships on the fly.

Stephen Curran
I guess I could do that. Any hint on how to compute those, or just a mass of pulling lists of tags and running simple comparisons on them then storing them to that new table? Thanks!
gokujou
This answer gives an SQL query to find related items based on common tags : http://stackoverflow.com/questions/246841/how-to-find-the-records-with-most-common-tags-like-the-related-questions-in-stac/247041#247041Maybe your CRON job could iterate all entries, compute related entries using this query and store them in your table. I am no expert here so perhaps someone else has a better solution :-)
Stephen Curran
+1  A: 

You'll need to keep track of how often one tag is linked to another. Like, say "php" and "mysql" share 50 articles (or whatever the main content being tagged is), while "php" and "sql-server" might have 3, and "php" and "apache" have 25. So given "php," you'd want to return "mysql" and "apache" in that order (possibly letting "sql-server" fall to the wayside).

No way is this ideal, just thinking out loud (and kind of expanding on stephenc's answer, now that I see it):

CREATE TABLE tag_relations (
tag_id int unsigned not null,
related_tag_id int unsigned not null,
relation_count smallint unsigned not null,
PRIMARY KEY (tag_id, related_tag_id),
KEY relation_count (relation_count)
);

Then for each unique tag tied to an article, loop through all other tags and INSERT / UPDATE, incrementing the relation_count by 1. That means ("php", "mysql") and ("mysql", "php") are two completely different relations to be maintained, but without digging through search concepts I've probably forgotten, it'll still function. If something has 10+ tags, updates will be very slow (maybe pass that to cron like stephenc suggested), but it'll be easier to search this way. Nice and straightforward like so:

SELECT related_tag_id, COUNT(relation_count) AS total_relations
FROM tag_relations
WHERE tag_id IN ([list,of,tag,IDs,to,compare])
// AND tag_id NOT IN ([list,of,tag,IDs,to,compare]) -- probably
GROUP BY related_tag_id
ORDER BY total_relations DESC

Easier than having to check against both tag_id & related_tag_id and sum them up through a mess of subqueries, at least. JOIN on your tags table to get the actual tagnames & you're set.

So if you're looking up "php" and "mysql," and "apache" often relates to both, it'll be near the top since it's counting & weighting each common relation. It won't strictly limit it to common links though, so add HAVING total_relations >= x (x being an arbitrary cutoff) and/or just a regular LIMIT x to keep things relevant.

(note: research the heck out of this before thinking this is even slightly useful - I'm sure there's some known algorithm out there that's 100x smarter and I'm just not remembering it.)

PHPro.org has a good writeup too, using a similar idea.

tadamson