近接検索 (proximity search) とは,複数のキーワードからなるクエリで検索する際,ドキュメント中でキーワードがどれだけ近接して出現するかを考慮して検索する手法です.
Solrでは,以下の例のように,フレーズに出現間の距離の最大値を指定して検索することができます.
text:"テスト クエリ"~10
(Lucene query の場合)
ここで最大値を slop,slop が指定されたフレーズを sloppy フレーズと呼びます.
この例では,テストの出現とクエリの出現の間に,無関係な出現が10個まであってもマッチします.(また,後述しますが,先にクエリが出現する場合,そこからテストの出現までの間に,無関係な出現が8個まであってもマッチします.)
この機能については,例えば公式の Solr Relevancy FAQ に紹介されています.
しかし,細かい挙動についてまとめたドキュメントがあまり見つからなかったので,挙動を調べてまとめてみました.Solr 6.3.0 を使用しています.
例のコレクションは以下の通りです.トークンがわかりやすいよう分かち書きしてあります.
body_txt_ja
テスト ドキュメント
テスト 用 ドキュメント
Alpha Beta Zeta Zeta Gamma
Alpha Zeta Beta Zeta Gamma
Alpha Zeta Zeta Beta Gamma
ドキュメント テスト
テスト 用 ダミー ドキュメント
ストップ ワード テスト
ストップ ワード の テスト
近接性がスコアに影響する
近接性は,マッチするか否かの判断だけでなく,スコアにも影響します.
近接して出現するドキュメントのほうが,離れて出現するドキュメントよりも高スコアになります.
具体的には,無関係な出現の数を距離とおくと,フレーズの出現は1 /(距離 + 1)
回の出現として扱われるので,距離によってスコアに差が出ます.
body_txt_ja:"テスト ドキュメント"~1
と BM25 スコアリング関数の例:
"response":{"numFound":2,"start":0,"maxScore":1.3883159,"docs":[
{
"body_txt_ja":"テスト ドキュメント",
"score":1.3883159},
{
"body_txt_ja":"テスト 用 ドキュメント",
"score":0.74605227}]
}
前者の距離は0,後者は1です.
例のスコアリング関数は BM25 です.ドキュメント長による正規化やスコアの非線形な丸めがあるため,最終的なスコアは出現回数に比例はしません.
ちなみに,debugQuery にするとスコアリングの経過が詳しくわかります.
距離 = マッチの長さ - キーワード数
上述の距離ですが,マッチした部分の長さ - その部分が含むキーワードの出現の数
と考えることができます.
ですので,二キーワード間の距離は両キーワードの出現間の無関係な出現の数となり,直感的です.
また,三キーワード間の距離は,第一キーワードと第二キーワード間の距離と,第二キーワードと第三キーワード間の距離の和です.
body_txt_ja:"Alpha Beta Gamma"~2
の例:
"response":{"numFound":3,"start":0,"maxScore":1.1809129,"docs":[
{
"body_txt_ja":"Alpha Beta Zeta Zeta Gamma",
"score":1.1809129},
{
"body_txt_ja":"Alpha Zeta Beta Zeta Gamma",
"score":1.1809129},
{
"body_txt_ja":"Alpha Zeta Zeta Beta Gamma",
"score":1.1809129}]
}
この例では,いずれも距離2です.
語順の入れ替わりもマッチする
語順の入れ替わりは,前者の語から後者の語の直後の距離,あるいは後者の語から前者の語の直前の距離を考え,距離2とします.
body_txt_ja:"テスト ドキュメント"~2
の例:
"response":{"numFound":4,"start":0,"maxScore":1.3883159,"docs":[
{
"body_txt_ja":"テスト ドキュメント",
"score":1.3883159},
{
"body_txt_ja":"テスト 用 ドキュメント",
"score":0.74605227},
{
"body_txt_ja":"ドキュメント テスト",
"score":0.70354825},
{
"body_txt_ja":"テスト 用 ダミー ドキュメント",
"score":0.54773456}]
}
三番目のドキュメントがヒットしています.ちなみに,四番目のドキュメントよりも上位に来ているのは,ドキュメント長による正規化のためです.
ストップワードも出現にカウントする
どちらかというとフレーズの性質かもしれませんが,ストップワードも出現にカウントします.
body_txt_ja:"ストップ ワード テスト"~1
の例:
"response":{"numFound":2,"start":0,"maxScore":3.0475318,"docs":[
{
"body_txt_ja":"ストップ ワード テスト",
"score":3.0475318},
{
"body_txt_ja":"ストップ ワード の テスト",
"score":1.9441152}]
}
前者の距離は0,後者は1です.