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

コメント