SolrのJSON Facet API

検索条件が複雑になりがちなファセット検索ではJSON APIが威力を発揮します。

以下は、大阪市の施設情報のデータを使った区のフィールドによるファセット検索の例です。

$ curl -s http://localhost:8983/solr/test/query?omitHeader=yes -d '{
    "query" : "*:*",
    "offset" : 0,
    "limit" : 0,
    "facet" : {
        "areas" : {
            "type" : "terms",
            "field" : "area",
            "limit" : 3
        }
    }
}' |jq .
{
  "response": {
    "numFound": 9238,
    "start": 0,
    "docs": []
  },
  "facets": {
    "count": 9238,
    "areas": {
      "buckets": [
        {
          "val": "平野区",
          "count": 610
        },
        {
          "val": "北区",
          "count": 566
        },
        {
          "val": "中央区",
          "count": 509
        }
      ]
    }
  }
}

複数のクエリによるファセット検索もすっきりと書けます。
以下は、大阪市役所の直線距離(0m~300m, 300m~500m, 500m~1km)で作成したファセットです。

$ cat request.json
{
    query: "*:*",
    offset: 0,
    limit: 0,
    facet: {
        "300m": {
            type: "query",
            q: "{!frange l=0 u=0.3}geodist()",
        },
        "500m": {
            type: "query",
            q: "{!frange l=0.3 u=0.5}geodist()"
        },
        "1km": {
            type: "query",
            q: "{!frange l=0.5 u=1}geodist()"
        }
    }
    params: {
	pt: "34.6938,135.502002777777", /* 大阪市役所 */
        sfield: "address_p"
    }
}

$ curl -s http://localhost:8983/solr/test1/query?omitHeader=yes -d @request.json
{
  "response":{"numFound":9238,"start":0,"docs":[]
  },
  "facets":{
    "count":9238,
    "300m":{
      "count":28},
    "500m":{
      "count":27},
    "1km":{
      "count":185}}}

ファセットのネストも書けます。
以下の例では、上の例で作ったファセットのサブファセットとして施設タイプを指定しています。

$ cat request.json
{
    query: "*:*",
    offset: 0,
    limit: 0,
    facet: {
	    "300m": {
	        type: "query",
	        q: "{!frange l=0 u=0.3}geodist()",
	        facet: {
		    average_distance: "avg(geodist())",
		    types: {
		        type: "terms",
		        field: "type",
                        limit: 3
		    }
                }
	    },
	    "500m": {
	        type: "query",
	        q: "{!frange l=0.3 u=0.5}geodist()",
	        facet: {
		    average_distance: "avg(geodist())",
		    types: {
		        type: "terms",
		        field: "type",
                        limit: 3
		    }
                }
	    },
	    "1km": {
	        type: "query",
	        q: "{!frange l=0.5 u=1}geodist()",
	        facet: {
		    average_distance: "avg(geodist())",
		    types: {
		        type: "terms",
		        field: "type",
                        limit: 3
		    }
                }
        }
    }
    params: {
	    pt: "34.6938,135.502002777777", /* 大阪市役所 */
	    sfield: "address_p"
    }
}
$ curl -s http://localhost:8983/solr/test1/query?omitHeader=yes -d @request.json
{
  "response":{"numFound":9238,"start":0,"docs":[]
  },
  "facets":{
    "count":9238,
    "300m":{
      "count":28,
      "average_distance":0.18667141635662304,
      "types":{
        "buckets":[{
            "val":"駅・バス停",
            "count":8},
          {
            "val":"文化・観光",
            "count":5},
          {
            "val":"官公庁",
            "count":4}]}},
    "500m":{
      "count":27,
      "average_distance":0.39623014517757793,
      "types":{
        "buckets":[{
            "val":"駐車場・駐輪場",
            "count":12},
          {
            "val":"文化・観光",
            "count":6},
          {
            "val":"官公庁",
            "count":2}]}},
    "1km":{
      "count":185,
      "average_distance":0.7759130600495204,
      "types":{
        "buckets":[{
            "val":"駐車場・駐輪場",
            "count":62},
          {
            "val":"駅・バス停",
            "count":46},
          {
            "val":"文化・観光",
            "count":24}]}}}}

JSON API は複雑な検索リクエストをプログラム的に生成する場合に非常に有効なので、活用していきたいところです。

コメント