関口宏司のLuceneブログ

OSS検索ライブラリのLuceneおよびそのサブプロジェクト(Solr/Tika/Mahoutなど)について
スポンサーサイト

一定期間更新がないため広告を表示しています

| スポンサードリンク | - | | - | - |
LUCENE-6819: Good bye index-time boost

Lucene/Solr 7.0 のリリースの投票がまもなく始まろうとしている。

今回私が気になっているのが、LUCENE-6819 による修正である。
Deprecate index-time boosts?
https://issues.apache.org/jira/browse/LUCENE-6819

タイトルだけ見ると、「インデクシング時ブースト(重み付け)を止めよう」、もっと深読みすると「クエリ時に重み付けが指定できるからインデクシング時に重み付けしなくてもいんじゃね?」ととらえてしまう方もいるかもしれない。もちろん、インデクシング時重み付けとクエリ時重み付けでは、大きく意味や目的が異なる。[1]

本記事では、LUCENE-6819 と関連する他の修正と合わせ、Lucene 7.0 以降で fieldNorm がどのようになるか、簡単に解説しよう。

LUCENE-6819

このチケットでは、タイトル通り、インデクシング時のboostを止めよう、というものである。もう少し細かく言うと、fieldNorm という、各ドキュメントの各フィールド(ただし、omitNorms=trueのフィールドを除く)ごとに1バイトでエンコーディングされた値の、次の式からboostを取り除こう、というものである。

fieldNorm = lengthNorm * boost

ちなみにこの式は、BM25Similarity が登場する以前の、Lucene/Solr の標準であったベクトル空間モデルによるランキング計算(各ドキュメントのクエリに対する類似度計算)に強く依存している。Lucene/Solr はコサイン類似度ベースだが、上のように計算された fieldNorm を加味しており、BM25 で考慮されている文書長はとっくに加味されている。[2]

さて、これからboostを除けば、次のようになる。

fieldNorm = lengthNorm

lengthNorm はデフォルトで次のように計算される。

lengthNorm = 1 / sqrt(numTerms)

numTermsは当該フィールドの単語数である。したがって、lengthNorm は単語数が1の時は 1 / sqrt(1) = 1 / 1 = 1、単語数が2の時は 1 / sqrt(2) = 1 / 1.414213562373095… = 0.70710678118655、という具合になるので、0 < lengthNorm <= 1 となる。しかし、Lucene 6.x 以前では、boost が lengthNorm にかかった fieldNorm を保存しなければならず、boost の値はユーザの設定次第なので最悪 Float.MAX_VALUE になってしまうことも考えられる。そこで 0 から Float.MAX_VALUE の広大な値域をわずか1バイトにマッピングしているのが Lucene 6.x である(下図)。

LUCENE-6819

しかし、ほとんどのユーザーはインデクシング時重み付けなどしないので、上図グレーの部分がもったいない。boostがかけられる可能性を考えて1バイトの半分を残しているのだが、ほとんどのユーザーはboost=1なので、非常にもったいない、かつ、低精度な使い方になっている。

そこで、LUCENE-6819 では:

  • Lucene 6.x では boost 設定と参照に係わる API は @deprecated とし、boostに1でない値が投入されようとすると、「将来バージョンで使えなくなる」旨の警告が表示される。
  • Lucene 7.0 では、boost 設定と参照に係わる API から boost 引数を取り除き、fieldNorm には lengthNorm そのものが記録されるようになった。
という修正が行われた。

LUCENE-7730

LUCENE-6819 ではまだ fieldNorm の1バイトが有効活用されていない。そこでこのチケットでは、フィールド長(単語数)をSmallFloat.intoTobyte4(numTerms)でエンコードして保存するように修正された。たとえば単語数が1000のときは、SmallFloat.intoTobyte4(1000)が87となり、これが記録される。デコードにはSmallFloat.byte4ToInt()が使われる。SmallFloat.byte4ToInt(87)は984となる。ちなみに、1〜40はエンコードしても1〜40を出力する(変わらない)。長さ41から徐々にエンコードによる誤差が大きくなる(下図)。

LUCENE-7730

Lucene 6.x では boost / sqrt(numTerms) の計算結果が1バイトに圧縮されて記録されていたが、Lucene 7.0以降では numTerms がそのままエンコードされて1バイトに記録される。もはや BM25Similarity が標準なので、1 / sqrt(numTerms) を計算する意味自体がない、ということだ。

Lucene/Solr 7.0 以降も omitNorms 指定は相変わらず有効である。

ロンウイットの社内勉強会で説明に使用したスライドも公開しているので、合わせて読んで欲しい。







[1] ロンウイット主催のトレーニングコース「Solr基礎」では、このような大事な基礎を丁寧に教えています。お申し込みはこちらから

[2] ロンウイット主催のトレーニングコース「Apache Mahout & Sparkではじめる機械学習」では、機械学習のさまざまなモデルやアルゴリズムを丁寧に解説しています。ベーシックな機械学習の解説にとどまらず、本記事にあるような、検索エンジンのランキングの元になるスコア計算の考え方なども含み、ソフトウェア開発の実際の現場で役に立つ内容を網羅しています。お申し込みはこちらから

| 関口宏司 | Luceneインデックス | 10:41 | comments(0) | trackbacks(0) |
+ Solrによるブログ内検索
+ PROFILE
  12345
6789101112
13141516171819
20212223242526
2728293031  
<< August 2017 >>
+ LINKS
検索エンジン製品 - 比較のポイント
商用検索エンジンを購入した企業担当者は読まないでください。ショックを受けますから・・・
>>製品比較 10のポイント
+ Lucene&Solrデモ
+ ThinkIT記事
+ RECOMMEND
Apache Solr入門 ―オープンソース全文検索エンジン
Apache Solr入門 ―オープンソース全文検索エンジン (JUGEMレビュー »)
関口 宏司,三部 靖夫,武田 光平,中野 猛,大谷 純
+ RECOMMEND
Lucene in Action
Lucene in Action (JUGEMレビュー »)
Erik Hatcher,Otis Gospodnetic,Mike McCandless
FastVectorHighlighterについて解説記事を寄稿しました。
+ RECOMMEND
+ SELECTED ENTRIES
+ RECENT COMMENTS
+ RECENT TRACKBACK
+ CATEGORIES
+ ARCHIVES
+ MOBILE
qrcode
+ SPONSORED LINKS