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を使うことになるだろうと思います。