2009年12月27日日曜日

MySQL でレコードのランダム抽出をするには

ORDER BY RAND() で OK。

ただ、全レコードに対してランダムな数値を与えてインデックスなしでソートするのでそれなりのコストがかかる。

この場合の計算量はどうなんだろう。ソートの実装がどうなっているのかは知らないので確かなことは分からないけれど、LIMIT をつけずに全レコードをランダムソートするならば計算量はよくて O(N log N)程度のはず。LIMIT で K 件(K < log N)を抽出する場合は、愚直にやっても O(KN)あればできる。

よって、1件ずつランダム抽出していくような場合は大して問題にならないが、リストとしてまとめてランダムに並んだレコードを取り出したい、というような場合にはあまり効率的でない。
そういった場合には事前にインデックスつきのフィールドに RAND() を書き込んでおいて、取得したいときにそのフィールドで ORDER BY してやったほうがいいはず。

2009年12月26日土曜日

Django の ModelForm / ModelFormSet まとめ

ModelForm の扱いが分かってきたのでまとめ。

なぜ ModelForm を使うのか (普通の Form との違い)

普通のフォームはデータベースの構成とは独立しているので自由に入力フォームを作成することができる反面、データベースの構造を反映したフォームを作成する際には、モデルの記述とほぼ同じ内容をもう一度書き下す必要が出てくる。これは冗長であるし、またモデルの変更をフォームに反映しなければならない点で保守性が低い。
きれいに構成された Web アプリケーションであればデータの入出力はデータベース上での生成、変更、削除にほぼ対応しているわけで、そのようなシーンにおいて、モデルを反映した入力を実現するためにモデルから半自動的にフォームを生成するものが ModelForm である。

ModelForm の定義

モデルフォーム内のサブクラス "Meta" の属性として各種の定義を書く。
  • model 属性: フォームのもととなるモデル
  • fields 属性: モデルの中でこのフォームに含めたいフィールド
各々のフィールドがどのようなフォームで表示されるか (テキストなのかチェックボックスなのかプルダウンメニューなのか等々)は、モデルで指定したフィールドのタイプに基づいて適当なものが選択される。
とはいえ実際の運用においては表示の仕方を変えたいことも多々ある(最もよくあるのは hidden にしたい場合など)ので、これは変更することが可能。
これは Meta 内ではなく、モデルフォーム自身の属性として記述。

ModelFormSet

一度に複数のレコードを編集する場合、同じモデルフォームをそのまま複数並べるわけにはいかない。(同じ name を持つ input 要素が複数作成されて、submit されてもどれとどれを組み合わせるのか分からなくなるから。)
FormSet はこの問題を解決するためのもの。ひとまとめに扱う input 要素ごとに id (フォームセットの内部的なもの。HTML の id 属性ではない) を作成してフォームの name 属性を適宜変更、送信されたデータをきちんとグループ分けして一つ一つのフォームを切り分けてくれる。
ModelFormSet は、上述の Form と ModelForm の関係ように、Model を反映した FormSet。

ModelFormSet の定義

modelformset_factory に、ベースにしたいモデルを渡す。
フィールドの表示の種類を変更するためには、意図する表示を定義した ModelForm を予め定義しておき、引数に "form=モデルフォーム名" を追加してやればよい。
ここで、上述の引数として渡したモデルフォームにおいて、fields 属性が定義されていても、新たに作成される ModelFormSet はそれらを無視して全てのフィールドに関してフォームを作成する点に注意。
これを抑制するには、modelformset_factory の 引数に "fields=フィールド名リスト" を与える。

データ受信後の処理

POST でデータを受け取ってからは、送信されたデータをデータベースに書き込むことになる。
ここで、既存のデータを変更する場合には注意すべき点がある。
基本的に、ModelForm のデータを保存する場合はモデルフォームオブジェクトの save メソッドを利用する。
これは新規作成(SQL でいうと INSERT)でも上書き(SQL でいうと UPDATE)でも同じで、Django はそれらを自動的に使い分ける。
使い分けの基準は、"保存しようとしているデータの主キー値と同じ主キー値を持つレコードがあれば UPDATE、それ以外は INSERT"となっている。
よって、既存のデータを UPDATE するためには、必ず主キーをフォームの中に含めなければならない。
また、一部のフィールドのみを用いたモデルフォームの場合、除外したフィールドが必須であった場合、その値を与えなければ is_valid が False となり保存できない。
このような場合は、受信後にフォームインスタンスを作成する際に、POST データとともにもとのデータベースレコードを渡してやることで、フォームに含まれているフィールドはその値を、そうでないフィールドはデータベースの値を用いて、不足するデータを補ったフォームオブジェクトを作成することができる。
渡し方は、モデルフォームの場合は引数 instance、モデルフォームセットの場合は引数 queryset。

2009年12月25日金曜日

ruby in HTML

ruby と言っても言語の方ではありません。HTML の ruby (ルビ)タグです。
そもそも ruby というタグが HTML のセマンティクス的に許されるかどうかというのは十分議論の余地があるとは思いますが、文字列に近接して付記すべき情報があるのも事実。
で、ここ12時間くらいどうすべきか迷ったことをメモ。

ruby タグの使い方

  1. ルビを振りたい部分を <rb> でマークアップ
  2. ルビとして表示したい文字列を上記 <rb> に隣接する <rt> 内に記述
  3. <rb> と <rt> を <ruby> でマークアップ
例えば
田んぼと<ruby><rb>案山子</rb><rt>かかし</rt></ruby>ののどかな風景

と書くと
田んぼと案山子かかしののどかな風景
となります。

ブラウザ互換性の問題

となります、と書きましたが、上記のサンプルは Internet Explorer もしくは Google Chrome 以外のブラウザではきちんと表示されなかったことと思います。というのは主要なブラウザのうち上記の2つ以外には ruby タグが実装されていないためです。そのため互換性を実現するにはそれなりの workaround が必要になります。
(正直なところそういう見苦しい HTML は書きたくないのですが、差し迫って必要なのだから仕方がない。ちなみに CSS 3 には ruby が含まれているようなのでそのうち他のブラウザでも利用できるようになるのでしょう。)

Firefox における ruby

この手の話はあらゆるブラウザに対応することを目指すときりがなくなるので、今回のサイトが研究室内の他のメンバーに見てもらうためのものであることを踏まえて Firefox できちんと表示できればそれでよしとすることにします。
手っ取り早い方法としては、そのためのアドオンを導入する手があります。しかしながら今回のサイトはどちらかというと周囲にお願いして見てもらうものであるので、できるだけ利用のためのハードルを低くしておくためにもユーザ側では作業をさせたくありません。なので CSS で対処したいと思います。
調べたところ、こちらのサイトに書かれている CSS がベストな解となりそうです。
簡単に言うと、ruby を inline-table、rb を table-row、rt を table-header-group とするというものです。
ただ、そのまま上記のタグの属性を変更すると、もともと ruby をきちんと表示できているブラウザにおいて表示が崩れるので、span に class を設定してクラスセレクタで CSS を設定するのがよさそうです。
先ほどの例をこの方法でマークアップすると以下のようになります。
<style>
#ruby{
display: inline-table;
vertical-align: bottom;
}
#rb{
display: table-row;
}
#rt{
display: table-header-group;
}
</style>
田んぼと
<span class="ruby">
<span class="rb">
案山子
</span>
<span class="rt">
かかし
</span>
</span>
ののどかな風景

そしてこれを表示するとこのようになります。
田んぼと案山子かかしののどかな風景

意図した通りになっているのではないでしょうか。
上記の場合、ルビのサイズを地の文よりも小さくするために rt の font-size を50%に、また周囲の語との垂直方向の位置会わせのために ruby の vertical-align を bottom に設定しています。
とりあえずこれだと Firefox 以外に Chrome、Safari でもきちんと表示できるようです。

さらなる問題

さて、ここまででルビを振ることはできた訳ですが、ちょっとした問題に遭遇しました。
<rb> 内に、間に空白を挟んだ複数の <span> を配置すると、空白が反映されません。
SPAN1 SPAN2RUBY

中身だけであれば
SPAN1 SPAN2

と、きちんと間に空白が表示されるので、おそらく table-row の中に直接 span を複数配置しているのが何らかの影響を与えているものと思われます。
これは、上記の複数の span を、さらに一つの span にまとめてやることで回避できます。
SPAN1 SPAN2RUBY
あまり詳しくないので確定的なことは言えないのですが、おそらく table-row の中には table-cell に相当する要素が必要だということなのではないかと推測しています。

以上、とても胸を張れないバッドノウハウでした。

2009年12月22日火曜日

Django の分からないところ

調べてみたけど分からなかったことリスト。(随時更新)
知っている方、教えていただけると本当に助かります。
あるモデルの一部のフィールドのみ編集可能にしてそれ以外は表示だけさせたい

複数のフィールドを持つモデルの値のうち一部を書き換える場合。例えばこんなかんじで。オブジェクトとそれをインスタンスとして作ったフォームオブジェクトをコンテキストに突っ込めばテンプレートから参照はできるけれど、なんだか冗長だし、複数のインスタンスを一度に編集できるようにしたい場合などはテンプレートにリストが2つ渡って対応付けしたりとややこしくなる。
フォームオブジェクトから value を抜き出して表示することがテンプレートからできれば万事解決なんですが、そういう方法ってないのだろうか。

複合キーを扱いたい

とりあえず現時点では扱えないらしい?
複合キーにすべきフィールド以外に主キーをたてておく。
データモデリング的によろしくないが実用上は複合キーで検索してリレーションには主キーを使えばまあ問題ないか。
(追記) モデルオブジェクトの Meta 内で unique_together(フィールド名リスト) で指定可能だった。

ModelForm での is_validがよくわからない

何をチェックしているのかよくわからない。モデルで指定した「省略可能」 (blank=True) とか 「ヌル値許容」 (null=True) とかの条件にフォーム内データが合致しているか否かをチェックしているのだろうとは思うけれど、暗黙の主キーである id フィールドがフォームに入ってると問答無用で False を返される。なぜ?
追記: 主キーの値の重複が不正と見なされている。下に書いたように主キーを指定した場合は update になるので問題ないはずだが、なぜか invalid となっている。なぜ?
追記: ここに答えがあった。つまり
  1. 主キーは POST パラメータではなく URL で渡す
  2. そこから取得した主キーをもとにして既存レコードのインスタンスを取得する
  3. そのインスタンスと POST パラメータを一緒に渡してインスタンスを作り直す
が正解の模様。

Django は insert と update を勝手に呼び分ける

save が呼ばれたデータの Primary Key が既にデータベースに存在すれば update、なければ insert を実行する。Primary Key が Python 的に False である場合は update する。例えば Primary Key の値が入ってないデータは insert になるので、Primary Key 以外に unique 制約を持つデータなどは、既存データのつもりでうっかり Primary Key のフィールドを入れずに save したりすると insert されて unique 制約に引っかかる、とかありそう。

メモリリーク?

大量データ(300万レコードほど)をデータベースに突っ込むために Django のモデルをインポートして作成したスクリプトをコマンドラインで走らせているとどんどんメモリを食う。やっていることはレコードごとに関数を読んで、その中で新たにモデルのインスタンスをローカル変数に代入して save するというだけ。関数から抜けた後にどこかの時点で GC にかかることを期待していたのだけれど、どうもそうなってはくれない模様。

2009年12月6日日曜日

あす楽がよかった

3週間ほど前から友人達と今日鍋をする約束をしていました。
せっかくの機会だから外で食べると高いカニでも食べようということで楽天の店に注文していたのですが、3日前に「その商品が受注可能でないのに誤って掲載されていたのでキャンセルとします」という連絡が来たとのことで、その夜に急遽あす楽対応の店に切り替えて注文し直しました。

あす楽だと正午までの受注は翌日着になるものの、旭川の店とのことできちんと夕飯に間に合うのか半信半疑だったのですが、驚いたことに朝の10時に着きました。どうやって発送するのか知らずに注文していたのですが、航空便で届くんですね。

Amazon のお急ぎ便でもかなりすごいと思っていたのですが、まさか冷凍の食品を航空便で送ってもらえるなんて夢にも思っていなかったので驚きでした。
コスト的に大丈夫なのか気になりますが、利用する側としてはありがたいサービスです。

2009年12月3日木曜日

Google の日本語インプットメソッドを使ってみた

なにやら Google が日本語のインプットメソッドを作ったらしい。

Google Japan Blog: 思いどおりの日本語入力 - Google 日本語入力
http://googlejapan.blogspot.com/2009/12/google_03.html

ほぼ間違いなく世界最多のテキストデータを持っているであろう Google だからこういう利用法を思いつくのはごく自然な流れですよね。
関わっているのも数々の機械学習ライブラリや MeCab で知られる工藤拓さんはじめオープンソースの日本語インプットメソッドの開発者とくれば期待も高まります。

で、使ってみているところです。

まだあまり長く使ってないので大した感想は書けないんですが、特に不満を感じない完成度であることは分かりました。
とりあえず、スペースで変換、タブでいわゆる補完になっている模様。この辺は ATOK と同じですね。
長い慣用句、しかも最近の言い回しが補完候補に出てきたりして、手元で Google Suggest が動いてるような感覚です。

2009年11月26日木曜日

事業仕分けに関する声明発表を聞いてきた

今日小柴ホールで最近話題の事業仕分けに関してノーベル賞・フィールズ賞受賞の先生方の声明発表があるとのことで聞きに行ってきました。

大筋として、今回の事業仕分けのやり方が学術分野の予算を検討するにふさわしくないとの主張には賛成です。というのも、同じ国家予算の使途とはいえ、いわゆる公共サービスの提供事業と学術的な事業は評価のされ方が大きく異なるものであるからです。

公共サービスはすでに社会から必要とされているものを提供するのであって、その達成自体が国民の利益となる性質のものです。そのため目標達成のためのプロセスと、外部の人間にとっての評価基準が比較的明確で、その事業自体が無駄であるか否か、またそのためのコストが適切に計上されてされているかどうかを検証しやすい類のものです。
一方で学術的な研究活動は、研究を行っている段階でそれがどのように国民の利益につながるのか必ずしも明確ではありません。けして少なくない数の研究成果が日の目を見ずに埋まってしまうものだと思います。そしてそれらのうちごく一部がブレイクスルーにつながり、経済を潤して生活を豊かにしてきました。ですが、それがどれなのか事前に判断することは容易ではありません。(判断ができるものは国が手を出さずとも民間で積極的に研究されることでしょう。)

今日の講演者の話に「GPS を実現するには相対論が必要」だという例が挙げられていました。もちろんアインシュタインは GPS を実現するために研究をしたわけではありません。おそらく当時の役人や政治家に「運動する物体の時の流れは遅くなるのだ」と力説したところでその研究の意義を見いだすことはできなかったでしょうし、アインシュタインに「GPS のような応用例を出して分かりやすくプレゼンしろ」と言うのも無理な話です。しかし、そのような研究でも結果的に私たちは確かにその利便性を享受しています。小柴先生は自身の研究成果を「何の役にも立たない」と述べられたそうですが、それが本当に何の役にも立たないかはまだ誰にもわかりません。(というよりも、「役に立つ」ことは未来のある時点で証明される可能性がありますが、「役に立たない」ことは人類が絶滅するまでは誰にも証明できません。)

そういう基礎研究に対して、「現時点で役に立つことが証明できなければ継続させられない」と断罪しては大きな機会損失を生じさせる可能性があるわけで、野依先生の「科学技術や教育は短期的な費用対効果で評価されるべきではない」という主張は至極尤もであるように思います。

ただしこれはあくまで基礎研究に関することであって、スパコンの話のような応用寄りの研究に関しては、ある程度の説明責任はあると感じています。それにしたって「目指すのは2位でもよいではないか」との主張は的外れであると思いますが。

追記: この発言は本当に疑問に思っていたためではなく相手に説明の契機を与えるためのものであったとの記述を他のブログで見かけました。その真偽は確認しておりません。
この件に関しては金田先生のサイトからリンクが張られていた以下のサイトの記述が参考になります。


テレビで報じられているものとはずいぶん違った印象を受けました。

メディアといえば、今日の会見でどう考えても報道には乗らない発言があったので、ここに書いておきます。
朝日新聞の記者の「一般の人に科学の大切さを理解してもらうには?」との質問に対して、冗談交じりに利根川先生
「マスコミがいけない。アメリカの有力な新聞社などでは科学部に各分野の専門家、それも Ph.D. をもっているような人を揃えている。そのため一定以上の層の科学に対する理解と基礎研究の重要性の認識が確保されている。数学でも物理学でも一人でやらせる日本の新聞社とは大きな差がある。」
日本の新聞社の実態がそうなのかどうかは分かりません、と申し添えておきます。

2009年11月23日月曜日

Command Line Browser 0.6














Warning:
Command APIs are modified and command definitions on your PC are going to be replaced with new default commands when you update the add on.
If you have written scripts in the config page, please back them up in advance.

ChangeLog:
  • Each command can have an icon. (Defined as an URL in command definition)
  • Emphasized selected completion candidate
  • Backward candidate select by Shift-Tab key
  • Added some commands
    • Google Blog Search
    • Google Image Search
    • Google Maps Search
    • delicious Search
    • Wikipedia Japan Search
    • Yahoo! Japan Search
    • Yahoo! Japan Auction Search
    • Amazon Japan Search
    • kakaku.com Search
  • Renamed "google-scholar" command to "google/scholar"
Download: Command Line Browser

2009年11月19日木曜日

Google Preview for Chrome 0.5

ChangeLog:
  • Implemented configuration page (type "chrome://extensions/" into omnibox, and you will find it)
  • Variable image size (you can define it in configuration page)
Therefore you can do something like this...













2009年11月6日金曜日

Command Line Browser 0.5















Warning:
Command APIs are modified and command definitions on your PC are going to be replaced with new default commands when you update the add on.
If you have written scripts in the config page, please back them up in advance.

ChangeLog:
  • Command APIs have been changed
  • Default command definitions are updated

Now you can get keyword suggestions in "google" command.
Furthermore, commands can get modification keys when it is executed.
Each default command opens new tab when it is triggered by "Alt-Enter" key.

2009年11月1日日曜日

Command Line Browser 0.4


















ChangeLog:
  • Implemented configuration window.
  • Bug fix: URI encode for search commands.
Please type "chrome://extensions/" in omnibox, then click "Options" in "Command Line Browser" section.
You can edit, add, and delete commands.
I'll write short coding guide afterward.

2009年10月30日金曜日

Google Preview for Chrome 0.4

ChangeLog:
  • Append anchor tag to thumbnails
Download: Google Preview for Chrome

2009年10月29日木曜日

Command Line Browser 0.3










ChangeLog:
  • Command complement available (tab key)
  • Renamed existing commands ("o" -> "open", "s" -> "google")
  • "google-scholar" command
  • Placed the form at the center of the window
  • Command definition has been moved to "background.html"
Download: Command Line Browser

2009年10月28日水曜日

Updated Command Line Browser








ChangeLog:
  • Incremental search for commands available
Download: Command Line Browser

2009年10月27日火曜日

Updated Google Preview for Chrome



















ChangeLog:
  • Changed thumbnail apis from SimpleAPI to HeartRails
  • Changed thumbnail size to 160 x 120
  • Adjusted style sheet
It looks better now.
Enjoy!

2009年10月25日日曜日

Command Line Interface for Chrome

I have been using Mozilla Firefox with Vimperator.
It is not ported to Chrome, therefore I am using ChromeKeyconfig, but it does not support command line operations like "open http://~~~" which are available on Vimperator because this add on focuses only on key configuration.
(I think this should be as-is because key event reassignment and command line interface are quite different functions to be implemented in one add on.)

Then I wrote a simple add on which enables command line operations on Chrome.

Download: Command Line Browser

After install this, please type a colon.
An input field will appear on your screen, and you can execute some actions.
Only 2 actions are implemented so far, "open url" (command "o") and "search with google" (command "s").
I'd like to append other functions afterward, and if you'd like to do it by yourself, you can do it by editing "Command definitions" part of script.js.
The script is so simple that you will be able to edit it easily.
(If you need more detailed information, please tell me.)

Finally, If you know how to manipulate tabs and windows from Chrome extentions, I would appreciate it if you could write it in comments.
I tried to get window size with "chrome.windows.getCurrent" or something like that, but it wouldn't let me touch windows.

Oct 29
Resolved.
Most chrome.* APIs are not accessible from content script.
But we can get window size by window.innerHeight and window.innerWidth.

Updated Google Preview for Chrome

Updated Google Preview for Chrome to cooperate with AutoPatchWork.
Now it receives events thrown by AutoPatchWork and appends thumbnails for succeeding search results.

Download: Google Preview for Chrome

2009年10月23日金曜日

Google Preview for Chrome


I've begun to use Google Chrome, but I can't find any add on works like Google Preview for Mozilla Firefox.

Therefore I made it for myself.

Download: Google Preview for Chrome