Rails太阳黑子宝石:使用多个模型全站点搜索的Usings方面

时间:2011-09-25 00:53:15

标签: ruby-on-rails solr sunspot faceted-search sunspot-rails

我正在尝试通过强大的Sunspot gem for Rails实现全站搜索。这包括一次搜索多个非常不同的模型。我想要做的是使用分面功能允许用户在每个模型上过滤他们的搜索结果,或者默认查看同一页面上的所有内容,并通过:boost限定符排序。将Sunspot Railscast中的分面代码与来自另一个Stackoverflow question的多个模型搜索代码(来自Sunspot documentation的“多种类型”代码的变体)结合起来,给了我一个解决方案认为会起作用,但不会。

多方法搜索成功,但方面总是变为空。我的基本方法是在每个模型上使用相同的名称提供虚拟属性:search_class,这只是模型的类名称呈现为字符串。然后我尝试将其用作一个方面。但是,在视图逻辑中,facet(@ search.facet(:search_class).rows)的结果始终是一个空数组,包括@ search.results在同一查询中返回许多不同的模型,尽管每个返回的实例都有一个完全可访问的Instance.search_class属性。

我正在使用Rails 3.1.0和sunspot-rails 1.2.1。

如何使这个分面代码有效?

控制器:

#searches_controller.rb
class SearchesController < ApplicationController

  def show
    @search = search(params[:q])
    @results = @search.results
  end

  protected
  def search(q)
    Sunspot.search Foo, Bar, CarlSagan do
      keywords q
      #provide faceting for "search class", a field representing a pretty version of the model name
      facet(:search_class)
      with(:search_class, params[:class]) if params[:class].present?
      paginate(:page => params[:page], :per_page => 30)
    end
  end

end

型号:

#Foo.rb
class Foo < ActiveRecord::Base
  searchable do
    text :full_name, :boost => 5
    text :about, :boost => 2
    #string for faceting
    string :search_class
  end

  #get model name, and, if 2+ words, make pretty
  def search_class
    self.class.name#.underscore.humanize.split(" ").each{|word| word.capitalize!}.join(" ")
  end
end

#Bar.rb
class Bar < ActiveRecord::Base
  searchable do
    text :full_name, :boost => 5
    text :about, :boost => 2
    #string for faceting
    string :search_class
  end

  #get model name, and, if 2+ words, make pretty
  def search_class
    self.class.name.underscore.humanize.split(" ").each{|word| word.capitalize!}.join(" ")
  end
end

#CarlSagan.rb
class CarlSagan < ActiveRecord::Base
  searchable do
    text :full_name, :boost => 5
    text :about, :boost => 2
    #string for faceting
    string :search_class
  end

  #get model name, and, if 2+ words, make pretty
  def search_class
    self.class.name#.underscore.humanize.split(" ").each{|word| word.capitalize!}.join(" ")
  end
end

查看:

#searches/show.html.erb
<div id="search_results">
<% if @results.present? %> # If results exist, display them

            # If Railscasts-style facets are found, display and allow for filtering through params[:class]
    <% if @search.facet(:search_class).rows.count > 0 %>
        <div id="search_facets"> 
          <h3>Found:</h3>  
          <ul>  
            <% for row in @search.facet(:search_class).rows %>  
              <li>  
                <% if params[:class].blank? %>  
                  <%= row.count %>  <%= link_to row.value, :class => row.value %>
                <% else %>  
                  <strong><%= row.value %></strong> (<%= link_to "remove", :class => nil %>)  
                <% end %>  
              </li>  
            <% end %>  
          </ul>  
        </div>
    <% end %>


    <% @results.each do |s| %>
        <div id="search_result">
            <% if s.class.name=="Foo"%>
                <h5>Foo</h5>
                <p><%= link_to s.name, foo_path(s) %></p>
            <% elsif s.class.name=="Bar"%>
                <h5>Bar</h5>
                <p><%= link_to s.name, bar_path(s) %></p>
            <% elsif s.class.name=="CarlSagan"%>
                <h5>I LOVE YOU CARL SAGAN!</h5>
                <p><%= link_to s.name, carl_sagan_path(s.user) %></p>
            <% end %>
        </div>
    <% end %>

<% else %>
    <p>Your search returned no results.</p>
    <% end %>
</div>

1 个答案:

答案 0 :(得分:2)

这个

  

Sunspot.search(Foo,Bar){with(:about,'a');小刻面(:名称)}

转换为Solr中的以下内容

INFO: [] webapp=/solr path=/select params={facet=true&start=0&q=*:*&f.name_s.facet.mincount=1&facet.field=name_s&wt=ruby&fq=type:(Foo+OR+Bar)&fq=about_s:a&rows=30} hits=1 status=0 QTime=1 

您可以在solr/log/ solr_production.log文件

中找到准确的Solr查询

如果您发现facet(:name)已翻译为f。name_s。facet和 f.foo.facet and f.bar.facet.这就是为什么它无法正常工作的原因。

以下内容可行但需要在每个模型中创建3个虚拟方法。我们的想法是为每种类型都需要一个单独的构面线。

Sunspot.search Foo, Bar, CarlSagan do
  keywords q
  #provide faceting for "search class", a field representing a pretty version of the model name
  facet(:foo)
  facet(:bar)
  facet(:carlsagan)
  with(:search_class, params[:class]) if params[:class].present?
  paginate(:page => params[:page], :per_page => 30)
end

同样,查看实际的SOLR查询日志以调试搜索问题总是更好。太阳黑子使许多东西变得神奇,但它有其局限性; - )