Rails Sunspot gem: использование фасетов с несколькими моделями поиска по всему сайту
Я пытаюсь внедрить поиск по всему миру через мощный гем Sunspot для Rails. Это включает в себя поиск по нескольким, очень различным моделям одновременно. То, что я ХОЧУ сделать, - это использовать функцию огранки, чтобы позволить пользователю фильтровать свои результаты поиска по каждой модели, или по умолчанию просматривать все на одной и той же странице, перемежаясь друг с другом в соответствии с классификатором:boost. Сочетание ограненного кода из Sunspot Railscast с кодом поиска нескольких моделей из другого вопроса Stackru (вариант кода "Multiple Type" из документации Sunspot) дало мне решение, которое, я думаю, сработало бы, но не работает.
Поиск по нескольким методам завершается успешно, но фасеты всегда обнуляются. Мой основной подход заключается в предоставлении виртуального атрибута для каждой модели с одинаковым именем: search_class, который представляет собой просто имя класса модели, отображаемое в строку. Затем я пытаюсь использовать это как аспект. Однако в логике представления результаты фасета (@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 ответ
Это
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 вы можете найти в solr/log/ solr_production.log
файл
если вы заметили facet(:name)
переведено на ф.name_s
. а не 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 для устранения проблем с поиском. Sunspot делает многие вещи волшебными, но у него есть свои ограничения;-)