Solr4.0のPivotFacetingを使ってみる

先日のSolr勉強会でドリルダウンの実装に関するセッションがあって、
その中でSolr4.0のPivot Facetingが最強じゃね?って話で、
スゲー良さげだったので自分も試してみる事にしました。
 
ってか、FacetPivotって何なのっていうと、、Solr4.0のWikiに以下のように書いてあります。

* Pivot Faceting – Multi-level or hierarchical faceting where the top
constraints for one field are found for each top constraint of a
different field.

 
ってことで、使うデータはこれまたSolr勉強会の際にクックパッドの@PENGUINANA_
ElasticSeachのセッションでコレいいよーってオススメしてたlivedoorグルメさんのものを使います。
livedoor Techブログ : livedoor グルメの DataSet を公開
 
schema.xmlのフィールドの定義は↓こんな感じ(テキトーですいやせん、、、w)

   <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
   <field name="name" type="text_ja" indexed="true" stored="true" omitNorms="true"/>
   <field name="property" type="text_ja" indexed="true" stored="true" omitNorms="true"/>
   <field name="alphabet" type="text_general" indexed="true" stored="true" omitNorms="true"/>
   <field name="name_kana" type="text_cjk" indexed="true" stored="true" omitNorms="true"/>
   <field name="pref_id" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="area_id" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="station_id1" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="station_time1" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="station_distance1 " type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="station_id2" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="station_time2" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="station_distance2 " type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="station_id3" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="station_time3" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="station_distance3 " type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="category_id1" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="category_id2" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="category_id3" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="category_id4" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="category_id5" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="zip" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="address" type="text_ja" indexed="true" stored="true" omitNorms="true"/>
   <field name="north_latitude" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="east_longitude" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="description" type="text_ja" indexed="true" stored="true" omitNorms="true"/>
   <field name="purpose" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="open_morning" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="open_lunch" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="open_late" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="photo_count" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="special_count" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="menu_count" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="fan_count" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="access_count" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="created_on" type="date" indexed="true" stored="true" omitNorms="true"/>
   <field name="modified_on" type="date" indexed="true" stored="true" omitNorms="true"/>
   <field name="closed" type="string" indexed="true" stored="true" omitNorms="true"/>

   <field name="text" type="text_ja" indexed="true" stored="false" multiValued="true"/>

日本語検索するところはデフォルトのtextにcopyFieldで↓こんな感じで。

   <copyField source="name" dest="text"/>
   <copyField source="property" dest="text"/>
   <copyField source="address" dest="text"/>
   <copyField source="description" dest="text"/>

Solrのexampledocsの中にXMLファイルをアップロード出来るサンプルがあるので、
CSVファイルをアップデートするようにシェル(post.sh)をコピって↓だけ書き換えたシェル作りやす。

curl $URL --data-binary @$f -H 'Content-type:application/csv'

前はCSVファイルを突っ込むときのURLはsolr/update/csvだったのですが、
・Solr4.0からCSVがデフォルトの UpdateHandler に取り込まれた。
・つまり solr/update でCSVも扱えるようになった。
・CSV入れる時は Content-type を application/csv か text/csv で。
という事がSolrのWiki↓に書いてありました。
http://wiki.apache.org/solr/UpdateCSV
 
んでシェル叩いたら、date型がinvalidとか言われてムカついたのでstringにしてやりましたw

   <field name="created_on" type="string" indexed="true" stored="true" omitNorms="true"/>
   <field name="modified_on" type="string" indexed="true" stored="true" omitNorms="true"/>

ってことで、ようやくデータが入りました。

root@hoge:/usr/local/apache-solr-4.0.0/ldgourmet/exampledocs# /bin/sh post_csv.sh restaurants.csv
Posting file restaurants.csv to http://localhost:8983/solr/update
<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">75033</int></lst>
</response>

<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader"><int name="status">0</int><int name="QTime">562</int></lst>
</response>

 
ってことで、、、
いよいよ facet.pivot してやるぜ~!と。
 
クエリは↓こんな感じ。自分の地元の海老名で居酒屋~

http://localhost:8983/solr/collection1/select?q=海老名&fq=category_id1:505&wt=xml&facet=true&facet.pivot=category_id1,category_id2,category_id3

結果は↓こんな感じ。検索に19ミリ秒かかって13レコード見つかりましたよ、と。

 
で、気になるファセットのところは↓こんな感じ。

ちなみにカテゴリはIDになってて、マスタは別CSVファイルで
↓のようになってます。

id,name,name_kana,parent1,parent2,similar
100,"和食","わしょく",0,0,
101,"懐石・精進・料亭・割烹","かいせき・しょうじん・りょうてい・かっぽう",100,0,
102,"懐石料理","かいせきりょうり",101,0,
103,"精進料理","しょうじんりょうり",101,0,
105,"会席料理","かいせきりょうり",101,0,
106,"料亭","りょうてい",101,0,
107,"割烹","かっぽう",101,0,
~略~

上記で居酒屋って言ってたのは、カテゴリ1が505って事です。

505,"居酒屋","いざかや",500,0,

海老名の居酒屋で検索して結果のファセットの詳細をみていくと、、、
1. category_id2のvalueが無いのが9件
2. category_id2が127(焼き鳥)が1件
3. category_id2が159(カニ)が1件
4. category_id2が178(和食その他)が1件
5. category_id2が502(ダイニングバー)が1件
で、唯一category_id3のデータを持ってたのが上記の5.で
category_id3が172(沖縄料理)
でした。
 
なんか1件ばっかりで、多段にネストしないとこの検証の意味ないじゃん、、、
って事になってしまって、ちょっと微妙だったので、新宿も試してみました。

http://localhost:8983/solr/collection1/select?q=新宿&fq=category_id1:505&wt=xml&facet=true&facet.pivot=category_id1,category_id2,category_id3

新宿で居酒屋だと570件も引っかかって、

 
facetのとこみると、category_id3もガッツリ入ってますね~

category_id2が178でcategory_id3で718が24件って事で。
何のお店かな?って思ったら↓でした。

178,"和食その他","わしょくそのた",179,0,
718,"創作料理","そうさくりょうり",999,0,

んま、蓋を開けてみると、土間土間とかつぼ八って事でしたが、、w

<str name="id">345180</str>
<str name="name">八吉</str>
<str name="property">新宿三丁目店</str>

<str name="id">345191</str>
<str name="name">土間土間</str>
<str name="property">新宿東口店</str>

<str name="id">345214</str>
<str name="name">つぼ八</str>
<str name="property">新宿駅中央口店</str>

 
このデータ使ってUIも作ってキャッキャしてみるかのぅ。
#って、いつもなんだかんだでやらないんだけどww
 

Apache Solr入門 ―オープンソース全文検索エンジン
関口 宏司 三部 靖夫 武田 光平 中野 猛 大谷 純
技術評論社
売り上げランキング: 24318

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中