前提条件
Elasticsearch + kuromoji
Ruby/Rails
前回の記事では、カタカナで検索するところまででした。
今回はカタカナで並び替え(ソート、sort)します。
前回の条件のまま、ソートの条件としてヨミガナ昇順、降順を指定したら、順番がめちゃくちゃになりました。おそらく文字コード順になってるのかなぁと推測しましたが、まぁわかりません。
追記: ここから
analyzerで分割した結果の中から採用されるそうです。詳しくはコメントをみてください。
追記: ここまで
そこで、なんかいい方法ないかなぁと調査していたら、本家のコードにありました。
elastic: String Sorting and Multifields
fieldsのrawに設定をすればよいようです。
"tweet": { "type": "string", "analyzer": "english", "fields": { "raw": { "type": "string", "index": "not_analyzed" } } }
実験的に、これに合わせてfieldsを設定してみました。
省略されている箇所のコードを見たい人は前回の記事を見てください。
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 } } end end end
その後、ソートしてみたところ、うまくいきました。
{ query: { # その他の検索条件 }, sort: [{ :'yomigana.raw' => :asc }] }
やっと多少Elasticsearchの気持ちがわかってきたかな、というところです。
まだまだ分からないところだらけですが…。
前回の読みのフィールドでソートしたらおかしかったという話ですが、
Elasticsearchは内部で、文字列をある特定の条件で単語に分割しています。
分割する役割がanalyzerです。
で、このanalyzerが分割した単語を内部で検索に利用しています。
この分割された単語がソートにも利用されます。
「ヒロシマ」は「ヒロ」「ヒロシ」「ロシ」「ロシマ」「シマ」という感じです。
で、この分割された単語ですが、順序を保持しません。
このデータを使って、ソートすると、これらの単語のうちソートに利用される値が「シマ」が採用されます。ソート対象のフィールドが複数のデータを持っている場合は(minがデフォルト)その中の一つが採用されます。なので、おかしくなるのかと。
参照:https://www.elastic.co/guide/en/elasticsearch/guide/current/multi-fields.html#multi-fields
詳しい解説ありがとうございます!
分割された単語が使われるんですね…。
分割前のほうがいいということでしたら、analyzedを指定していましたが、not_analyzedを指定するのが正しそうですね。
変更しておきました。