2012年9月8日土曜日

レコーダーのSchema

レコーダーのデータベース Schema について。
要するに必要な情報は何かということと情報へのアクセスのしやすさを考えなくてはならない。というメモ。

デバイス

デバイスの情報
そんなに重要な情報ではないけど、予約の衝突検出とかで使うと思う。
かといって、物理的な情報 (/dev/pt3video*とか)は別にいらん。なぜならrecpt1が空いてるデバイスを勝手に選んで使ってくれるから(たぶん)
録画マネージャ側でいくつ録画が走っているかわかる(ように作る)ので物理デバイスがどうなってるかは特に意識しなくていいはず。
type カラムでデバイスがどの放送波に対応しているかわかるようにはしておく。

こんな感じ

Groonga::Schema.create_table('Devices', :type => :array) do |table|
  table.uint8('number')
  table.string('type')
  table.int16('priority')
end

Array Table にしたけど 主キーをnumberにしてしまえば良かった気もする。
type カラムが string なのは Symbol を使うためだけど、格納するときに.to_sされるのでSymbolと比較する時は.to_sしないといけない…ので結局文字列で使ってる。
デバイス優先度 priority は定義したものの使ってないし、いらない気がしてる。

チャンネル

チャンネル名、チャンネル番号、サービスID、放送波タイプ(ISDB-T/S)、EPG最終更新時刻あたりあれば十分。
放送局のウェブサイトへのリンクがあるといつか便利かもしれないのでURLも。

Groonga::Schema.create_table('Channels', :type => :hash) do |table|
  table.string('name')
  table.uint32('number')
  table.uint32('service_id')
  table.string('type')
  table.string('url')
  table.time('updated_at')
end

主キーは epgdump で出力される channel_id ("#{number}_#{service_id}") を使っている。
number と service_id は recpt1 に渡すオプションに使えるもの。

番組情報

番組情報は放送波から取得している。つまりEPG。
必要な情報は チャンネル、タイトル、開始時間、終了時間、詳細くらい。
あると便利なのはイベントID。イベントIDはグローバルに一意なIDかと思っていたらどうやらサービス単位で一意なようで、主キーに使おうと思ったけど使うわけにはいかなかった。まぁサービス内でも番組を一意に特定できるので便利。
ジャンル(カテゴリ)情報も検索や絞り込みに将来使えるかもしれないから持っておく。

こんな感じ

Groonga::Schema.create_table('Programs', :type => :hash ) do |table|
  table.reference('channel', 'Channels')
  table.uint32('event_id')
  table.string('title')
  table.string('description')
  table.time('start')
  table.time('stop')
  table.string('category_ja')
  table.string('category_en')
end

結局、主キーは "#{channel_id}_#{event_id}" にした。(channel_id = "#{channel.number}_#{chunnel.service_id}")
channel は Channels テーブルのオブジェクトへのリファレンスになる。

予約情報

予約情報はほぼ番組情報と同じ。加えて Twitter で予約を要求した際の情報 'request*' と 'word' を持っている。
なぜ番組情報を Programs へのリファレンスにしないかといえば、放送波のEPGからなくなった情報はデータベースから削除しているのだが、EPG取得はわりと不安定というか環境によって取得が中途半端に終わることがあって、本来あるべき情報もそのとき削除してしまうことがあるからである。
他には予約実行時に使うデバイスの情報、録画中フラグ(running)、録画プロセスのPid(中断処理するときに必要)、優先度(priority)がある。

Groonga::Schema.create_table('Reserves', :type => :hash) do |table|
  table.reference('channel', 'Channels')
  table.uint32('event_id')
  table.string('title')
  table.time('start')
  table.time('stop')
  table.uint64('request_id')
  table.string('requested_by')
  table.string('request_text')
  table.string('word')
  table.reference('device', 'Devices')
  table.bool('running')
  table.uint32('pid')
  table.int16('priority')
end

主キーは Programs の主キーに一致する値を使い、予約と番組情報を一意に結びつけられるようにしている。
これで Programs からなくなった予約の検出も容易になる。

キーワード

キーワードとはキーワード検索で予約を登録するためのキーワードである。
重複しないように主キーはキーワードそのものにした。
一応、検索対象の放送波を限定するために type を持っているが今のところ地上波でしか使えないようにしてあるので意味が無いし、Twitter でのインタフェースでも指定できるようにはしていない
あとは Reserves と同じく Twitter の情報や優先度。

Groonga::Schema.create_table('Keywords', :type => :hash) do |table|
  table.int16('priority')
  table.string('type')
  table.string('requested_by')
  table.uint64('request_id')
  table.string('request_text')
end 

その他

Groonga の Schema はあとから変更するのはわりと楽だが型を変更するのは少々難儀を伴うので熟考すべきである。

カラムの型を変える手順は例えばこんな感じになるのかしら。

Groonga::Schema::change_table('Table') do |table|
  table.integer('new_column')
end
Groonga['Table'].each do |row|
  row.new_column = row.old_column.to_i
end
Groonga::Schema::remove_column('Table', 'old_column')
Groonga::Schema::rename_column('Table', 'new_column', 'old_column')

録画終わったら終わった情報を持っておくテーブルもあるといいかなーって思っているけど作ってない。

0 件のコメント:

コメントを投稿