いつもSolrのコードを調べては忘れ、調べては忘れているので、とりあえずここ見ると過去に調べたことはまとまってるよっていうメモ。
※ それ間違ってるよというものがあればご指摘ください。
fqとfilter cacheについて
fqはfilter cacheが有効になっている場合、それぞれのfqパラメータで独立に検索を行う。
それぞれのfqパラメータで検索し、それぞれのパラメータごとでfilter cacheにドキュメントの集合を保存している。
そしてfqたちで積集合を取り、最後にqパラメータのクエリと積集合を取る。
(fqでマッチするドキュメントが少ないものを起点に積集合は取ってくれる)
なのでSQLのwhereの感覚で 「他のfqの条件で絞られるから問題ない」 とはならない
おそらくキャッシュヒット率を上げるためにこうなっている。
なので、よくセットで指定しているfqは、一つのクエリパラメータにまとめたほうが早くなる(はず)
ちなみに
fq={!cache=false}key1:val1
このように、明示的にcache=false
とすることで、qとマージされて検索することができる。
その時は、qをMUST、fqをFILTERとしたBooleanQuery
として検索される。
fqとPostFilterについて
SolrはJavaで書かれているので、fqやqで指定したクエリは何らかのクラスのインスタンスになるが、fqのQueryにはPostFilter interface
を実装したQueryを指定することができる。
PostFilterを実装しているのは、 {!frange}
や、{!collapse}
などのクエリである。
こいつらは何かというと、その名の通りフィルタの後に実行されるクエリのクラス。
そしてfrangeやcollapseのようなクエリを指定すると、たとえfilter cacheが有効になっていても内部でcacheを切ってクエリを実行する。
そのため、newSearcherなどでcache warmingしようと思っていても、collapseはキャッシュされないので意味がない。
またfqでは、{!cache=false}
のようにキャッシュを使用しないことを明示的に指定できるが、同時にcost
パラメータも指定することができる。
fq={!cache=false cost=100}key1:val1
そしてcostが100以下の場合、costが100以下のPostFilterのみでcost順にソートされ、順に評価される。
ただし気をつける必要があるのが、1つ目のfqで検索されたドキュメントに対して2つ目のfqで検索されるのではなく、あるドキュメントに対して、一致するまで順番にfqを見るという点。
これは、キャッシュ対象としないfqをcost順にソートした後、一つのQueryクラスに変換しているためである。
上述のfrangeやcollapseは、内部でcostが100に設定されているので、ドキュメントに対してPostFilterが順に適用される。
こういった仕組みにより、重い処理をフィルタした後の少ないドキュメント数に対して実行できるようになっている。
collapseの仕組み
collapseは、PostFilterを実装していて、PostFilterはこのようなメソッドを持っている必要がある。
public DelegatingCollector getFilterCollector(IndexSearcher indexSearcher)
戻り値のDelegatingCollectorは、別のCollectorに処理を委譲できるCollectorのクラス。
このクラスは、処理が終わったときに呼ばれるvoid finish()
を持っている。
collapseでは、以下のような流れで処理される。
-
collect()
が呼ばれる - 内部で持ってるMap(DynamicMap)にputする(同じキーなら一つにまとめられる)
-
finish()
が呼ばれると、Mapを順に見て、それで後続のcollectorのcollect()
を呼ぶ
Mapに入れるかどうか(collapseでまとめるものの代表とするか)は、GroupHeadSelectorによって判断される。
個人的には、Mapで実現っていう割とイメージ通りでびっくりした。
expandの仕組み
collapseしたものを、expandできる。
expandは、ExpandComponent
として実装されていて、Componentをまたぐときは、検索結果がdocList(ドキュメントIDの一覧)としてしか取得できない。
そのため、collapseに指定したフィールドで再度検索して実現されている。
collapseとスコア計算の順序
collapseは、ローカルパラメータとして、主に以下のようなものを受け取ることができる。
ローカルパラメータ | 説明 |
---|---|
field |
collapseの対象となるフィールド |
min or max
|
指定されたフィールド or 関数クエリの最小値 か最大値 を代表とする |
sort |
指定されたソートの文字列に従って代表を選択する |
collapseは実行されると、ドキュメントがまとめられる = 減る
ので、スコア計算が重い処理を行う場合、collapseの実行後に行って欲しい。
実態としては
- collapseの
min
max
sort
でscoreを使う場合は代表選択にスコア計算が必要なので、計算される - collapseの実行タイミングはfqのフィルタの後なので、スコア計算される場合でもフィルタされた後にスコア計算される。
- collapseの代表選択にスコア計算が不要で、全体の中でスコアが必要(
fl
orsort
にscoreが指定されている)ならば、Mapに保存されている値を更新する必要があるときにスコアを計算する(最終的に代表となるドキュメントのスコアが残るように) - collectorが複数個 chainされているとき、何回もスコア計算が走らないように、ScoreAndDocクラスのオブジェクトをMapに保存しておいて、
finish()
内で次のcollect()
を呼んだときに、Mapから保存してあるスコアが取得できるようにsetScorer(dummy)
しておく