Elasticsearchで、包含してるデータをソートの項目に使う

私の環境
Mac OSX Yosemite
Ruby 2.2.2
Rails 4.2.1

まだElasticsearchと戦っています。
リレーション先とのデータ連携とかまではまだわかってないのですが、今のところはデータの取り込みの際にリレーション先を含める方法を取っています。そのリレーションのデータを包含するときにmappingする際のやり方がよくなかったようで、包含したデータを使ってソートすることができませんでしたが、解決したので書き方を載せておきます。

gem elasticsearch-modelを使っています。

変更前

ここでは、Shopモデルと、Companyモデルがあるという前提とします。
変更前は、mappingでindexを定義する際に、company.nameのように書いていました。

class Shop < Activerecord::Base
  include Elasticsearch::Model
  # index_nameは省略
  settings index: {
    # 省略
  } do
    mapping do
      indexes :name,
              type: 'string',
              index: :analyzed,
              analyzer: :kuromoji_analyzer
      indexes :yomigana,
              type: 'string',
              index: :analyzed,
              analyzer: :ngram_analyzer,
              fields: {
                  raw: {
                      type: 'string',
                      index: :not_analyzed
                  }
              }
      indexes :'company.name', type: 'string', index: :analyzed, analyzer: :kuromoji_analyzer
      indexes :'company.yomigana',
              type: 'string',
              index: :analyzed,
              analyzer: :ngram_analyzer,
              fields: {
                  raw: {
                      type: 'string',
                      index: :not_analyzed
                  }
              }
    end
  end

  def as_indexed_json
    as_json(
        include: {
            company: { only: [:name, :yomigana] }
        }
    )
  end
end

この状態で、ソートの条件としてcompany.yomigana.rawと指定しても、うまく機能しませんでした。

そこでelasticsearch-modelのソースコードを読んでみたところ、indexesメソッドにブロックが渡せることがわかったので、試してみることにしました。

変更後

indexesのネストで定義します。
ネストすると、companyをobjectとして定義するので、ソートの項目として使えるようになるようです(詳細なところはよくわかってません…)。

class Shop < Activerecord::Base
  include Elasticsearch::Model
  # index_nameは省略
  settings index: {
    # 省略
  } do
    mapping do
      indexes :name,
              type: 'string',
              index: :analyzed,
              analyzer: :kuromoji_analyzer
      indexes :yomigana,
              type: 'string',
              index: :analyzed,
              analyzer: :ngram_analyzer,
              fields: {
                  raw: {
                      type: 'string',
                      index: :not_analyzed
                  }
              }
      indexes :company do
        indexes :name, type: 'string', index: :analyzed, analyzer: :kuromoji_analyzer
        indexes :yomigana,
                type: 'string',
                index: :analyzed,
                analyzer: :ngram_analyzer,
                fields: {
                    raw: {
                        type: 'string',
                        index: :not_analyzed
                    }
                }
      end
    end
  end

  def as_indexed_json
    as_json(
        include: {
            company: { only: [:name, :yomigana] }
        }
    )
  end
end

その後、ソートしてみたところ、うまくいきました。

{ 
  query: {
    # その他の検索条件
  },
  sort: [{
    :'company.yomigana.raw' => :asc
  }]
}

やりたいことが大分できてきました。


カテゴリー Ruby, Ruby on Rails | タグ | パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です