2007年12月23日日曜日

twitter

今更ながら始めた。hideaki_tです。
blogの記事書くより手軽なので、忙しいときでも簡単にかけるのが良いな。



2007年12月11日火曜日

LUCENE-969の記事訂正

よくみたら、next(Token result)ってAPIが追加されてたのね。
これ使えば問題なかった。



2007年12月6日木曜日

Connector/JのReplicationDriverとコネクションプールの問題が解決

要するに、RoundRobinLoadBalancefailOverReadOnly=trueの問題でした。

  • JDBC URLのホスト部にホストを複数書いたときに、先頭以外のホストが選ばれると、そのコネクションはfailover状態に設定される。
  • failover状態になると、failOverReadOnlytrueなら当然そのコネクションはReadOnlyなコネクションになる。
  • この状態(failover&failoverReadOnly=true)になると、setReadOnly(false)しても書き込み可能にならないので書き込もうとすると例外が発生する。
  • そんなコネクションがc3p0やらdbcpでプールされるが、書き込みたいときに書き込み可能コネクションがとれるとは限らない。

解決策の案
プールを別にする



Tokenつかいまわし(LUCENE-969)の罠

訂正: ちゃんと使えば問題ありません
何にも考えずに、Tokenizerで1つのTokenだけ保持して使い回すようにしたら、
今まで検索できていたものが検索できなくなった。
queryrewrite&toStringしてやっと気付いた。気付くまで時間がかかってしまった。
TokenをつかいまわすTokenizer/AnalyzerQueryParserで使うと、
Analyze結果をPhraseQueryとかにするために、TokenVectorに入れて保持してるから、
最終的に取得できるQueryでつかうTermが全部同じになってしまう。
気付けば当たり前なんだけど。
Indexの構築は問題なかった。

2007年12月1日土曜日

Lucene2.3を見てみる

いつ出るのかわからないけど、かなり性能が改善しているようなので見てみた。

うれしい改善

  • Fieldつかいまわし(LUCENE-963)。これでDocumentも使い回せる。
  • Tokenつかいまわし(LUCENE-969)。Tokenizer内でTokenを使い回す。
  • IndexReader.reopen()(LUCENE-743)。Searcherを作り直さないで良いなら、かなり便利になる気がする。
とりあえず、Field使い回しと、Token使い回しをしてみた。どっちも簡単。

Field使い回し

フィールドの数だけFiledのインスタンスを作っておいて、Documentにaddしておく。
あとは、実際にインデックスにつっこみたい文書を、作っておいたフィールドにそれぞれ設定して、
IndexWriterにdocをaddすればいい。docに対してaddするのは最初だけで良い。

final Document doc = new Document();
final Field url = new Field("url", "", Field.Store.YES, Field.Index.UN_TOKENIZED, Field.TermVector.NO);
final Field title = new Field("title", "", Field.Store.NO, Field.Index.TOKENIZED, Field.TermVector.NO);


final Field desc = new Field("desc", "", Field.Store.NO, Field.Index.TOKENIZED, Field.TermVector.NO);
doc.add(url); doc.add(title); doc.add(desc);
for (Content c: clist) {
    url.setValue(c.url);
    title.setValue(c.title);
    desc.setValue(c.desc);
    indexWriter.add(doc);
}


Token使い回し

Tokenをコンストラクタで作っておいて、nextが呼ばれるたびにTokenに設定されている値を変えるだけ。
Termを書き換えるのに、termBufferを書き換えた方が良いようなのでそうしてみる。

final int len = term.length();
char[] buf = token.termBuffer();
if (buf.length < len) {
  buf = token.resizeTermBuffer(len);
}
term.getChars(0, len, buf, 0);
token.setTermLength(len);

まだベンチマークしてないから、どれだけ効果あるのか不明。


ChasenTokenizerをいじる

ChasenTokenizerを使う場合、Filedのvalueの方に空文字列を設定すると、例外が出て死ぬ(QUITの応答を処理しちゃうから)。
なので、コンストラクタで空かどうか確認するようにしてみた。mark(1)してから1文字読んでみて、-1が帰ってきたらサーバに接続しないようにした。読めたらresetして今まで通り。
connectorがnullでは無いことを仮定しているコードなので、closeとかnextも修正しないと駄目。