Solrでdistinct

はじめに
Solrを使った検索で、特定のフィールドのすべての値を取得したい場合がありました。SQLで言うところのdistnctです。これを実現する方法を調べてみました。
(その1)Facetを使う方法
Solrの得意技であるFacetを使えば特定のフィールドのユニークな値をすべて列挙できます。
弊社から出しているSportareというアプリでは、スポーツ施設の検索にSolrを利用しています。各施設が持っている、実施できるスポーツ名のユニーク値を取得してみます。
$ curl 'http://localhost:8983/solr/sportare/select?facet.field=sports&facet.limit=10&facet.offset=0&facet=on&q=*:*&rows=0'
{
(略)
"facet_counts":{
"facet_queries":{},
"facet_fields":{
"sports":[
"野球",4644,
"バレーボール",4420,
"バドミントン",4365,
"バスケットボール",4218,
"フィットネス",4089,
"卓球",3918,
"テニス",3493,
"ソフトボール",3438,
"サッカー",2711,
"水泳",2687]},
"facet_ranges":{},
"facet_intervals":{},
"facet_heatmaps":{}}}
sportsフィールドの値でFacetを作っています。facet.limitとfacet.offsetを指定して最初の10件を取得しています。facet.limit=-1と指定すれば全件取れます。
(その2)StatsComponentを使う方法
StatsComponentは、インデックスに含まれるドキュメントの統計情報を扱うコンポーネントです。このコンポーネントにdistinctValuesというパラメータを含めたリクエストを送ることでフィールドのユニーク値を取得できます。
$ curl 'http://localhost:8983/solr/sportare-spots/select?q=*:*&rows=0&stats.field={!countDistinct=true distinctValues=true}sports&stats=true'
{
(略)
"stats":{
"stats_fields":{
"sports":{
"distinctValues":["",
"BMX",
"アイスホッケー",
"アメリカンフットボール",
"アルペンスキー",
"アーチェリー",
"インディアカ",
"インラインスケート",
"ウィンドサーフィン",
"エアロビクス",
"オートレース",
"カヌー",
"カヤック",
"カートレース",
"カーリング",
"カーレース",
"キックボクシング",
(略)
"自転車競技",
"野球",
"陸上",
"陸上競技",
"馬術"],
"countDistinct":89}}}}
まとめ
Solrでdistinctを実現する方法を2つ挙げてみましたが、
- 処理が軽い
- その値が何件存在するかも同時に出せる
- 全体の件数が非常に大きい場合に、n件ずつ取得するというページングの処理も簡単
などの利点がFacetにあるため、よほどの理由が無いかぎりはFacetを使うことになるだろうと思います。