4.10. マイクロブログ検索システムの作成¶
これまで学んだGroongaの機能を用いて、マイクロブログの検索システムを作成してみましょう。マイクロブログとは、Twitterのような短いメッセージを投稿するブログです。
4.10.1. テーブルの作成¶
まずは、テーブルを作成します。
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_type ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
table_create --name GeoIndex --flags TABLE_PAT_KEY --key_type WGS84GeoPoint
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 followee --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
column_create --table GeoIndex --name users_location --type Users --flags COLUMN_INDEX --source location
column_create --table GeoIndex --name comments_location --type Comments --flags COLUMN_INDEX --source location
4.10.1.1. Usersテーブル¶
ユーザーの名前や自己紹介文、フォローしているユーザー一覧など、ユーザー情報を格納するためのテーブルです。
_key
ユーザーID
name
ユーザー名
follower
フォローしているユーザーの一覧
favorites
お気に入りのコメント一覧
location
ユーザーの現在地(緯度経度座標)
location_str
ユーザーの現在地(文字列)
description
ユーザーの自己紹介
followee
Users
テーブルのfollower
カラムに対するインデックス。 このインデックスを作ることで、あるユーザーをフォローしているユーザーを検索できるようになります。
4.10.1.2. Commentsテーブル¶
コメント内容や投稿日時、返信先情報など、コメントに関する内容を格納するテーブルです。
_key
コメントID
comment
コメント内容
last_modified
投稿日時
replied_to
返信元のコメント内容
replied_users
返信先のユーザーの一覧
hash_tags
コメントのハッシュタグの一覧
location
投稿場所(緯度経度座標のため)
posted_by
コメントを書いたユーザー
favorited_by
Users
テーブルのfavorites
カラムに対するインデックス。 このインデックスを作ることで、指定したコメントを誰がお気に入りに入れているのかを検索できるようになります。
4.10.1.3. HashTagsテーブル¶
コメントのハッシュタグを一覧で保存するためのテーブルです。
_key
ハッシュタグ
hash_index
「Comments.hash_tags」のインデックス。 このインデックスを作ることで、指定したハッシュタグのついているコメントの一覧を出すことが出来るようになります。
4.10.1.4. Bigramテーブル¶
ユーザー情報・コメントで全文検索が出来るようにするためのインデックスを格納するテーブルです。
_key
単語
users_index
ユーザー情報のインデックス。 このカラムは、ユーザー名「Users.name」、現在地「Users.location_str」、自己紹介文「Users.description」のインデックスになっています。
comment_index
コメント内容「Comments.comment」のインデックス
4.10.1.5. GeoIndexテーブル¶
位置情報検索を効果的に行うための locationカラムのインデックスを保持するテーブルです。
users_location
Usersテーブルのlocationカラムに対するインデックス
comments_location
Commentsテーブルのlocationカラムに対するインデックス
4.10.2. データのロード¶
つづいて、テスト用データをロードします。
load --table Users
[
{
"_key": "alice",
"name": "Alice",
"follower": ["bob"],
"favorites": [],
"location": "152489000x-255829000",
"location_str": "Boston, Massachusetts",
"description": "Groonga developer"
},
{
"_key": "bob",
"name": "Bob",
"follower": ["alice","charlie"],
"favorites": ["alice:1","charlie:1"],
"location": "146249000x-266228000",
"location_str": "Brooklyn, New York City",
"description": ""
},
{
"_key": "charlie",
"name": "Charlie",
"follower": ["alice","bob"],
"favorites": ["alice:1","bob:1"],
"location": "146607190x-267021260",
"location_str": "Newark, New Jersey",
"description": "Hmm,Hmm"
}
]
load --table Comments
[
{
"_key": "alice:1",
"comment": "I've created micro-blog!",
"last_modified": "2010/03/17 12:05:00",
"posted_by": "alice",
},
{
"_key": "bob:1",
"comment": "First post. test,test...",
"last_modified": "2010/03/17 12:00:00",
"posted_by": "bob",
},
{
"_key": "alice:2",
"comment": "@bob Welcome!!!",
"last_modified": "2010/03/17 12:05:00",
"replied_to": "bob:1",
"replied_users": ["bob"],
"posted_by": "alice",
},
{
"_key": "bob:2",
"comment": "@alice Thanks!",
"last_modified": "2010/03/17 13:00:00",
"replied_to": "alice:2",
"replied_users": ["alice"],
"posted_by": "bob",
},
{
"_key": "bob:3",
"comment": "I've just used 'Try-Groonga' now! #groonga",
"last_modified": "2010/03/17 14:00:00",
"hash_tags": ["groonga"],
"location": "146566000x-266422000",
"posted_by": "bob",
},
{
"_key": "bob:4",
"comment": "I'm come at city of New York for development camp! #groonga #travel",
"last_modified": "2010/03/17 14:05:00",
"hash_tags": ["groonga", "travel"],
"location": "146566000x-266422000",
"posted_by": "bob",
},
{
"_key": "charlie:1",
"comment": "@alice @bob I've tried to register!",
"last_modified": "2010/03/17 15:00:00",
"replied_users": ["alice", "bob"],
"location": "146607190x-267021260",
"posted_by": "charlie",
}
{
"_key": "charlie:2",
"comment": "I'm at the Museum of Modern Art in NY now!",
"last_modified": "2010/03/17 15:05:00",
"location": "146741340x-266319590",
"posted_by": "charlie",
}
]
Users
テーブルの follower
カラムと favorites
カラム、そして Comments
テーブルの replied_users
カラムは、ベクターカラムです。そのため、これらのカラムは配列で値を指定します。
Users
テーブルの location
カラムと、Comments
テーブルの location
カラムは、 GeoPoint
型です。この型での値の指定は、"[緯度]x[経度]"と記述して指定します。
Comments
テーブルの last_modified
カラムは、Time型です。
この型での値を指定する方法は2つあります。1つ目の方法は、1970年1月1日0時0分0秒からの経過秒数の値を直接指定する方法です。このとき、小数部分を指定することでマイクロ秒数での指定が可能です。指定した値は、データのロードの際にマイクロ秒を単位とする整数値に変換後、格納されます。 2つ目の方法は、文字列で日時と時刻を指定する方法です。"年/月/日 時:分:秒"というフォーマットで記述することで、データロードの際に文字列からキャストされ、マイクロ秒数の値が格納されます。
4.10.3. 検索¶
マイクロブログを検索してみましょう。
4.10.3.1. キーワードでユーザー検索¶
ここでは、 match_columnsパラメータ で扱った、複数カラムを対象とした検索を行います。
指定された文字列で、ユーザー名・現在地・自己紹介文を対象に検索をします。
実行例:
select --table Users --match_columns name,location_str,description --query "New York" --output_columns _key,name
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], true]
# [[0, 1337566253.89858, 0.000355720520019531], 3]
# [[0, 1337566253.89858, 0.000355720520019531], 8]
# [
# [
# 0,
# 1337566253.89858,
# 0.000355720520019531
# ],
# [
# [
# [
# 1
# ],
# [
# [
# "_key",
# "ShortText"
# ],
# [
# "name",
# "ShortText"
# ]
# ],
# [
# "bob",
# "Bob"
# ]
# ]
# ]
# ]
「New York」をキーワードにユーザー検索した結果、New Yorkに住んでいる「Bob」がヒットしました。
4.10.3.2. 位置情報(GeoPoint)でユーザー検索¶
ここでは、GeoPoint型のカラムで検索をします。GeoPoint型については さまざまな検索条件 を参照してください。
次の例では、特定の場所から20km以内に住んでいる人を検索します。
実行例:
select --table Users --filter 'geo_in_circle(location,"146710080x-266315480",20000)' --output_columns _key,name
# [
# [
# 0,
# 1337566253.89858,
# 0.000355720520019531
# ],
# [
# [
# [
# 2
# ],
# [
# [
# "_key",
# "ShortText"
# ],
# [
# "name",
# "ShortText"
# ]
# ],
# [
# "charlie",
# "Charlie"
# ],
# [
# "bob",
# "Bob"
# ]
# ]
# ]
# ]
「Bob」と「Charlie」が「Grand Central Terminal」から20km以内に住んでいることがわかります。
4.10.3.3. あるユーザーをフォローしてるユーザーの検索¶
ここでは、 タグ検索・参照関係の逆引き の参照関係の逆引きをします。
次の例は、 Users
テーブルの follower
カラムにあるフォローリストを逆引きします。
実行例:
select --table Users --query follower:@bob --output_columns _key,name
# [
# [
# 0,
# 1337566253.89858,
# 0.000355720520019531
# ],
# [
# [
# [
# 2
# ],
# [
# [
# "_key",
# "ShortText"
# ],
# [
# "name",
# "ShortText"
# ]
# ],
# [
# "alice",
# "Alice"
# ],
# [
# "charlie",
# "Charlie"
# ]
# ]
# ]
# ]
「Alice」と「Charlie」が「Bob」をフォローしていることがわかります。
4.10.3.4. GeoPointでコメント検索¶
ある範囲内で書かれたコメントを検索します。
また、 ドリルダウン をおこないます。検索結果をハッシュタグとユーザーでドリルダウンし、ユーザー別・ハッシュタグ別のカウントを出します。
実行例:
select --table Comments --filter 'geo_in_circle(location,"146867000x-266280000",20000)' --output_columns posted_by.name,comment --drilldown hash_tags,posted_by
# [
# [
# 0,
# 1337566253.89858,
# 0.000355720520019531
# ],
# [
# [
# [
# 4
# ],
# [
# [
# "posted_by.name",
# "ShortText"
# ],
# [
# "comment",
# "ShortText"
# ]
# ],
# [
# "Charlie",
# "I'm at the Museum of Modern Art in NY now!"
# ],
# [
# "Bob",
# "I've just used 'Try-Groonga' now! #groonga"
# ],
# [
# "Bob",
# "I'm come at city of New York for development camp! #groonga #travel"
# ],
# [
# "Charlie",
# "@alice @bob I've tried to register!"
# ]
# ],
# [
# [
# 2
# ],
# [
# [
# "_key",
# "ShortText"
# ],
# [
# "_nsubrecs",
# "Int32"
# ]
# ],
# [
# "groonga",
# 2
# ],
# [
# "travel",
# 1
# ]
# ],
# [
# [
# 2
# ],
# [
# [
# "_key",
# "ShortText"
# ],
# [
# "_nsubrecs",
# "Int32"
# ]
# ],
# [
# "charlie",
# 2
# ],
# [
# "bob",
# 2
# ]
# ]
# ]
# ]
このクエリは、ニューヨークのセントラルパークから20km圏内で投稿されたコメントを検索します。
指定した範囲が20kmなので、位置情報を含むすべてのコメントが検索されました。#groongaというハッシュタグが2件、#travelというハッシュタグが1件で、BobとCharlieがコメントしているのは2件あります。
4.10.3.5. キーワードでコメント検索¶
あるキーワードを含むコメントを検索します。そして、 さまざまな検索条件 で言及している _score を出してみます。
実行例:
select --table Comments --query comment:@Now --output_columns comment,_score
# [
# [
# 0,
# 1337566253.89858,
# 0.000355720520019531
# ],
# [
# [
# [
# 2
# ],
# [
# [
# "comment",
# "ShortText"
# ],
# [
# "_score",
# "Int32"
# ]
# ],
# [
# "I've just used 'Try-Groonga' now! #groonga",
# 1
# ],
# [
# "I'm at the Museum of Modern Art in NY now!",
# 1
# ]
# ]
# ]
# ]
'Now'をキーワードに使っているので、このクエリは2件のコメントを返します。 _score の値として 'Now'のカウントを含んでいます。
4.10.3.6. キーワードと位置情報で検索¶
あるキーワードと位置情報の両方でコメントを検索します。 --query と --filter オプションの両方を使用した場合、両方の条件に一致するレコードを返します。
実行例:
select --table Comments --query comment:@New --filter 'geo_in_circle(location,"146867000x-266280000",20000)' --output_columns posted_by.name,comment --drilldown hash_tags,posted_by
# [
# [
# 0,
# 1337566253.89858,
# 0.000355720520019531
# ],
# [
# [
# [
# 1
# ],
# [
# [
# "posted_by.name",
# "ShortText"
# ],
# [
# "comment",
# "ShortText"
# ]
# ],
# [
# "Bob",
# "I'm come at city of New York for development camp! #groonga #travel"
# ]
# ],
# [
# [
# 2
# ],
# [
# [
# "_key",
# "ShortText"
# ],
# [
# "_nsubrecs",
# "Int32"
# ]
# ],
# [
# "groonga",
# 1
# ],
# [
# "travel",
# 1
# ]
# ],
# [
# [
# 1
# ],
# [
# [
# "_key",
# "ShortText"
# ],
# [
# "_nsubrecs",
# "Int32"
# ]
# ],
# [
# "bob",
# 1
# ]
# ]
# ]
# ]
両方の条件をみたすコメントが1件あります。ドリルダウンの結果も含まれ、Bobによるコメントであることがわかります。
4.10.3.7. ハッシュタグでコメントを検索¶
あるハッシュタグのついているコメントを検索します。テーブルの参照関係を逆にたどってみましょう。
実行例:
select --table Comments --query hash_tags:@groonga --output_columns posted_by.name,comment --drilldown posted_by
# [
# [
# 0,
# 1337566253.89858,
# 0.000355720520019531
# ],
# [
# [
# [
# 2
# ],
# [
# [
# "posted_by.name",
# "ShortText"
# ],
# [
# "comment",
# "ShortText"
# ]
# ],
# [
# "Bob",
# "I've just used 'Try-Groonga' now! #groonga"
# ],
# [
# "Bob",
# "I'm come at city of New York for development camp! #groonga #travel"
# ]
# ],
# [
# [
# 1
# ],
# [
# [
# "_key",
# "ShortText"
# ],
# [
# "_nsubrecs",
# "Int32"
# ]
# ],
# [
# "bob",
# 2
# ]
# ]
# ]
# ]
このクエリは#groongaハッシュタグを含む2件のコメントを返します。投稿者のドリルダウン結果を2件含んでいて、Bobが投稿したことがわかります。
4.10.3.8. ユーザーIDでコメントを検索¶
あるユーザーが投稿したコメントを検索します。
実行例:
select --table Comments --query posted_by:bob --output_columns comment --drilldown hash_tags
# [
# [
# 0,
# 1337566253.89858,
# 0.000355720520019531
# ],
# [
# [
# [
# 4
# ],
# [
# [
# "comment",
# "ShortText"
# ]
# ],
# [
# "First post. test,test..."
# ],
# [
# "@alice Thanks!"
# ],
# [
# "I've just used 'Try-Groonga' now! #groonga"
# ],
# [
# "I'm come at city of New York for development camp! #groonga #travel"
# ]
# ],
# [
# [
# 2
# ],
# [
# [
# "_key",
# "ShortText"
# ],
# [
# "_nsubrecs",
# "Int32"
# ]
# ],
# [
# "groonga",
# 2
# ],
# [
# "travel",
# 1
# ]
# ]
# ]
# ]
このクエリはBobによる4件のコメントを返します。ハッシュタグによるドリルダウン結果も含まれ、#groongaが2件、#travelが1件であることがわかります。
4.10.3.9. ユーザーのお気に入りのコメント一覧¶
あるユーザーのお気に入りコメントを検索します。
実行例:
select --table Users --query _key:bob --output_columns favorites.posted_by,favorites.comment
# [
# [
# 0,
# 1337566253.89858,
# 0.000355720520019531
# ],
# [
# [
# [
# 1
# ],
# [
# [
# "favorites.posted_by",
# "Users"
# ],
# [
# "favorites.comment",
# "ShortText"
# ]
# ],
# [
# [
# "alice",
# "charlie"
# ],
# [
# "I've created micro-blog!",
# "@alice @bob I've tried to register!"
# ]
# ]
# ]
# ]
# ]
このクエリはBobのお気に入りのコメント一覧を返します。
4.10.3.10. 投稿時間でコメントを検索¶
コメントの投稿時間で検索をします。Time 型については いろいろなデータの保存 を参照してください。
ある時刻よりも古いコメントを検索します。
実行例:
select Comments --filter 'last_modified<=1268802000' --output_columns posted_by.name,comment,last_modified --drilldown hash_tags,posted_by
# [
# [
# 0,
# 1337566253.89858,
# 0.000355720520019531
# ],
# [
# [
# [
# 5
# ],
# [
# [
# "posted_by.name",
# "ShortText"
# ],
# [
# "comment",
# "ShortText"
# ],
# [
# "last_modified",
# "Time"
# ]
# ],
# [
# "Alice",
# "I've created micro-blog!",
# 1268795100.0
# ],
# [
# "Bob",
# "First post. test,test...",
# 1268794800.0
# ],
# [
# "Alice",
# "@bob Welcome!!!",
# 1268795100.0
# ],
# [
# "Bob",
# "@alice Thanks!",
# 1268798400.0
# ],
# [
# "Bob",
# "I've just used 'Try-Groonga' now! #groonga",
# 1268802000.0
# ]
# ],
# [
# [
# 1
# ],
# [
# [
# "_key",
# "ShortText"
# ],
# [
# "_nsubrecs",
# "Int32"
# ]
# ],
# [
# "groonga",
# 1
# ]
# ],
# [
# [
# 2
# ],
# [
# [
# "_key",
# "ShortText"
# ],
# [
# "_nsubrecs",
# "Int32"
# ]
# ],
# [
# "alice",
# 2
# ],
# [
# "bob",
# 3
# ]
# ]
# ]
# ]
このクエリは2010/03/17 14:00:00以前の5件のコメントを返します。投稿者によるドリルダウン結果も含まれ、Aliceが2件、Bobが3件であることがわかります。