5

如何在 SunSpot Solr 中正确搜索多个模型?

轮廓模型

has_one :match

searchable do
  string        :country
  string        :state
  string        :city
end

匹配模型

belongs_to :profile

searchable do
  string :looking_for_education
  integer :age_from
  integer :age_to
end

ProfilesController#Index

def index
  
  @search = Sunspot.search Profile, Match do

    with(:country, params[:country])
    with(:state,   params[:state])      
    with(:looking_for_education, params[:looking_for_education]) <= from the 2nd model
  end

  @profiles = @search.results

end

这失败了:

 Using a with statement like 
  with(:age).between(params[:age_from]..params[:age_to])
 undefined method `gsub' for nil:NilClass

删除
with(:age).between(params[:age_from]..params[:age_to]) 行然后它尝试

然后它尝试加载

view app/views/educators/educator.html.haml 

不存在(我只使用

/app/views/profiles/_profile.html.haml 

显示个人资料

编辑#1:

有哪些优秀的 ruby​​ on rails 开源项目,它们以更高级的方式使用 sunspot 和 solr 来看看?也许我可以在那里找到答案。如果它产生了这个问题,那么这个方向的任何答案也将被接受赏金,谢谢!

4

4 回答 4

8

The method you've found for searching multiple models is correct. However, it appears that the meaning of your search is not what you intended. It looks as if you're trying to say:

Give me all Profile records with these country and state values, and whose Match record has this looking_for_education value

Your search, however, says:

Give me all records of type Profile or Match that have all of these country, state and looking_for_education values

Because neither Profile nor Match have all of these fields in their respective searchable blocks, no single record can match the conditions you specify.

If I'm correct about your intended behaviour above, then you need to include the profile's associated match information in the profile's searchable block, like so:

class Profile < ActiveRecord::Base
  has_one :match

  searchable do
    string(:country)
    string(:state)
    string(:city)
    string(:looking_for_education) { match.looking_for_education }
    integer(:age_from)             { match.age_from              }
    integer(:age_to)               { match.age_to                }
  end
end

Here, we've told Sunspot to index properties of the profile's match association as if they lived on the profile itself. In the respective blocks, we've told Sunspot how to populate these values when the profile is indexed.

This will allow you to write your search using only the Profile model:

def index
  @search = Sunspot.search Profile do
    with(:country, params[:country])
    with(:state,   params[:state])      
    with(:looking_for_education, params[:looking_for_education])
    with(:age).between(params[:age_from]..params[:age_to])
  end

  @profiles = @search.results
end

This search will return only Profile records, while still reflecting the properties of each profile's match association, because we stored them when the profile was indexed.

Note that this increases complexity when you index your models. If a Match record changes, its associated profile now needs to be reindexed to reflect those changes.

于 2013-09-26T09:32:20.627 回答
4

@moises-zaragoza 正确回答了您的问题,但您想要做的事情比您想象的要多。

第一个错误:

 Using a with statement like 
  with(:age).between(params[:age_from]..params[:age_to])
 undefined method `gsub' for nil:NilClass

最有可能产生是因为 params[:age_from] 和/或 params[:age_to] 为 nil。我不能保证,因为您没有显示堆栈跟踪。只有当它们存在时,您才能通过过滤器进行修复:with(:age).between(params[:age_from]..params[:age_to]) if params[:age_from].present? 和 params[:age_to].present?

第二个错误

与您的观点有关。我假设您正在使用其中一个 rails helper 部分对象帮助程序来渲染集合或对象,而没有指定部分(同样,如果没有代码,这比其他任何事情都更适合猜测):

<%= render @results %>

或者

<% @results.each do |result| %>
  <%= render result %>
<% end %>

当 Rails 没有指定部分时,它会根据对象类型猜测部分名称。在这种情况下,如果您的对象是 Educator 类的例子,它可能是 Profile 的子类,Rails 将查找部分 'eductors/_eductor.html.erb。确保根据对象类型渲染正确的部分,这将确保您渲染您想要的。

于 2013-09-24T17:57:38.947 回答
4

当我必须搜索多个模型时,这就是我正在做的事情

Sunspot.search [Model1, Model2] do
  ....
end
于 2013-09-20T20:27:43.077 回答
2

这里是使用匹配字符串搜索不同模型的答案with

searchable(:auto_index => AppConfig.solr.auto_index) do
  string :category_name, :stored => true
  text :content, :stored => true
  text :title
  string :company_id, :stored => true
  time :published_on
end

search do |q|
  if params[:keyword].present?
    q.fulltext params[:keyword] do
      fields(:deal_data)
    end
  end
  if (ids = params["company_id"]).present?
    ids = ids.split(",")
    q.with(:company_id,ids) #here company id formate should be ["***","***"]
  end
end
于 2014-04-15T11:02:28.237 回答