質問
テストで、termqueryとワイルドカードクエリで構成されるブールクエリからヒットを取得しようとすると、Too Many Clauses例外に突然遭遇しました。
ネットを検索し、見つかったリソースでBooleanQuery.SetMaxClauseCount()を増やすことを提案しました。
これは私には怪しげに聞こえます。この新しいマジックナンバーがクエリに十分であることをどのように信頼できますか?すべての地獄が崩れる前にこの数値をどれだけ増やすことができますか?
一般に、これは解決策ではないと感じています。より深い問題があるはずです。.
クエリは+ {+ companyName:mercedes + paintCode:a *}で、インデックスには約250万のドキュメントがあります。
解決
クエリのpaintCode:a *部分は、「a」で始まるpaintCodeのプレフィックスクエリです。それはあなたが目指しているものですか?
Luceneは、プレフィックスクエリを、プレフィックスに一致するすべての可能な用語を含むブールクエリに展開します。あなたの場合、明らかに「a」で始まる1024を超える paintCode
があります。
プレフィクスクエリが役に立たないように聞こえる場合、あなたは真実からそれほど遠くありません。
プレフィックスクエリの使用を避けるために、インデックススキームを変更することをお勧めします。あなたがあなたの例で何を達成しようとしているのかわかりませんが、最初の文字でペイントコードを検索したい場合は、paintCodeFirstLetterフィールドを作成してそのフィールドで検索してください。
追加
必死で、部分的な結果を受け入れる場合は、ソースから独自のLuceneバージョンを構築できます。 org / apache / lucene / search
の下にある PrefixQuery.java
および MultiTermQuery.java
ファイルを変更する必要があります。両方のクラスの rewrite
メソッドで、行を変更します
query.add(tq, BooleanClause.Occur.SHOULD); // add to query
to
try {
query.add(tq, BooleanClause.Occur.SHOULD); // add to query
} catch (TooManyClauses e) {
break;
}
自分のプロジェクトでこれを実行しましたが、動作します。
Luceneを変更するというアイデアが本当に気に入らない場合は、独自のPrefixQueryバリアントと独自のQueryParserを作成することもできますが、これほど優れているとは思いません。
他のヒント
キーワードタイプのフィールドでこれを使用しているようです(データソースフィールドに複数のトークンがないことを意味します)。
ここには、私にとって非常にエレガントな提案があります: http://grokbase.com/t/lucene.apache.org/java-user/2007/11/substring-indexing-to-avoid-toomanyclauses-exception/ 12f7s7kzp2emktbn66tdmfpcxfya
基本的な考え方は、句の制限に達しないことが確実になるまで、用語を長さの長い複数のフィールドに分割することです。
例:
このようなpaintCodeを想像してください:
"a4c2d3"
この値にインデックスを付けるとき、ドキュメントに次のフィールド値を作成します。
[paintCode]: "a4c2d3"
[paintCode1n]: "a"
[paintCode2n]: "a4"
[paintCode3n]: "a4c"
クエリを実行するまでに、用語の文字数によって検索するフィールドが決まります。つまり、3文字以上の用語に対してのみプレフィックスクエリを実行し、内部結果カウントを大幅に減らして、悪名高い TooManyBooleanClausesException を防ぎます。これにより、検索プロセスも高速化されたようです。
用語を自動的に分類し、インデックス作成中に名前スキームに従ってドキュメントに値を入力するプロセスを簡単に自動化できます。
各フィールドに複数のトークンがある場合、いくつかの問題が発生する可能性があります。詳細については記事をご覧ください