よくみたら、next(Token result)ってAPIが追加されてたのね。
これ使えば問題なかった。
要するに、RoundRobinLoadBalanceとfailOverReadOnly=trueの問題でした。
- JDBC URLのホスト部にホストを複数書いたときに、先頭以外のホストが選ばれると、そのコネクションはfailover状態に設定される。
- failover状態になると、
failOverReadOnlyがtrueなら当然そのコネクションはReadOnlyなコネクションになる。 - この状態(failover&
failoverReadOnly=true)になると、setReadOnly(false)しても書き込み可能にならないので書き込もうとすると例外が発生する。 - そんなコネクションがc3p0やらdbcpでプールされるが、書き込みたいときに書き込み可能コネクションがとれるとは限らない。
解決策の案
プールを別にする
訂正: ちゃんと使えば問題ありません。
何にも考えずに、Tokenizerで1つのTokenだけ保持して使い回すようにしたら、
今まで検索できていたものが検索できなくなった。
queryをrewrite&toStringしてやっと気付いた。気付くまで時間がかかってしまった。
TokenをつかいまわすTokenizer/AnalyzerをQueryParserで使うと、
Analyze結果をPhraseQueryとかにするために、TokenをVectorに入れて保持してるから、
最終的に取得できるQueryでつかうTermが全部同じになってしまう。
気付けば当たり前なんだけど。
Indexの構築は問題なかった。
いつ出るのかわからないけど、かなり性能が改善しているようなので見てみた。
うれしい改善
- Fieldつかいまわし(LUCENE-963)。これでDocumentも使い回せる。
- Tokenつかいまわし(LUCENE-969)。Tokenizer内でTokenを使い回す。
- IndexReader.reopen()(LUCENE-743)。Searcherを作り直さないで良いなら、かなり便利になる気がする。
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);
python+cmecabを使って、chasen server(chasend?)もどきを書きました。
LuceneでJapaneseAnalyzer+ChasenTokenizerで使う事しか考えてないけど、とりあえず使える。
いまいち仕様がわからないので、ChasenTokenizerのソースとmecab -Ochasenの出力を見て書いてみた。
いろいろWindows用にポーティングしたりするのに疲れたので、ubuntu7.10をノートに入れたcoLinux(Snapshot 20071105 of version 0.8.0 with kernel 2.6.22,compiled with gcc 4.1.2)で使えるようにしてみた。
coLinuxでUbuntu 7.04をネットワークインストールを参考に、7.10のファイルを使うようにしただけ。
ネットワークはslirpにした。
初めてubuntuつかうけどdebian使ってた(まだ残ってるけど)から、まあなんとなく勝手はわかる。
メイン機以外だとビルドしまくるgentooは厳しいし、メモリが多くないノートだとOpenSolarisをVMWareで動かすのも厳しい。
deibanのsidとか、gentooの~みたいなのはないのかな?experimentalってやつかな?
頼まれたので簡単に調べてみた。
- 文字列の連結は
& - 文字列をセル参照指定としてつかうには、
INDIRECT
- 1つ目の値を列指定文字に変換(
IFでやった) - 2つ目の値を行指定文字に変換(
IFで) - 連結(
&で) INDIRECTで参照
pythonで辞書の値でソートしたかったので適当に考えてみたけど、検索したら普通の方法っぽい。
>>> d = {"a": 9, "b":5, "c":10, "d":0}>>> for i in sorted([(v, k) for k, v in d.items()]):print i(0, 'd')(5, 'b')(9, 'a')(10, 'c')>>>