我目前在为Lucene / Solr指定过滤器时遇到问题。我提出的每个解决方案都打破了其他解决方案让我先举一个例子。假设我们有以下5个文件:
所以我需要构建以下过滤器查询:
给我所有类型的文件:已售出的汽车:仅假,如果是与汽车不同的类型,则包含在结果中。所以基本上我想要文档1,2,4,5,我不想要的唯一文件是doc3,因为它已售出:true。更准确地说:
for each document d in solr/lucene
if d.type == Car {
if d.sold == false, then add to result
else ignore
}
else {
add to result
}
return result
过滤所有(类型:Car和sold:false)或(类型:Bike和productID:1)的文档。因此,我将获得1,2,5。
注意:您不知道文档中的所有类型。这显然是因为文件数量很少。
所以我的解决方案是:
答案 0 :(得分:1)
好的,除了售出的汽车外,你可以使用-(type:Car sold:true)
。
这可以合并到其他查询中,但是你需要小心这样的孤独的否定查询。一般来说,Lucene不能很好地处理它们,Solr也有一些奇怪的陷阱。特别是,A -B
更像是“得到所有A但禁止B”,而不是“获得所有A和除B以外的任何东西”。与A or -B
类似的问题,请参阅this question了解更多信息。
为了解决这个问题,您需要使用一组额外的括号来包围否定,以确保Solr将其理解为独立的否定查询,例如:(-(type:Car AND sold:true))
所以:
-(type:Car AND sold:true)
(这不会得到您所说的结果,但根据我的评论,我并不理解您的陈述结果)
(type:Bike AND productID:1) (-(type:Car AND sold:true))
(你实际上是在问题描述中写的!)
(-(type:Car AND sold:false)) owner:(John Brian Josh)
答案 1 :(得分:0)
我的建议是使用程序化Lucene(即使用Java Lucene API直接在Java中)而不是发出将被解释的文本查询。这将为您提供更细粒度的控制。
您要做的是使用QueryWrapperFilter API构建Lucene过滤器对象。 QueryWrapperFilter是一个过滤器,它接受Lucene查询,并筛选出与该查询不匹配的任何文档。
为了使用QueryWrapperFilter,您需要构建一个与您感兴趣的术语相匹配的查询。最好的方法是使用TermQuery:
TermQuery tq = new TermQuery(new Term("fieldname", "value"));
正如您可能已经猜到的那样,您需要将“fieldname”替换为字段名称,将“value”替换为所需值。例如,根据OP中的示例,您可能希望执行new Term("type", "Car")
。
这只匹配一个词。您将需要多个TermQueries,以及一种将它们组合在一起以创建单个更大查询的方法。最好的方法是使用BooleanQuery:
BooleanQuery bq = new BooleanQuery();
bq.add(tq, BooleanQuery.Occur.MUST);
您可以根据需要多次调用bq.add
- 对于您拥有的每个TermQuery一次。第二个参数指定查询的严格程度。它可以指定显示子查询MUST
,SHOULD
出现,或NOT
出现(这些是BooleanQuery.Occur
枚举的三个值)。
添加完每个子查询后,此BooleanQuery表示完整查询,该查询仅匹配您要求的文档。但是,它仍然不是过滤器。我们现在需要将它提供给QueryWrapperFilter,它将返回一个过滤器对象:
QueryWrapperFilter qwf = new QueryWrapperFilter(bq);
应该这样做。然后,如果您只想对该过滤器允许的文档运行查询,只需使用新查询(称之为q
)和过滤器,然后创建FilteredQuery:
FilteredQuery fq = new FilteredQuery(q, qwf);