SolrでSparse Vectorを使った検索をする
本記事は情報検索・検索技術 Advent Calendar 2025の22日目の記事です。
SolrでSparse Vector Searchができないかなぁと思って検索していたところ、2025/07に出た9.9で面白そうな機能が入っていたので、それを試してみた記録です。
SolrでのSparse Vector検索のサポート状況について
2025年7月にリリースされたSolr 9.9にて、RawTFSimilarityFactoryなるクラスが追加されました。まだexperimental扱いですが、フィールドのTerm Frequencyを用いて類似度を計算するためのクラスなようです。
またこの追加に付随して、残念ながら今現在Closeとなってしまっていますが、チュートリアルページを追加するPRがでていました。本ブログはこちらを元に試してみた記録です。
実践
Sparse Vector用のスキーマ
まずはRawTFSimilarityFactoryを用いるためのスキーマを定義します。
...
<dynamicField name="*_drtf" type="delimited_rawtf" indexed="true" stored="true" omitPositions="true"/>
<fieldType name="delimited_rawtf" stored="false" indexed="true" class="solr.TextField">
<analyzer>
<tokenizer name="whitespace"/>
<filter name="delimitedTermFrequency"/>
</analyzer>
<analyzer type="query">
<tokenizer name="whitespace"/>
</analyzer>
<similarity class="solr.RawTFSimilarityFactory"/>
</fieldType>
...
ここでは*_drtfという名前のDynamic Field、およびそれに適用するdelimited_rawtfというField Typeを定義しています。
delimited_rawtfではdelimitedTermFrequencyを用いて、スペース区切りのterm|frequencyの形式でタームおよび出現頻度を定義できるようにしています。また、SimilarityとしてRawTFSimilarityFactoryを指定しています。
これらを追加したスキーマ定義をmanaged-schema.xmlとして保存します。
Solrの起動
次に、Docker ComposeでSolrを起動します。以下のcompose.ymlを用意します。
services: solr: image: solr ports: - "8983:8983" volumes: - data:/var/solr - ./managed-schema.xml:/opt/solr/server/solr/configsets/_default/conf/managed-schema.xml:ro command: - solr-precreate - sparse volumes: data:
あとはdocker compose upでSolrを起動するだけです。
ドキュメントの登録
次に、新しく定義したフィールドを用いてドキュメントを登録します。登録内容は以下の通りで、各ドキュメントに対してtext_ws(通常のテキストフィールド)とtext_drtf(Sparse Vector用フィールド)を登録しています。
[ { "id" : "1", "text_ws" : "bumble bee", "text_drtf" : "bee|3 bumble|2" } , { "id" : "2", "text_ws" : "honey bee", "text_drtf" : "bee|3 honey|2 sugar|1" } , { "id" : "3", "text_ws" : "solitary bee", "text_drtf" : "bee|3 solitary|2 alone|1" } ]
検索
最後に、登録したドキュメントに対して検索します。以下のように、text_drtfフィールドに対してクエリを投げることで、Sparse Vector Searchが可能です。
curl 'http://localhost:8983/solr/sparse/select?fl=text_*,score&q=text_drtf:(bumble^10+honey^2+bee)'
{ "responseHeader":{ "status":0, "QTime":2, "params":{ "q":"text_drtf:(bumble^10 honey^2 bee)", "fl":"text_*,score" } }, "response":{ "numFound":3, "start":0, "maxScore":23.0, "numFoundExact":true, "docs":[{ "text_ws":"bumble bee", "text_drtf":"bee|3 bumble|2", "score":23.0 },{ "text_ws":"honey bee", "text_drtf":"bee|3 honey|2 sugar|1", "score":7.0 },{ "text_ws":"solitary bee", "text_drtf":"bee|3 solitary|2 alone|1", "score":3.0 }] } }
ここでそれぞれのドキュメントに対してスコアが
- id:1 -> bumble210 + bee31 = 20 + 3 = 23
- id:2 -> honey22 + bee31 = 7
- id:3 -> bee31 = 3
としてそれぞれ計算されており、事前に登録したSparse Vectorに基づいて正しくスコアリングされていることがわかります。
注意点
今回はシンプルな例でしたが、この実装ではスコアの計算にTerm Frequencyを使用することに注意が必要です。例えばSPLADEのような浮動小数点で表現されるベクトルの場合、事前に浮動小数点のスコアから正の整数への変換が必要となります。浮動小数点のままインデクシングを試みるとUnable to parseの例外が発生します。
まとめ
本記事ではSolr 9.9で追加されたRawTFSimilarityFactoryを用いたシンプルなSparse Vector Searchの方法について紹介しました。Sparse Vector SearchをSolrで試してみたい方の参考になれば幸いです。