疑問文

PythonとかRubyについて、疑問や学びをまとめる場所

勉強しないと。しないと。

Solrでアルファベット順にソートする

Solrの検索結果をアルファベット順で上手にソートすることができず
日本語で検索してもなかなか参考になるものがなかったのでまとめ。

参考
SOLR 4.0 alphabetical sorting trouble - Stack Overflow

背景

今回は例として、ex_nameフィールドでindexingされている
aaaAAAbbbBBBの4つの文字列を使います。
アルファベット順にソートしたいので、求める結果は以下の通り。
ascかdescの指定が必要ですが、今回は重要じゃないので割愛)

aaa
AAA
bbb
BBB

ですが、単純にソートを指定すると以下のような結果になります。

AAA
BBB
aaa
bbb

文字コードにして並べた結果
小文字のaより大文字のBが優先されたんでしょうか。
この躓きを回避するための記事です。

環境

Solr 4.6.1(たぶん)

解決法

Solrにソート用のフィールドを追加します。
まず、scheme.xmlでソートに使うフィールドのfieldTypeを設定。

<fieldType name="alphaOnlySort" class="solr.TextField" sortMissingLast="true" omitNorms="true">
    <analyzer>
        <tokenizer class="solr.KeywordTokenizerFactory"/>
        <filter class="solr.LowerCaseFilterFactory"/>
        <filter class="solr.TrimFilterFactory"/>
        <filter class="solr.PatternReplaceFilterFactory" replace="all" replacement="" pattern="([^a-z])"/>
    </analyzer>
</fieldType>

ザックリ中身を解説すると

<filter class="solr.LowerCaseFilterFactory"/>` 

でフィールドに含まれる大文字をすべて小文字に変換し

<filter class="solr.TrimFilterFactory"/>

でフィールド内の値の前後に含まれる空白を除去し

<filter class="solr.PatternReplaceFilterFactory" replace="all" replacement="" pattern="([^a-z])"/>` 

でアルファベットのa〜z以外のすべて文字列を置換(削除)しています。

要するに、フィールド間の比較をすべて小文字で行うためのフィールドを作るわけですね。
次にソート用のフィールドを追加します。

<field name="sort_ex_name" type="alphaOnlySort" indexed="true" stored="false" multiValued="false" />

最後に、ex_namesort_ex_nameにコピーして完了。

<copyField source="ex_name" dest="sort_ex_name" />

この際に前述の3つのフィルタが動作し、ソート用に値を書き換えるようです。

これを保存して再度データをインポートした後に
sort_ex_nameでsortをすると、求めていた結果にたどり着けます。

まとめ

結果的に泥臭い方法になっている気がするけど、これでいいんだろうか。
あと、アルファベット以外(数字や記号)が先頭のものをどう扱うか。

ちなみにalphaOnlySortというフレーズが

  • Solrとして定義された語なのか
  • 暗黙の了解的に使われてる語なのか

がわからずに実装中は悶々としていたのですが、「Apache Solr入門」曰く

SolrコミュニティではStrFieldのような組み込みの非テキスト系フィールド型の名前は習慣によって決められた名前が広く使われており〜独自名称を付けるのはお勧めしません

ということだそうで。何でもいいけどこの方がいい、なのかな。
今回は場当たり的に実装してるので、これからもっと勉強します。