太阳黑子多面搜索

Sunspot Multi Faceted Search

我正在构建一个 API,它使用 Sunspot 作为后端的搜索引擎并实施分面搜索。我有以下模型来说明我如何为我的所有内容处理许多不同的方面类型:

Contents
  content_name
  searchable_fields

Facets
  facet_name

ContentFacets
  content_id
  facet_id

虽然内容 has_many 方面 content_facets。我已经设法设置好一切,让它作为一个单面搜索工作——因为 API 它 returns 它需要的一切,当前端应用程序发回必要的参数时,它会从那个方面向下钻取,但是,我无法从那里做多个方面。这是我所做的搜索(同样,这是有效的):

#SearchController

facet_id = Facet.find_by_name(params[:commit]).id

@search = Content.search do
    fulltext params[:search]
    with(:facet_ids, facet_id) if params[:commit].present?
    facet(:facet_ids)
    paginate :page => 1, :per_page => 300
end

facets = @search.facet(:facet_ids).rows.map { |row| row.instance.name }

render :json => [facets, @search.results]

然后是配置内容模型:

searchable do
  text :searchable_fields
  integer :facet_ids, :multiple => true, :references => Facet
end

最后,这是在查询我的 API 的前端应用程序上的处理方式:(看起来好像先前的参数正在作为路由本身的参数传回,而submit_tag 中的 :commit 参数决定了具体的方面名称)

<% if @facets %>
  <div id="facets">
  <h3>Given - <%= @search_params %></h3>
  <ul>
    <% @facets.each do |facet| %>
      <%= form_tag facet_path(@search_params), method: "POST" do %>
        <li><%= submit_tag facet %></li>
      <% end %>
    <% end %>
  </ul>
</div>

所以我的问题是:考虑到一切,什么是我将其变成实际的多方面搜索的最佳方式,而不是每次选择一个新方面时只使用一个方面并覆盖它?

对于您的特定问题,以下方法应该有效 -

在您看来,只需将此行添加到 submit_tag 行上方

<li><%= hidden_field_tag :existing_facets, @existing_facets %></li>

然后在您调用 API 之前有一段代码如下:

@existing_facets = ""

        unless facet_params[:existing_facets].nil?
            @existing_facets =  "#{facet_params[:existing_facets]}+#{facet_params[:commit]}"
        end

这将跟踪用户为特定查询选择的所有方面,同时仍将原始搜索参数保留在那里 - 这些参数按顺序存储在字符串中以便于使用,以 + 号分隔。

所以现在在 API 方面,我会将您的搜索代码更改为以下内容:

facets = gather_facets(params[:existing_facets], params[:commit])

@search = Content.search do
    fulltext params[:search]
    facets.each do |facet|
        facet_id = Facet.find_by_name(facet).id
        with(:facet_ids, facet_id)
    end
    facet(:facet_ids)
    paginate :page => 1, :per_page => 300
end

facets = @search.facet(:facet_ids).rows.map { |row| row.instance.name }

render :json => [facets, @search.results]

def gather_facets(existing_str, new_facet)
  arr = existing_str.scan(/([^+]+)/).flatten << new_facet
end

这将跟踪所有选定的方面,按顺序查询它们,并在搜索查询中的迭代问题导致 API 变慢之前缩小自身范围(假设这些方面已完成正确 :P)