2011年4月23日土曜日

Google ChromeとJavaScriptのタイマー

Chrome(dev)でウェブアプリの類を使っていると、別のタブで作業してから、アプリのタブに戻るといつもなら更新されているはずなのに更新されていないことがよく起きます。
(追記 4/27にChrome 11がStableになったので、stableでも影響を受けるようになります)

なんとなく、アクティブなタブ以外はCPU消費を軽減するためにそういうことをやっているというような記事を読んだ記憶があったので、調べてみました。

まず、Firefox5に関しての記事 たくさんタブを開く人にとってFirefox 5は福音となる…かも をみたことを思いだし読み直してみて、Chromeでやっててもおかしくないと思い調査を継続しました。

ちょっと検索して、Getting smoother animated web content while reducing CPUを見つけました。そこには次のような記述がありました。
In the forthcoming Chrome 11 release, we plan to reduce CPU consumption even for pages that are using setTimeout and setInterval. For background tabs, we intend to run each independent timer no more than once per second. 
Chrome devを使っているので、この影響を受けたのは間違いなさそう。いずれ他のブラウザでもそのうち影響が出てきそうです。

これはタイマーの使い方によっては影響の度合いは違いますが、それなりに影響が出てきそうです。
タイマーの数を節約するために、最も短い間隔で発生させたいイベントの間隔とか最大公約数的にイベントを発生させて、そのイベントハンドラ内でイベントディスパッチしたりすることがあります。
これの実現方法に、どのイベントを起こすかの制御にカウンターを使っていると、イベントの発生回数が減り、カウンタの変化が遅くなるため、イベントの発生タイミングが大きくずれることになります。

簡単なテストを書いてみて確認しました。タイマーのイベントハンドラで、イベント発生回数と時間ベースで、表示を更新するというものです。
前面に表示している間はほぼ同じ速さで数字が増えていくのに対して、裏に回すと時間ベースの方はあまり影響を受けないの対して、イベント発生回数によるほうはどんどん遅れていきます。

イベント発生回数による処理
if (++cnt % 5 === 0) {
    c = $('#counter1');
    c.text(parseInt(c.text()) + 1);
}

時間ベースの処理
var now = Date();
if (now > next) {
    c = $('#counter2');
    c.text(parseInt(c.text()) + 1);
    next = now + 1000;
}

Whooshで始める全文検索的なもの(2)

前回作ったのをGAEに乗せました。ファイルのロックがかけられなくてエラーになるので、そこだけ手を加えました(gae_fileindex.py, gae_filestorage.py)。

最初はIgoTokenizerで試していましたが、GAEに載せたらメモリ&時間食い過ぎで毎回インスタンスが停止されてしまうので、TinySegmenterに変えたらだいぶ良くなりました。

まあ、まだ試してないけど、GAEのStorageを使ってインデックスが作れるのでそっちを使った方が良いかと思います。GAEのStorageを使わないで、ファイルベースのインデックスをGAEで使うメリットは、ローカルで作ったインデックスがそのままGAEでも使えることぐらいだと思います。

リクエストを受けて検索するところ
def get(self):
        qs = self.request.get('q')
        q = self.qp.parse(qs)
        h = self.s.search(q, limit=50)
        template = self.env.get_template('main')
        self.response.out.write(template.render(results=h))

表示テンプレート
<span>ヒット総数{{results.estimated_length()}}ぐらい</span>
{#{{results.key_terms('title')}}#}
  <ol>
{% for item in results %}
    <li><a href="{{item['url']}}">{{item['title']}}</a>({{item.score}})
      <ul><li>{{item.highlights('content')}}</li></ul>
    </li>
{% endfor %}
  </ol>

2011年4月17日日曜日

lucene-gosenベースのIgoTokenizerを作成中

地震やら忙しいやらでしばらくWhoosh関係をいじってなかったので、なかなかエンジンがかからず。
そんななか、lucene-gosenの記事を見て、自分でいろいろ作るよりこれに乗った方が間違いなさそうと感じたので、乗ってみました。

結果はこんな感じ。
試した結果

ソース(sf.netで公開しようと思って登録したけど、まだ何にもしてない。パッケージ名にだけ使ってます)
とりあえず作って、NetBeansのプロジェクトごと公開した状態です。


試すには
必要なものをそろえる
  • Solr 3.1.0を展開
  • lucene-gosenの準備(jar作る。辞書は要らないけど)
  • Igoの準備(jar,辞書)
準備
  • IgoTokenizerをチェックアウト
  • libの下に必要なjarを置く(igo, lucene-core, apache-solr-core, lucene-gosen)
  • ant jar
実行
schemaは次のようにフィールド種別を指定する。
<fieldType class="solr.TextField" name="text_ja" positionincrementgap="100">
  <analyzer>
    <tokenizer class="net.sf.igoanalyzer.solr.IgoTokenizerFactory" dicpath="/home/path/to/ipadic">
    </tokenizer>
  </analyzer>
</fieldType>