chr*_*isk 9 solr ruby-on-rails sunspot faceted-search sunspot-rails
我正在尝试通过强大的Sunspot gem for Rails实现全站搜索.这包括一次搜索多个非常不同的模型.我想要做的是使用分面功能允许用户在每个模型上过滤他们的搜索结果,或者默认查看同一页面上的所有内容,并通过:boost限定符排序.将来自Sunspot Railscast的分面代码与来自另一个Stackoverflow问题的多个模型搜索代码(来自Sunspot文档的"多种类型"代码的变体)结合起来,给了我一个我认为可行的解决方案,但却没有.
多方法搜索成功,但小平面总是变为空.我的基本方法是在每个模型上使用相同的名称提供虚拟属性: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
Run Code Online (Sandbox Code Playgroud)
楷模:
#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
Run Code Online (Sandbox Code Playgroud)
视图:
#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>
Run Code Online (Sandbox Code Playgroud)
这
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
同样,最好查看实际的 SOLR 查询日志来调试搜索问题。太阳黑子使许多事物变得神奇,但它也有其局限性;-)