LoginSignup
3
3

More than 1 year has passed since last update.

Solr内部のそうだったのか メモ

Posted at

いつも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では、以下のような流れで処理される。

  1. collect()が呼ばれる
  2. 内部で持ってるMap(DynamicMap)にputする(同じキーなら一つにまとめられる)
  3. 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 or sortにscoreが指定されている)ならば、Mapに保存されている値を更新する必要があるときにスコアを計算する(最終的に代表となるドキュメントのスコアが残るように)
  • collectorが複数個 chainされているとき、何回もスコア計算が走らないように、ScoreAndDocクラスのオブジェクトをMapに保存しておいて、finish()内で次のcollect()を呼んだときに、Mapから保存してあるスコアが取得できるようにsetScorer(dummy)しておく
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3