2011-09-25 28 views
9

Tôi đang cố triển khai tìm kiếm trên toàn trang web thông qua đá quý Sunspot mạnh mẽ cho Rails. Điều này liên quan đến việc tìm kiếm trên nhiều mô hình rất khác nhau cùng một lúc. Những gì tôi muốn làm là sử dụng tính năng faceting để cho phép người dùng lọc kết quả tìm kiếm của họ trên mỗi mô hình, hoặc theo mặc định xem tất cả trên cùng một trang, xen kẽ với nhau theo thứ tự bởi: vòng loại tăng. Kết hợp mã faceting từ Sunspot Railscast với mã tìm kiếm nhiều mô hình từ một mã khác Stackoverflow question (biến thể khi mã 'Nhiều Loại' từ Sunspot documentation) đã cho tôi giải pháp mà tôi nghĩ là sẽ hoạt động, nhưng không.Rails Sunspot gem: Sử dụng các khía cạnh với nhiều tìm kiếm trên toàn trang web mô hình

Tìm kiếm nhiều phương pháp thành công, nhưng các khía cạnh luôn bật lên null. Cách tiếp cận cơ bản của tôi là cung cấp một thuộc tính ảo trên mỗi mô hình bằng cùng một tên,: search_class, đó chỉ là tên lớp của mô hình được kết xuất thành một chuỗi. Sau đó tôi thử và sử dụng nó như một khía cạnh. Tuy nhiên, trong logic xem các kết quả của các khía cạnh (@ search.facet (: search_class) .rows) luôn luôn là một mảng trống, bao gồm khi @ search.results trả về nhiều mô hình khác nhau trong cùng một truy vấn, mặc dù mỗi thể hiện được trả về có một thuộc tính Instance.search_class có thể truy cập hoàn toàn.

Tôi đang sử dụng Rails 3.1.0 và sunspot-ray 1.2.1.

Tôi nên làm gì để làm cho mã faceting này hoạt động?

Bộ điều khiển:

#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 

Xem:

#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

Tại sao bạn sẽ sử dụng các khía cạnh cho điều này? Bạn không thể chỉ cần tạo ra một menu lựa chọn, nơi tất cả các lớp có thể được liệt kê với số lượng kết quả tất cả đều có? Sau đó, khi bạn gọi phương thức tìm kiếm, tự động gọi lớp liên quan làm đối số cho tìm kiếm? –

+0

Bạn đã nhập lại dữ liệu của mình chưa? Và bạn đã kiểm tra xem liệu các dữ liệu có tên lớp trong các tập tin vết đen mặt trời? – Sebastien

Trả lời

2

này

Sunspot.search (Foo, Bar) {với (: về, 'a'); khía cạnh (: tên)}

dịch như sau trong 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 

Bạn có thể tìm thấy các truy vấn Solr chính xác trong solr/log/ solr_production.log tập tin

nếu bạn nhận thấy facet(:name) dịch sang f. name_s .facet và khôngf.foo.facet and f.bar.facet. Đó là lý do tại sao nó không hoạt động như bạn mong đợi.

Sau đây sẽ làm việc nhưng cần một để tạo 3 phương pháp giả trong mỗi mô hình. Ý tưởng là bạn cần một đường nét riêng cho từng loại.

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 

Một lần nữa, hãy xem nhật ký truy vấn SOLR thực tế để gỡ lỗi các vấn đề tìm kiếm. Sunspot làm cho nhiều điều huyền diệu nhưng nó có những hạn chế của nó ;-)

Các vấn đề liên quan