如何在太阳黑子中动态构建搜索块?

Ric*_*lse 6 sunspot sunspot-rails

我正在使用acts_as_solr将Rails应用程序转换为太阳黑子.

该应用程序使用在acts_as_solr中公开的solr中的字段搜索功能.你可以给它一个像这样的查询字符串:

title:"The thing to search"
Run Code Online (Sandbox Code Playgroud)

它会在标题字段中搜索该字符串.

在转换为太阳黑子时,我正在解析查询字符串的字段特定部分,我需要动态生成搜索块.像这样的东西:

Sunspot.search(table_clazz) do
  keywords(first_string, :fields => :title)
  keywords(second_string, :fields => :description)

  ...
  paginate(:page => page, :per_page => per_page)      
end

如果查询需要,还需要执行持续时间(秒,整数)范围和否定,这很复杂.

在当前系统上,用户可以在标题中搜索某些内容,不包括在其他字段中包含其他内容的记录,并按持续时间确定范围.

简而言之,如何动态生成这些块?

Ric*_*lse 1

我自己已经解决了这个问题。我使用的解决方案是将所需的范围编译为字符串,连接它们,然后在搜索块内评估它们。

这需要一个单独的查询构建器库来询问 solr 索引,以确保不会为不存在的索引字段创建范围。

该代码非常适合我的项目,而且太长,无法完整发布,但这就是我所做的:

1. 拆分搜索词

这给了我一个术语或术语加字段的数组:

['field:term', 'non field terms']

2. 这被传递到查询构建器。

构建器根据可用索引将数组转换为范围。此方法是一个示例,它采用模型类、字段和值,并在字段已建立索引时返回范围。

def convert_text_query_to_search_scope(model_clazz, field, value)
  if field_is_indexed?(model_clazz, field)
    escaped_value = value.gsub(/'/, "\\\\'")
    "keywords('#{escaped_value}', :fields => [:#{field}])"
  else
    ""
  end
end
Run Code Online (Sandbox Code Playgroud)

3.加入所有范围

生成的范围被连接起来join("\n")并被eval编辑。

这种方法允许用户选择他们想要搜索的模型,并且可以选择进行特定领域的搜索。然后,系统将仅搜索具有任何指定字段(或公共字段)的模型,而忽略其余字段。

检查字段是否被索引的方法是:

# based on http://blog.locomotivellc.com/post/6321969631/sunspot-introspection
def field_is_indexed?(model_clazz, field)
  # first part returns an array of all indexed fields - text and other types - plus ':class'
  Sunspot::Setup.for(model_clazz).all_field_factories.map(&:name).include?(field.to_sym)
end
Run Code Online (Sandbox Code Playgroud)

如果有人需要它,请检查可排序性:

def field_is_sortable?(classes_to_check, field)
  if field.present?
    classes_to_check.each do |table_clazz|
      return false if ! Sunspot::Setup.for(table_clazz).field_factories.map(&:name).include?(field.to_sym)
    end
    return true
  end
  false
end
Run Code Online (Sandbox Code Playgroud)