mbleigh / acts-as-taggable-on

A tagging plugin for Rails applications that allows for custom tagging along dynamic contexts.
http://mbleigh.lighthouseapp.com/projects/10116-acts-as-taggable-on
MIT License
4.98k stars 1.2k forks source link

Feature Request: Tag's Closest Neighbors #78

Closed bouchard closed 11 years ago

bouchard commented 14 years ago

Thanks for the great work on this gem, it works wonderfully.

One feature I'm missing that'd I'd like to be considered for implementation is, for lack of a better term, a tag's "closest neighbors".

Given a tag A, what tags B, C, etc. are most commonly associated with a given object along with A?

This would allow for much more intuitive autocomplete on the client side, say if I often tag a user as "unprivileged, beginner, newbie", then:

User.first.nearest_tags("beginner") => [#<ActsAsTaggableOn::Tag id: 2, name: "unprivileged", associations: 6>, #<ActsAsTaggableOn::Tag id: 1, name: "newbie", associations: 4>]

Thoughts?

bouchard commented 14 years ago

I've coded this up - my SQL-fu isn't amazing, the best I could come up with uses two nested queries. Feel free to hack it apart, but it works :)

brady8@586078a3d2b62ec5fe976d2272ae5f291ef18a84

bouchard commented 14 years ago

A better version is up now, with support for arrays or strings of multiple tags (delimited using TagList.delimiter).

brady8@7012685626f66975c863bef0c8ca2c446ac2a9d5

bouchard commented 14 years ago

I've squashed the last two commits, and changed behaviour to include the tags being searched for in the results - my use case for this was with partial tag matching: If you start with 'card', and find all tags that are named_like, say 'cardio', and 'cardiology', then 'cardio' and 'cardiology' should be included in the neighboring_tags array.

Commit is here: brady8@ebbd7e25433b0ad4149127384d9ff0004e9becfc

YavorIvanov commented 12 years ago

Hey have you given up on this?

I can extract some "pseudo code" from our app. It has a tag_relation.rb model which I believe does what you want. Unfortunately it works with some hacking through generating a tag.rb which extends the ActsAsTaggableOn and its in a Rails 2.3.14 app so it uses an older monkey patched version of ActsAsTaggableOn. The result is pretty good though.

Let me know if I can help you with this.

bouchard commented 12 years ago

I should've posted this up in a Gist, as I managed to push to Github and lose my commits when working on an unrelated project.

All I had was a find_neighbouring_tags method added to tag.rb that would do a complicated join query to find the nearest neighbours, based on the frequency that any two tags where tagged on the same model instance together. Should be quite a bit simpler than what you're suggesting?

I'll need this again for a project soon, so I'll give a go a re-implementing it again, unless you'd like to show your work!

YavorIvanov commented 12 years ago

Have you tested the performance of you implementation? I believe we implemented our approach after stumbling on some performance issues. We have couple of tables including the taggings one that are in the millions.

YavorIvanov commented 12 years ago

Yep. Just tested an sql statement. The taggings table has 8M rows so its using a filesort at the end. This is going to be very costly. I'll try to come up with a simpler solution.

bouchard commented 12 years ago

Good points. Let me know if you come up with something, and/or I should hopefully be able to come up with something performant soon.

YavorIvanov commented 12 years ago

I tried decomposing it but no luck for now.

artemk commented 12 years ago

@YavorIvanov looking forward on this

tilsammans commented 11 years ago

It would be a nice feature, but I'm inclined to close it for now.

It seems like something that would be better handled by a full-text engine.

If anyone has thoughts about the implementation, I will gladly reopen it.

trostli commented 7 years ago

Best way to accomplish this IMO is to index the tags in soemthign like Elastic Search and do a similarity query. Check out the great gem Searchkick for this.