2011-09-25 9 views
9

Próbuję zaimplementować wyszukiwanie w sieci przez potężny klejnot Sunspot dla Rails. Obejmuje to wyszukiwanie w wielu, bardzo różnych modelach jednocześnie. Co chcę zrobić, to użyć funkcji faceting, aby umożliwić użytkownikowi filtrowanie wyników wyszukiwania w każdym modelu lub domyślnie wyświetlać wszystkie na tej samej stronie, przeplecione między sobą, zamawiane przez kwalifikator: boost. Połączenie kodu facetingowego z Sunspot Railscast z kodem wyszukiwania wielu modeli z innego Stackoverflow question (odmiana kodu "wiele typów" z Sunspot documentation) dało mi rozwiązanie, które według mnie działałoby, ale nie działa.Klejnot szyny Sunspot: fasety użytkowania z wieloma modelami wyszukiwania w całym serwisie

Wyszukiwanie wielu metod powiedzie się, ale fasety zawsze zwracają wartość null. Moje podstawowe podejście polega na dostarczeniu wirtualnego atrybutu dla każdego modelu o tej samej nazwie: search_class, czyli tylko nazwa klasy modelu przekształcona w ciąg znaków. Następnie próbuję użyć tego jako aspekt. Jednak w logice widoku wyniki aspektu (@ search.facet (: search_class) .rows) są zawsze pustą tablicą, w tym gdy @ search.results zwraca wiele różnych modeli w tym samym zapytaniu, mimo że każda zwrócona instancja ma doskonale dostępny atrybut Instance.search_class.

Używam Rails 3.1.0 i szyny Sunspot 1.2.1.

Co należy zrobić, aby ten kod facetingowy działał?

kontrolera:

#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 

Modele:

#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 

Widok:

#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> 
+0

Dlaczego używałbyś do tego faset? Czy możesz po prostu stworzyć menu wyboru, w którym znajdują się wszystkie możliwe klasy z liczbą wszystkich wyników? Następnie, gdy wywołasz metodę wyszukiwania, dynamicznie wywołaj powiązaną klasę jako argument do wyszukiwania? –

+0

Czy ponownie wyindeksowałeś swoje dane? Czy sprawdziłeś, czy dane w nazwie zbioru słonecznego mają nazwę klasy? – Sebastien

Odpowiedz

2

Ten

Sunspot.search (Foo Bar) {z (:na temat'); facet (: name)}

przekłada się na następujące w 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 

można znaleźć dokładny zapytania Solr w pliku

solr/log/ solr_production.log jeśli zauważy facet(:name) tłumaczone na f. name_s .facet i nief.foo.facet and f.bar.facet. Dlatego nie zadziałało zgodnie z oczekiwaniami.

Poniższe będą działać, ale jeden z nich wymaga utworzenia 3 fałszywych metod w każdym modelu. Chodzi o to, że potrzebujesz osobnej linii aspektu dla każdego z typów.

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 

Ponownie, zawsze lepiej jest spojrzeć na aktualny dziennik zapytań SOLR, aby usunąć problemy z wyszukiwaniem. Sunspot sprawia, że ​​wiele rzeczy jest magicznych, ale ma swoje ograniczenia ;-)

Powiązane problemy