私はこれを自分で解決しました。私が使用した解決策は、必要なスコープを文字列としてコンパイルし、それらを連結してから、検索ブロック内で評価することでした。
これには、存在しないインデックスフィールドのスコープが作成されないようにするために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
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
そして、誰かがそれを必要とする場合は、ソート可能性をチェックしてください:
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