これまで学んだgroongaの機能を用いて、マイクロブログの検索システムを作成してみましょう。マイクロブログとは、Twitterのような短いメッセージを投稿するブログです。
まずは、テーブルを作成します。
table_create --name Users --flags TABLE_HASH_KEY --key_type ShortText
table_create --name Comments --flags TABLE_HASH_KEY --key_type ShortText
table_create --name HashTags --flags TABLE_HASH_KEY --key_type ShortText
table_create --name Bigram --flags TABLE_PAT_KEY|KEY_NORMALIZE --key_type ShortText --default_tokenizer TokenBigram
column_create --table Users --name name --flags COLUMN_SCALAR --type ShortText
column_create --table Users --name follower --flags COLUMN_VECTOR --type Users
column_create --table Users --name favorites --flags COLUMN_VECTOR --type Comments
column_create --table Users --name location --flags COLUMN_SCALAR --type WGS84GeoPoint
column_create --table Users --name location_str --flags COLUMN_SCALAR --type ShortText
column_create --table Users --name description --flags COLUMN_SCALAR --type ShortText
column_create --table Users --name folowee --flags COLUMN_INDEX --type Users --source follower
column_create --table Comments --name comment --flags COLUMN_SCALAR --type ShortText
column_create --table Comments --name last_modified --flags COLUMN_SCALAR --type Time
column_create --table Comments --name replied_to --flags COLUMN_SCALAR --type Comments
column_create --table Comments --name replied_users --flags COLUMN_VECTOR --type Users
column_create --table Comments --name hash_tags --flags COLUMN_VECTOR --type HashTags
column_create --table Comments --name location --flags COLUMN_SCALAR --type WGS84GeoPoint
column_create --table Comments --name posted_by --flags COLUMN_SCALAR --type Users
column_create --table Comments --name favorited_by --flags COLUMN_INDEX --type Users --source favorites
column_create --table HashTags --name hash_index --flags COLUMN_INDEX --type Comments --source hash_tags
column_create --table Bigram --name users_index --flags COLUMN_INDEX|WITH_POSITION|WITH_SECTION --type Users --source name,location_str,description
column_create --table Bigram --name comment_index --flags COLUMN_INDEX|WITH_POSITION --type Comments --source comment
ユーザーの名前や自己紹介文、フォローしているユーザー一覧など、ユーザー情報を格納するためのテーブルです。
コメント内容や投稿日時、返信先情報など、コメントに関する内容を格納するテーブルです。
コメントのハッシュタグを一覧で保存するためのテーブルです。
ユーザー情報・コメントで全文検索が出来るようにするためのインデックスを格納するテーブルです。
つづいて、テスト用データをロードします。
load --table Users
[
{
"_key": "daijiro",
"name": "hsiomaneki",
"follower": ["tasukuchan"],
"favorites": [],
"location": "127678039x502643091",
"location_str": "神奈川県",
"description": "groonga developer"
},
{
"_key": "tasukuchan",
"name": "グニャラくん",
"follower": ["daijiro","OffGao"],
"favorites": ["daijiro:1","OffGao:1"],
"location": "128423343x502929252",
"location_str": "東京都渋谷区",
"description": "エロいおっさん"
},
{
"_key": "OffGao",
"name": "OffGao",
"follower": ["tasukuchan","daijiro"],
"favorites": ["tasukuchan:1","daijiro:1"],
"location": "128544408x502801502",
"location_str": "東京都中野区",
"description": "がおがお"
}
]
load --table Comments
[
{
"_key": "daijiro:1",
"comment": "マイクロブログ作ってみました(甘栗むいちゃいました的な感じで)。",
"last_modified": "2010/03/17 12:05:00",
"posted_by": "daijiro",
},
{
"_key": "tasukuchan:1",
"comment": "初の書き込み。テストテスト。",
"last_modified": "2010/03/17 12:00:00",
"posted_by": "tasukuchan",
},
{
"_key": "daijiro:2",
"comment": "@tasukuchan ようこそ!!!",
"last_modified": "2010/03/17 12:05:00",
"replied_to": "tasukuchan:1",
"replied_users": ["tasukuchan"],
"posted_by": "daijiro",
},
{
"_key": "tasukuchan:2",
"comment": "@daijiro ありがとう!",
"last_modified": "2010/03/17 13:00:00",
"replied_to": "daijiro:2",
"replied_users": ["daijiro"],
"posted_by": "tasukuchan",
},
{
"_key": "tasukuchan:3",
"comment": "groongaなう #groonga",
"last_modified": "2010/03/17 14:00:00",
"hash_tags": ["groonga"],
"location": "127972422x503117107",
"posted_by": "tasukuchan",
},
{
"_key": "tasukuchan:4",
"comment": "groonga開発合宿のため羽田空港に来ました! #groonga #travel",
"last_modified": "2010/03/17 14:05:00",
"hash_tags": ["groonga", "travel"],
"location": "127975798x502919856",
"posted_by": "tasukuchan",
},
{
"_key": "OffGao:1",
"comment": "@daijiro @tasukuchan 登録してみましたよー!",
"last_modified": "2010/03/17 15:00:00",
"replied_users": ["daijiro", "tasukuchan"],
"location": "128551935x502796433",
"posted_by": "OffGao",
}
{
"_key": "OffGao:2",
"comment": "中野ブロードウェイなうなう",
"last_modified": "2010/03/17 15:05:00",
"location": "128551935x502796434",
"posted_by": "OffGao",
}
]
Usersテーブルのfollowerカラムとfavoritesカラム、そしてCommentsテーブルのreplied_usersカラムは、ベクターカラムです。そのため、これらのカラムは配列で値を指定します。
Usersテーブルのlocationカラムと、Commentsテーブルのlocationカラムは、GeoPoint型です。この型での値の指定は、”[緯度]x[経度]”と記述して指定します。
Commentsテーブルのlast_modifiedカラムは、Time型です。この型での値の指定方法は、マイクロ秒数の値を直接指定する方法のほかに、文字列で指定する方法もあります。”年/月/日 時:分:秒”というフォーマットで記述することで、データロードの際に文字列からキャストされ、マイクロ秒数の値が格納されます。
それでは、実際に検索をしてみましょう。
ここでは、 match_columnsパラメータ で扱った、複数カラムを対象とした検索を行います。 指定された文字列で、ユーザー名・現在地・自己紹介文を対象に検索をします。
実行例
> select --table Users --match_columns name,location_str,description --query 東京 --output_columns _key,name
[[0,1280378873.00607,0.00053],[[[2],[["_key","ShortText"],["name","ShortText"]],["tasukuchan","グニャラくん"],["OffGao","OffGao"]]]]
「東京」をキーワードにユーザー検索した結果、東京都に住んでいる「グニャラくん」と「OffGao」がヒットしました。
ここでは、 さまざまな検索条件の指定 で扱った、GeoPoint型のカラムで検索をします。 以下の例では、指定された位置から5000m以内にいるユーザーを検索しています。
実行例
> select --table Users --filter 'geo_in_circle(location,"128484216x502919856",5000)' --output_columns _key,name
[[0,1280378873.20845,0.000337],[[[2],[["_key","ShortText"],["name","ShortText"]],["tasukuchan","グニャラくん"],["OffGao","OffGao"]]]]
新宿駅から5km以内にすんでいるユーザーを検索したところ、「グニャラくん」と「OffGao」がヒットしました。
ここでは、 タグ検索・参照関係の逆引き で扱った、参照関係の逆引きをします。 以下の例では、Usersテーブルのfollowerカラムにあるフォローリストを逆引きします。
実行例
> select --table Users --query follower:@tasukuchan --output_columns _key,name
[[0,1280378873.4108,0.000311],[[[2],[["_key","ShortText"],["name","ShortText"]],["daijiro","hsiomaneki"],["OffGao","OffGao"]]]]
「グニャラくん」をフォローしている「hsiomaneki」と「OffGao」がヒットしました。
ある範囲内で書かれたコメントを検索します。 また、 ドリルダウン で扱ったドリルダウンも行います。検索結果をハッシュタグとユーザーでドリルダウンし、ユーザー別・ハッシュタグ別のカウントを出します。
実行例
> select --table Comments --filter 'geo_in_circle(location,"127975798x502919856",20000)' --output_columns posted_by.name,comment --drilldown hash_tags,posted_by
[[0,1280378873.61299,0.000702],[[[4],[["posted_by.name","ShortText"],["comment","ShortText"]],["OffGao","@daijiro @tasukuchan 登録してみましたよー!"],["グニャラくん","groongaなう #groonga"],["グニャラくん","groonga開発合宿のため羽田空港に来ました! #groonga #travel"],["OffGao","中野ブロードウェイなうなう"]],[[2],[["_key","ShortText"],["_nsubrecs","Int32"]],["groonga",2],["travel",1]],[[2],[["_key","ShortText"],["_nsubrecs","Int32"]],["OffGao",2],["tasukuchan",2]]]]
範囲を広く指定したため、位置情報のあるすべてのコメントがヒットしました。そして、ヒットしたコメントからドリルダウンされた結果も返ってきており、ハッシュタグは「#groonga」が2つに「#travel」が1つ、投稿者は「グニャラくん」「OffGao」がそれぞれ2件ずつであることがわかります。
あるキーワードを含むコメントを検索します。 さらに、 さまざまな検索条件の指定 で扱った、スコア値_scoreも出してみましょう。
実行例
> select --table Comments --query comment:@なう --output_columns comment,_score
[[0,1280378873.81946,0.000332],[[[2],[["comment","ShortText"],["_score","Int32"]],["groongaなう #groonga",1],["中野ブロードウェイなうなう",2]]]]
「なう」をキーワードにコメント検索した結果、2件のコメントがヒットしました。また、_scoreの値も返ってきており、「なう」の数が出力されていることが確認できます。
今度は、キーワードとGeoPointの両方を条件に検索をしてみます。–queryと–filterの両方を使用した場合、両方の条件に一致するレコードがヒットします。
実行例
> select --table Comments --query comment:@羽田 --filter 'geo_in_circle(location,"127975798x502919856",20000)' --output_columns posted_by.name,comment --drilldown hash_tags,posted_by
[[0,1280378874.02194,0.000669],[[[1],[["posted_by.name","ShortText"],["comment","ShortText"]],["グニャラくん","groonga開発合宿のため羽田空港に来ました! #groonga #travel"]],[[2],[["_key","ShortText"],["_nsubrecs","Int32"]],["groonga",1],["travel",1]],[[1],[["_key","ShortText"],["_nsubrecs","Int32"]],["tasukuchan",1]]]]
両方の条件を満たすコメントが1件ヒットしました。また、ドリルダウンの結果も返ってきており、「グニャラくん」のコメント1件であることがわかります。
あるハッシュタグのついているコメントを検索します。 これも、 タグ検索・参照関係の逆引き で扱った、参照関係の逆引きを使います。
実行例
> select --table Comments --query hash_tags:@groonga --output_columns posted_by.name,comment --drilldown posted_by
[[0,1280378874.22658,0.000485],[[[2],[["posted_by.name","ShortText"],["comment","ShortText"]],["グニャラくん","groongaなう #groonga"],["グニャラくん","groonga開発合宿のため羽田空港に来ました! #groonga #travel"]],[[1],[["_key","ShortText"],["_nsubrecs","Int32"]],["tasukuchan",2]]]]
#groongaタグの付いている2件のコメントがヒットしました。また、投稿者のドリルダウンも返ってきており、2件とも「グニャラくん」のものであることがわかります。
あるユーザーが投稿したコメントを検索します。
実行例
> select --table Comments --query posted_by:tasukuchan --output_columns comment --drilldown hash_tags
[[0,1280378874.43074,0.000502],[[[4],[["comment","ShortText"]],["初の書き込み。テストテスト。"],["@daijiro ありがとう!"],["groongaなう #groonga"],["groonga開発合宿のため羽田空港に来ました! #groonga #travel"]],[[2],[["_key","ShortText"],["_nsubrecs","Int32"]],["groonga",2],["travel",1]]]]
「グニャラくん」が書き込んだ4件のコメントがヒットしました。また、ハッシュタグでドリルダウンした結果も返ってきており、ハッシュタグは「#groonga」が2つに「#travel」が1つあることがわかります。
あるユーザーがお気に入りに入れているコメントを検索します。
実行例
> select --table Users --query _key:tasukuchan --output_columns favorites.posted_by,favorites.comment
[[0,1280378874.63511,0.000327],[[[1],[["favorites.posted_by","Users"],["favorites.comment","ShortText"]],[["daijiro","OffGao"],["マイクロブログ作ってみました(甘栗むいちゃいました的な感じで)。","@daijiro @tasukuchan 登録してみましたよー!"]]]]]
「グニャラくん」がお気に入りに入れている2件のコメントがヒットしました。
コメントの投稿時間で検索をします。Time型については さまざまな種類をもったデータの保存 で扱っています。 この例では、指定した時間よりも前に投稿されているコメントを検索します。
実行例
> select Comments --filter 'last_modified<=1268802000' --output_columns posted_by.name,comment,last_modified --drilldown hash_tags,posted_by
[[0,1280378874.83883,0.000681],[[[5],[["posted_by.name","ShortText"],["comment","ShortText"],["last_modified","Time"]],["hsiomaneki","マイクロブログ作ってみました(甘栗むいちゃいました的な感じで)。",1268795100.0],["グニャラくん","初の書き込み。テストテスト。",1268794800.0],["hsiomaneki","@tasukuchan ようこそ!!!",1268795100.0],["グニャラくん","@daijiro ありがとう!",1268798400.0],["グニャラくん","groongaなう #groonga",1268802000.0]],[[1],[["_key","ShortText"],["_nsubrecs","Int32"]],["groonga",1]],[[2],[["_key","ShortText"],["_nsubrecs","Int32"]],["daijiro",2],["tasukuchan",3]]]]
2010/03/17 14:00:00以前に書かれたコメント5件がヒットしました。また、ドリルダウンの結果も返ってきており、「hsiomaneki」が2件、「グニャラくん」が3件ヒットしていることがわかります。