要允许用户使用Lucene 3.5搜索多个字段,我目前正在为要搜索的每个字段创建QueryParser并添加DisjunctionMaxQuery到{{3}}。使用 OR 作为默认运算符时效果很好但我现在想将默认运算符更改为 AND 以获得更准确(和更少)的结果。
问题是,queryParser.setDefaultOperator(QueryParser.AND_OPERATOR)
错过了很多文件,因为所有条款都必须在至少1个字段中。
例如,考虑文档的以下数据:title field =“Programming Languages”,body field =“Java,C ++,PHP”。如果用户要搜索 Java编程,则此特定文档将不会包含在结果中,因为标题和正文字段包含查询中的所有术语,尽管它们组合在一起。我希望为上述查询返回此文档,但不希望查询 HTML编程。
我认为这是一个笼罩的领域,但我遇到了一些问题。首先,用户经常在他们的查询(作者:账单)中包括每个字段术语,这对于一个catchall字段是不可能的。此外,我使用FastVectorHighlighter突出显示某些字段,这需要对它们进行索引和存储。因此,通过添加一个catchall字段,我必须将大部分相同的数据索引两次,这是耗费时间和空间的。
有什么想法吗?
答案 0 :(得分:6)
猜猜我应该做更多的研究。结果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的帮助!
答案 1 :(得分:2)
您可能需要的是结合使用布尔查询来捕获字段和术语的不同组合。在您给出的示例中,查询可以是 -
(标题:Java AND body:programming)或(标题:编程和正文:Java)。
我不知道是否有一个现有的Query类会自动为您生成,但我认为这应该是在索引上运行的最终查询。
答案 2 :(得分: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查询限制同一个词(在不同领域)的多个查询中得分增长,但你确实希望得分能够以不同的条件增长,我相信。 / p>
如果这种查询结构能让您获得更好的分数结果,那么将结果限制在某个最低分数(返回的最大分数的百分比,而不是简单的硬编码值)可能足以防止过于微弱的结果被人看见。
我还是不计算索引所有字段。这是我之前使用的一个实现,同时索引特定字段和catchall字段,从而允许一般查询和特定的单字段查询。对于未存储的术语,索引存储往往非常精简,如果您发现自己必须创建大而复杂的查询来弥补没有它,它通常会有助于提高性能。
如果你真的想确保它占用最少的存储空间,你甚至可以关闭该字段的TermVectors:
new Field(name, value, Field.Store.NO, Field.Index.ANALYZED, Field.TermVector.NO);
虽然我不知道会有多大差异。