この記事は Solr Advent Calendar 2016 の 21日目です。
数値を扱うフィールドに焦点を当てたいと思います。
Solr と言いつつコアとなっている Lucene 側の話がメインですが、きっと大丈夫だと信じています。
Lucene 6.0 から加わった新しい数値フィールド
Lucene 6.0 から、数値を表すフィールドとして、IntPoint
, LongPoint
, FloatPoint
などの「ナンタラPoint」というフィールドが追加されました。それまでに存在していた IntField
, LongField
, FloatField
などの数値フィールドとの違いの一つは、多次元空間における点の座標を表すことができるという点です。例えば、(x, y, z) といった座標をドキュメントに持たせようとしたときに、FloatField
を三つ用意する必要があったところが、FloatPoint
一つで表現できるようになります。
この新しいフィールドは昔のフィールドをただ束ねたものではなく、レンジによる検索や距離による検索が速くできるような工夫が施されています。
Point 系のフィールドは通常の転置インデックスの構造はとっておらず、k-d tree をベースとした構造になっています(正確に言うと Block k-d tree という構造をとっています)。Lucene の実装では、切り分けられた空間の中で最も幅が広くなる次元を選択し、その次元の中央値となる点を通るようにさらに空間を切り分ける、ということを再帰的に繰り返します。切り分けた空間の中で点の数がある程度まで少なくなったらそこで切り分けるのをやめます。こうすることで、空間を木構造に分けたうえで、点の密度が高いところは細かく、点の密度が低いところは粗く分割されるようになっています。
ある領域に含まれる点を検索する際は、木の根ノード(空間全体)から、子ノード(分割された空間)に向かってたどっていき、調べたい領域とノードの対応する領域が重なっている場合は探している点が存在する可能性があるということを利用していきます。調べたい領域にノードの対応する領域がすっぽりと包まれている場合はそのノードの先は全てヒットした点ということになるので、いちいち全ての点を調べることなく検索が実現できます。
と、ここまで文字だけで説明を書いてきましたが、何だか小難しくなってしまったので、次のElastic社のブログの記事の中の動画を見ると良いかと思います。
https://www.elastic.co/blog/lucene-points-6.0
Block k-d tree を利用した検索の様子を可視化した動画が貼ってあります。k-d tree がどんなものか何となく感じ取れるのではないでしょうか。ちなみに上の記事は dimensonal points の紹介記事で、本記事もこちらの内容を大いに参考にして書いています。
多次元の座標をドキュメントに入れることはないので、あまり関係のない話だと思う方もいらっしゃるかもしれませんが、そうとも言い切れません。二次元でも一次元でも、以前の数値フィールドに比べて検索・更新ともに速く、インデックスサイズ・ヒープ使用量も小さくなっているという結果が、先ほどの Elastic 社のブログ記事に記されています(ブラウザによっては一部の図が見られなくなっているようです)。この記事は Lucene 6.0 が出たころのものですが、その後も Point のインデックス構造の改善は進められている(LUCENE-7371、LUCENE-7563)ので、さらに圧縮率や速度などは良くなっているかもしれません。
一方 Solr は・・・
さて、ここまで Lucene に加わった数値フィールドの良さを紹介してきましたが、Solr Advent Calendar なので Solr の数値フィールドの話をします。
残念ながら、Solr では Point 系のフィールドは利用されていません。 (v6.3.0 時点)
Solr 側のフィールドであるところのTrieIntField
や TrieFloatField
などは、Lucene の旧式の数値フィールドを使い続けています。ちなみに 5 系までは IntField
, FloatField
というような名前だった旧式のフィールド達は 6.0 でその名前を LegacyIntField
, LegacyFloatField
に変えられ、7.0 からはパッケージも org.apache.lucene.document
から org.apache.lucene.legacy
に移される予定となっており、なかなか憂き目にあっています。
Solr 側も何も対応していないというわけではなく、Point 良さそうだから使ってみよう、というチケットは上がっていて、たまに更新されています。
https://issues.apache.org/jira/browse/SOLR-8396
Lucene 側としては旧式のフィールドを使わせない方向に動いているので、きっと Solr 側もそのうち対応してくれることでしょう。
まとめ
本記事のまとめです。
- Lucene の新しい数値フィールド
*Point
は「多次元、速い、小さい」といいことずくめ - 現状だと Solr は昔の数値フィールドのまま
Solr を利用している人にとってはあまり役に立たない内容になってしまい恐縮ですが、いつか Solr の数値フィールドが Point 系に移行したときに薄ぼんやりと思い出していただければ幸いです。