3

私はElasticSearchをタイヤジェムと一緒に使用して、サイトの検索機能を強化しています。必要な結果を得るためにデータをマッピングおよびクエリする方法を理解するのに問題があります。

関連するコードは以下のとおりです。その下にも、望ましいアウトバットについて説明します。

# models/product.rb

class Product < ActiveRecord::Base
  include Tire::Model::Search
  include Tire::Model::Callbacks

  has_many :categorizations
  has_many :categories, :through => :categorizations
  has_many :product_traits
  has_many :traits, :through => :product_traits

  mapping do
    indexes :id, type: 'integer'
    indexes :name, boost: 10
    indexes :description, analyzer: 'snowball'
    indexes :categories do
      indexes :id, type: 'integer'
      indexes :name, type: 'string', index: 'not_analyzed'
    end
    indexes :product_traits, type: 'string', index: 'not_analyzed'
  end

  def self.search(params={})

    out = tire.search(page: params[:page], per_page: 12, load: true) do
      query do
        boolean do

          must { string params[:query], default_operator: "OR" } if params[:query].present?
          must { term 'categories.id', params[:category_id] } if params[:category_id].present?

          # if we aren't browsing a category, search results are "drill-down"
          unless params[:category_id].present?
            must { term 'categories.name', params[:categories] } if params[:categories].present?
          end
          params.select { |p| p[0,2] == 't_' }.each do |name,value|
            must { term :product_traits, "#{name[2..-1]}##{value}" }
          end

        end
      end

      # don't show the category facets if we are browsing a category
      facet("categories") { terms 'categories.name', size: 20 } unless params[:category_id].present?
      facet("traits") {
        terms :product_traits, size: 1000 #, all_terms: true
      }

      # raise to_curl
    end

    # process the trait facet results into a hash of arrays
    if out.facets['traits']
      facets = {}
      out.facets['traits']['terms'].each do |f|
        split = f['term'].partition('#')
        facets[split[0]] ||= []
        facets[split[0]] << { 'term' => split[2], 'count' => f['count'] }
      end
      out.facets['traits']['terms'] = facets
    end

    out
  end

  def to_indexed_json
    {
      id: id,
      name: name,
      description: description,
      categories: categories.all(:select => 'categories.id, categories.name, categories.keywords'),
      product_traits: product_traits.includes(:trait).collect { |t| "#{t.trait.name}##{t.value}" }
    }.to_json
  end

end

上記のように、「product_traits」フィールドから必要なものを取得するために、elasticsearchとの間でデータの前処理/後処理を行っています。これは正しくないと感じていることであり、私の質問の出所です。

私は製品の大規模なカタログを持っており、それぞれに素材ブランドなどのいくつかの「特徴」があります。これらの特性は非常に多様であるため、特定の製品の特性の値を保持するProductTraitモデルを介して製品モデルに関連する特性モデルを含むようにデータをモデル化しました。

最初の質問は次のとおりです。これらの特性に適切にインデックスを付けるためにelasticsearchマッピングを作成するにはどうすればよいですか?これにはネストされたタイプが含まれていると思いますが、ドキュメントを理解するのに十分な意味がありません。

2番目の質問:ファセットをグループに戻したい(上記の方法の最後で処理している方法で)が、各特性に対して現在選択されている値を考慮せずに、search一致する数を反映するカウントを使用する例:ユーザーが「Glitter」を検索してから「BlueColor」ファセットに対応するリンクをクリックした場合、すべての「Color」ファセットを表示したままにし 、「BlueColor」フィルターなしでクエリ結果に対応するカウントを表示します。 。それが良い説明であることを願っています。さらに明確にする必要がある場合は申し訳ありません。

4

1 に答える 1

21

特性を次のようにインデックス付けする場合:

[
    {
        trait: 'color', 
        value: 'green'
    },
    {
        trait: 'material', 
        value: 'plastic'
    }
]

これは、内部的に次のようにインデックス付けされます。

{
    trait: ['color', 'material' ],
    value: ['green', 'plastic' ]
}

つまり、withvalue'color trait'とwithvalueを持つドキュメントのみをクエリできvalueますgreentraitとの間に関係はありませんvalue

この問題を解決するには、いくつかの選択肢があります。

単一の用語として

あなたがすでに行っている最初のものであり、それは良い解決策です。つまり、次のような単一の用語として特性を保存します。

['color#green`','material#plastic']

オブジェクトとして

別の方法(トレイト名の数が限られていると仮定)は、それらを次のように保存することです。

{
    traits: {
        color:    'green',
        material: 'plastic'
    }
}

traits.color次に、またはに対してクエリを実行できますtraits.material

ネストされたものとして

配列構造を保持したい場合は、ネストされた型を使用できます。例:

{
   "mappings" : {
      "product" : {
         "properties" : {

            ... other fields ...

            "traits" : {
               "type" : "nested",
               "properties" : {
                  "trait" : {
                     "index" : "not_analyzed",
                     "type" : "string"
                  },
                  "value" : {
                     "index" : "not_analyzed",
                     "type" : "string"
                  }
               }
            }
         }
      }
   }
}

各特性/値のペアは、個別の(ただし関連する)ドキュメントとして内部的にインデックス付けされます。つまり、特性とその値の間に関係があります。それらをクエリするには、ネストされたクエリまたはネストされたフィルターを使用する必要があります。例:

curl -XGET 'http://127.0.0.1:9200/test/product/_search?pretty=1'  -d '
{
   "query" : {
      "filtered" : {
         "query" : {
            "text" : {
               "name" : "my query terms"
            }
         },
         "filter" : {
            "nested" : {
               "path" : "traits",
               "filter" : {
                  "and" : [
                     {
                        "term" : {
                           "trait" : "color"
                        }
                     },
                     {
                        "term" : {
                           "value" : "green"
                        }
                     }
                  ]
               }
            }
         }
      }
   }
}
'

ファセット、フィルタリング、ネストされたドキュメントの組み合わせ

たとえば、ユーザーがフィルターをかけたときに、color == green結果をどこcolor == greenにのみ表示したいが、それでもすべての色のカウントを表示したいということです。

これを行うには、フィルタリングされたクエリではなく、検索APIfilterのパラメータを使用する必要があります。フィルター処理されたクエリは、ファセットを計算する前に結果をフィルターで除外します。パラメータは、ファセットの計算後にクエリ結果に適用されます。filter

これは、最終的なクエリ結果がドキュメントに限定されている例ですcolor == greenが、ファセットはすべての色について計算されています。

curl -XGET 'http://127.0.0.1:9200/test/product/_search?pretty=1'  -d '
{
   "query" : {
      "text" : {
         "name" : "my query terms"
      }
   },
   "filter" : {
      "nested" : {
         "path" : "traits",
         "filter" : {
            "and" : [
               {
                  "term" : {
                     "trait" : "color"
                  }
               },
               {
                  "term" : {
                     "value" : "green"
                  }
               }
            ]
         }
      }
   },
   "facets" : {
      "color" : {
         "nested" : "traits",
         "terms" : { "field" : "value" },
         "facet_filter" : {
            "term" : {
               "trait" : "color"
            }
         }
      }
   }
}
'
于 2012-09-21T13:16:45.037 に答える