2011-09-25 34 views
9

Rails için güçlü Sunspot gem ile bir site arama arama uygulamak çalışıyorum. Bu, aynı anda birden çok farklı model arasında bir arama yapılmasını içerir. Yapmak istediğim şey, kullanıcının arama sonuçlarını her bir modele göre filtrelemesini veya varsayılan olarak tümünün aynı sayfada görüntülenen, birbiriyle uyumlu hale getirilmiş: destekleyici niteleyici tarafından izin vermesini sağlamak için kaplama özelliğini kullanmaktır. Başka bir Stackoverflow question (Sunspot documentation'dan 'Çoklu Tip' kodunun bir varyasyonu) 'dan çoklu model arama koduyla facebook kodunu Sunspot Railscast'dan birleştirmek bana işe yarayacağını düşündüğüm bir çözüm verdi.Raylar Sunspot gem: Birden fazla model site çapında aramaları ile yönleri Kullanıyor

Birden çok yöntem araması başarılı olur, ancak yüzler daima sıfırlanır. Temel yaklaşımım, her modelde aynı ada göre sanal bir özellik sağlamaktır: search_class, yani bir dizeye işlenen modelin sınıf adıdır. Daha sonra bunu bir faset olarak kullanmayı denerim. Ancak, görünüm mantığında, facet'in (search.facet (: search_class) .rows) sonuçları her zaman döndürülmüş her örneğe sahip olsa bile @ search.results aynı sorguda birçok farklı model döndürdüğü zaman da dahil olmak üzere boş bir dizidir. mükemmel erişilebilir Instance.search_class özniteliği.

Rails 3.1.0 ve sunspot rayları kullanıyorum 1.2.1.

Bu faceting kodunun çalışması için ne yapmalıyım?

Denetleyici:

#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 

Modeller:

#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 

Görünüm:

#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

Bunun için neden yüzler kullanıyorsunuz? Tüm olası sınıfların hepsinin sahip olduğu sonuç sayısı ile listelendiği bir seçim menüsü oluşturuyor musunuz? Ardından, arama yöntemini çağırdığınızda, arama için bağımsız değişken olarak ilgili sınıfı dinamik olarak çağırın. –

+0

Verilerinizi yeniden indekslediniz mi? Verilerin güneş lekesi dosyalarında sınıf adı olup olmadığını kontrol ettiniz mi? – Sebastien

cevap

2

Bu

Sunspot.search (Foo, Bar) {ile (:hakkında'); faset (: ad)}

f no'lu tercüme facet(:name) fark varsa solr/log/ solr_production.log dosyası

kesin Solr sorgu bulabilirsiniz Solr

yılında
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 

aşağıdaki şekilde çevrilir. name_s .facet ve değilf.foo.facet and f.bar.facet. Bu yüzden beklediğiniz gibi çalışmadı.

Aşağıdakiler işe yarar, ancak her modelde 3 kukla yöntem oluşturmak için bir tane gerekir. Fikir, her tür için ayrı bir faset çizgisine ihtiyacınız var.

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 

Yine, arama sorunlarını hata ayıklamak için gerçek SOLR sorgu günlüğüne bakmak her zaman daha iyidir. Sunspot birçok şeyi büyülüyor ama sınırlamaları var ;-)