Rails Sunspot gem:使用多模型全站搜索的构面
我正在尝试通过强大的 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
型号:
#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>
I'm trying to implement a sitewide search through the powerful Sunspot gem for Rails. This involves a search across multiple, very different models at once. What I WANT to do is use the faceting feature to allow the user to filter their search results on each model, or by default view all on the same page, interspersed with each other ordered by the :boost qualifier. Combining the faceting code from the Sunspot Railscast with the multiple model searching code from another Stackoverflow question (a variation upon the 'Multiple Type' code from the Sunspot documentation) gave me a solution that I'd think would work, but doesn't.
The multiple method search succeeds, but the facets always turn up null. My basic approach is to provide a virtual attribute on each model by the same name, :search_class, that is just the model's class name rendered into a string. I then try and use that as a facet. However, in the view logic the results of the facet (@search.facet(:search_class).rows) is always an empty array, including when @search.results returns many different models in the same query, despite each returned instance having a perfectly accessible Instance.search_class attribute.
I'm using Rails 3.1.0 and sunspot-rails 1.2.1.
What should I do to make this faceting code work?
Controller:
#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
Models:
#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
View:
#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>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这
在 Solr 中转换为以下内容
您可以在
solr/log/solr_Production.log
文件中找到确切的 Solr 查询如果您注意到
facet(:name) 翻译为 f.
name_s
.facet 和 notf.foo.facet 和 f.bar.facet.
这就是它不起作用的原因正如你所期望的。以下方法可行,但需要在每个模型中创建 3 个虚拟方法。我们的想法是,每种类型都需要一条单独的面线。
同样,最好查看实际的 SOLR 查询日志来调试搜索问题。太阳黑子使许多事情变得神奇,但它也有其局限性;-)
This
translates to the following in Solr
You can find the exact Solr query in the
solr/log/ solr_production.log
fileif you notice
facet(:name)
translated to f.name_s
.facet and notf.foo.facet and f.bar.facet.
That is why it did not work as you expected.The following will work but that needs one to create 3 dummy methods in each model. The idea is you need a separate facet line for each of the types.
Again, it is always better to look at the actual SOLR query log to debug the search issues. Sunspot makes many things magical but it has its limitations ;-)