6

Railsアプリをacts_as_solrの使用からsunspotに変換しています。

このアプリは、acts_as_solrで公開されたsolrのフィールド検索機能を使用します。次のようなクエリ文字列を指定できます。

title:"The thing to search"

タイトルフィールドでその文字列を検索します。

黒点に変換する際に、クエリ文字列のフィールド固有の部分を解析しているので、検索ブロックを動的に生成する必要があります。このようなもの:

Sunspot.search(table_clazz)do
  キーワード(first_string、:fields =>:title)
  キーワード(second_string、:fields =>:description)

  ..。
  paginate(:page => page、:per_page => per_page)      
終わり

これは、期間(秒、整数)の範囲と、クエリで必要な場合は否定を実行する必要があるため、複雑になります。

現在のシステムでは、ユーザーはタイトル内の何かを検索できます。ただし、別のフィールドに他の何かがあるレコードを除外し、期間でスコープを設定します。

一言で言えば、これらのブロックを動的に生成するにはどうすればよいですか?

4

3 に答える 3

4

私は最近instance_eval、Sunspot検索ブロックのコンテキストでproc(他の場所で作成された)を評価するためにこの種のことを行いました。

利点は、これらのprocをアプリケーションのどこにでも作成できるにもかかわらず、黒点検索ブロック内にいるかのように同じ構文で記述できることです

特定のケースを開始するための簡単な例を次に示します。

def build_sunspot_query(conditions)
  condition_procs = conditions.map{|c| build_condition c}

  Sunspot.search(table_clazz) do
    condition_procs.each{|c| instance_eval &c}

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

def build_condition(condition)
  Proc.new do
    # write this code as if it was inside the sunspot search block

    keywords condition['words'], :fields => condition[:field].to_sym
  end
end

conditions = [{words: "tasty pizza", field: "title"},
              {words: "cheap",       field: "description"}]

build_sunspot_query conditions

ちなみに、必要に応じて、別のproc内でprocをinstance_evalすることもできます(私の場合、任意にネストされた'および'/'または'条件を作成しました)。

于 2012-05-18T18:45:45.487 に答える
2

Sunspotは、Sunspot.new_searchと呼ばれるメソッドを提供します。このメソッドを使用すると、検索条件を段階的に作成して、オンデマンドで実行できます。

Sunspotのソースコードによって提供される例:

search = Sunspot.new_search do
  with(:blog_id, 1)
end
search.build do
  keywords('some keywords')
end
search.build do
  order_by(:published_at, :desc)
end
search.execute

# This is equivalent to:
Sunspot.search do
  with(:blog_id, 1)
  keywords('some keywords')
  order_by(:published_at, :desc)
end

この柔軟性により、クエリを動的に構築できるはずです。また、次のように、メソッドに一般的な条件を抽出できます。

def blog_facets
  lambda { |s|
    s.facet(:published_year)
    s.facet(:author)
  }
end

search = Sunspot.new_search(Blog)
search.build(&blog_facets)
search.execute
于 2015-10-06T20:35:57.790 に答える
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

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
于 2012-05-15T22:47:25.790 に答える