在lucene查询中防止“Too Many Clauses”

时间:2009-03-05 13:31:13

标签: lucene

在我的测试中,当我试图从一个由termquery和一个通配符查询组成的布尔查询中获取命中时,我突然遇到了Too Many Clauses异常。

我在网上搜索并找到他们建议增加BooleanQuery.SetMaxClauseCount()的资源。
这对我来说听起来很可疑..我该怎么办呢?我如何能够依赖这个新的幻数足以满足我的查询?在所有地狱破裂之前我能在多长时间内增加这个数字?

总的来说,我觉得这不是解决方案。必须有更深层次的问题..

查询是+ {+ companyName:mercedes + paintCode:a *},索引有~2.5万个文档。

2 个答案:

答案 0 :(得分:3)

paintCode:查询的* *部分是以“a”开头的任何paintCode的前缀查询。那是你的目标吗?

Lucene将前缀查询扩展为包含与前缀匹配的所有可能术语的布尔查询。在您的情况下,显然有超过1024个可能以“a”开头的paintCode

如果听起来像前缀查询是没用的,那么你离事实并不远。

我建议您更改索引方案以避免使用前缀查询。我不确定你要用你的例子做什么,但是如果你想用第一个字母搜索绘画代码,请创建一个paintCodeFirstLetter字段并按该字段搜索。

ADDED

如果您非常绝望,并且愿意接受部分结果,您可以从源代码构建自己的Lucene版本。您需要对PrefixQuery.java下的文件MultiTermQuery.javaorg/apache/lucene/search进行更改。在两个类的rewrite方法中,更改行

query.add(tq, BooleanClause.Occur.SHOULD);          // add to query

try {
    query.add(tq, BooleanClause.Occur.SHOULD);          // add to query
} catch (TooManyClauses e) {
    break;
}

我为自己的项目做了这件事并且有效。

如果你真的不喜欢改变Lucene的想法,你可以编写自己的PrefixQuery变体和自己的QueryParser,但我认为它不会更好。

答案 1 :(得分:0)

您好像在一个 Keyword 类型的字段上使用它(意味着您的数据源字段中不会有多个令牌)。

这里有一个建议对我来说似乎很优雅: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 。显然,这也加快了搜索过程。

您可以轻松地自动执行自动分解条款的流程,并在编制索引期间根据名称方案使用值填充文档。

如果每个字段都有多个令牌,则可能会出现一些问题。您可以在文章中找到更多详细信息