Question

I installed Sphinx and Thinking Sphinx for ruby on rails 2.3.2.

When I search without conditions search works ok. Now, what I'd like to do is filter by tags, so, as I'm using the acts_as_taggable_on plugin, my Announcement model looks like this:

class Announcement < ActiveRecord::Base

  acts_as_taggable_on :tags,:category

  define_index do
    indexes title, :as => :title, :sortable => true
    indexes description, :as => :description, :sortable => true
    indexes tags.name, :as => :tags
    indexes category.name, :as => :category

    has category(:id), :as => :category_ids
    has tags(:id), :as => :tag_ids
  end

For some reason, when I run the following command, it will bring just one announcement, that has nothing to do with what I expect. I've got many announcements, so I expected a lot of results instead.

Announcement.search params[:announcement][:search].to_s, :with => {:tag_ids => 1}, :page => params[:page], :per_page => 10

I guess something is wrong, and it's not searching correctly.

Can anyone give my a clue of what's going on?

Thanks, Brian

Was it helpful?

Solution

Thinking Sphinx relies on associations in model. In common situations you only have to put index definition below your associations.

With acts_as_taggable_on plug-in you don't have tag-related associations in model file and when you write

indexes tags.name, :as => :tags

TS interprets it like:

CAST(`announcements`.`name` AS CHAR) AS `tags`

(look at sql_query in development.sphinx.conf, in my case). I suppose that you have attribute name in model Announcement and don't run into error when rebuild index.

But we expect:

CAST(GROUP_CONCAT(DISTINCT IFNULL(`tags`.`name`, '0') SEPARATOR ' ') AS CHAR) AS `tags`

and:

LEFT OUTER JOIN `taggings` ON (`announcements`.`id` = `taggings`.`taggable_id`)  
LEFT OUTER JOIN `tags` ON (`tags`.`id` = `taggings`.`tag_id`) AND taggings.taggable_type = 'Announcement'

To get things working just add tag-related associations in your model before you rebuild index:

class Announcement < ActiveRecord::Base

  acts_as_taggable_on :tags,:category

  has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "ActsAsTaggableOn::Tagging",
            :conditions => "taggings.taggable_type = 'Announcement'"
  #for context-dependent tags:
  has_many :category_tags, :through => :taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag",
          :conditions => "taggings.context = 'categories'"

In define_index method:

indexes category_tags(:name), :as => :tags
has category_tags(:id), :as => :tag_ids, :facet => true

In controller:

@announcement_facets = Announcement.facets params[:search], :with => {:tag_ids => [...]} 
@announcements = @announcement_facets.for.paginate( :page => params[:page], :per_page => 10 )

OTHER TIPS

I found that simply defining the index thus:

Class Thing < ActiveRecord::Base    

acts_as_taggable

     define_index do
        ..other indexing...
        indexes taggings.tag.name, :as => :tags
     end
end

worked fine.

One possibility is that you need to declare the type for tag_ids as :multi because TS can get confused (I just discovered this here http://groups.google.com/group/thinking-sphinx/browse_thread/thread/9bd4572398f35712/14d4c1503f5959a9?lnk=gst&q=yanowitz#14d4c1503f5959a9).

But why not use the tag names to search? E.g.,

Announcement.search params[:announcement][:search].to_s, :conditions => {:tags => "my_tag"}, :page => params[:page], :per_page => 10

Or, if you need to search for multiple tags:

Announcement.search( "#{params[:announcement][:search].to_s} (@tags my_tag | @tags your_tag)", :page => params[:page], :per_page => 10 )

(as aside, you may want to sanitize/remove sphinx-control-characters from the user-provided query before using it).

For debugging, I would go into console and strip down your query as much as possible (eliminate pagination arguments, even the query (just do ""), etc.).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top