8

为了允许用户使用 Lucene 3.5 搜索多个字段,我目前为要搜索的每个字段创建并添加一个QueryParser到DisjunctionMaxQuery。这在使用OR作为默认运算符时效果很好,但我现在想将默认运算符更改为AND以获得更准确(和更少)的结果。

问题是,queryParser.setDefaultOperator(QueryParser.AND_OPERATOR)由于所有术语必须在至少 1 个字段中,因此遗漏了许多文档。

例如,考虑文档的以下数据:title field = "Programming Languages",body field = "Java, C++, PHP"。如果用户要搜索Java Programming,则此特定文档不会包含在结果中,因为标题和正文字段包含查询中的所有术语,尽管它们组合在一起。我希望为上述查询返回此文档,而不是为查询HTML Programming

我考虑过一个包罗万象的领域,但我有一些问题。首先,用户经常在他们的查询中包含每个字段的术语(作者:bill),这对于一个包罗万象的字段是不可能的。此外,我使用 FastVectorHighlighter 突出显示某些字段,这需要对它们进行索引和存储。因此,通过添加一个包罗万象的字段,我将不得不对大多数相同的数据进行两次索引,这既费时又费空间。

有任何想法吗?

4

3 回答 3

7

我想我应该做更多的研究。事实证明MultiFieldQueryParser提供了我正在寻找的确切功能。无论出于何种原因,我都为我想搜索的每个字段创建了一个 QueryParser,如下所示:

String[] fields = {"title", "body", "subject", "author"};
QueryParser[] parsers = new QueryParser[fields.length];      
for(int i = 0; i < parsers.length; i++)
{
   parsers[i] = new QueryParser(Version.LUCENE_35, fields[i], analyzer);
   parsers[i].setDefaultOperator(QueryParser.AND_OPERATOR);
}

这将导致这样的查询:

(+title:java +title:programming) | (+body:java +body:programming)

...这不是我想要的。现在我像这样创建一个 MultiFieldQueryParser:

MultiFieldQueryParser parser = new MultiFieldQueryParser(Version.LUCENE_35, new String[]{"title", "body", "subject"}, analyzer);
parser.setDefaultOperator(QueryParser.AND_OPERATOR);

这给了我正在寻找的查询:

+(title:java body:java) +(title:programming body:programming)

感谢@seeta 和@femtoRgon 的帮助!

于 2012-12-17T22:10:05.117 回答
2

也许您需要的是布尔查询的组合,这些查询可以捕获字段和术语的不同组合。在您给定的示例中,查询可能是 -

(标题:Java 和正文:编程)或(标题:编程和正文:Java)。

我不知道是否有一个现有的 Query 类可以为您自动生成它,但我认为这应该是在索引上运行的最终查询。

于 2012-12-17T02:41:12.330 回答
0

您希望能够使用相同的术语集搜索多个字段,然后是您评论中的问题:

((title:java title:programming) | (body:java body:programming))~0.2

可能不是最好的实现。

您实际上是从标题中获得分数,或者从正文中获得组合术语的分数。在标题中点击 java 并在正文中编程的情况将给出大约。与对身体的 Java 的打击相等,对编程没有打击。

我认为更好的结构化查询是:

(title:java body:java)~0.2 (title:programming body:programming)~0.2

这对我来说更有意义,因为您希望 dismax 查询限制同一术语(在不同字段中)的多个查询的分数增长,但我相信您确实希望不同术语的命中分数增长。

如果这种查询结构可以让您获得更好的分数结果,则将结果限制在某个最低分数(返回的最高分数的百分比,而不是简单的硬编码值)可能足以防止看到太弱的结果。


我仍然不会计算索引所有字段。这是我以前使用过的一种实现,同时索引特定字段和包罗万象的字段,从而允许通用查询和特定的单字段查询。对于未存储的术语,索引存储往往非常精简,如果您发现自己必须创建大而复杂的查询来弥补没有它的情况,它通常会提高性能。

如果您真的想确保它占用最少的存储空间,您甚至可以关闭该字段的 TermVectors:

new Field(name, value, Field.Store.NO, Field.Index.ANALYZED, Field.TermVector.NO);

虽然我不知道这会带来多大的不同。

于 2012-12-17T07:50:29.150 回答