如果条件为真,则排除文档
Exclude document(s) if condition true
我在一个实体中有三个字段:
- establishmentNameEn
- IsTelPublishDa
- isTelSecret
我对 establishmentNameEn 进行了模糊搜索。现在,如果字段 IsTelPublishDa 值为 0 或 isTelSecret 值为 1,我想应用条件排除文档。
我的最终查询是:(+establishmentNameEn:kamran~1 +(-IsTelPublishDa:[0 TO 0] -isTelSecret:[1 TO 1]))
但是没有返回结果。
查询代码:
private org.apache.lucene.search.Query excludeDoc(QueryBuilder queryBuilder) {
List<org.apache.lucene.search.Query> queries = new ArrayList<>();
queries.add(queryBuilder.keyword().onField("IsTelPublishDa").matching(0).createQuery());
queries.add(queryBuilder.keyword().onField("isTelSecret").matching(1).createQuery());
BooleanQuery.Builder builder = new BooleanQuery.Builder();
for (Query qu : queries) {
builder.add(qu, BooleanClause.Occur.MUST_NOT);
}
return builder.build();
}
主要方法:
Query fuzzyQuery = queryBuilder.keyword().fuzzy().withEditDistanceUpTo(1).onField("establishmentNameEn").matching(word).createQuery();
luceneQuery.add(fuzzyQuery);
luceneQuery.add(excludeDoc(queryBuilder));
BooleanQuery.Builder builder = new BooleanQuery.Builder();
for (Query qu : luceneQuery) {
builder.add(qu, BooleanClause.Occur.MUST);
}
这永远不会匹配任何东西,因为布尔查询只包含否定子句:
BooleanQuery.Builder builder = new BooleanQuery.Builder();
for (Query qu : queries) {
builder.add(qu, BooleanClause.Occur.MUST_NOT);
}
return builder.build();
这很令人困惑,但这就是 Lucene 的工作方式,当您使用 BooleanQuery.Builder
.
时,您使用的是低级 Lucene API
解决方案 #1
如果您想避免将来出现这种意外情况,请确保您的查询中始终包含肯定的子句。例如,重构您的代码以将 "MUST_NOT" 子句添加到顶级布尔查询:
// Main code
BooleanQuery.Builder builder = new BooleanQuery.Builder();
builder.add(queryBuilder.keyword().fuzzy().withEditDistanceUpTo(1).onField("establishmentNameEn").matching(word).createQuery(), BooleanClause.Occur.MUST);
builder.add(excludedDoc(queryBuilder), BooleanClause.Occur.MUST_NOT);
private org.apache.lucene.search.Query excludedDoc(QueryBuilder queryBuilder) {
BooleanQuery.Builder builder = new BooleanQuery.Builder();
builder.add(queryBuilder.keyword().onField("IsTelPublishDa").matching(0).createQuery(), BooleanClause.Occur.SHOULD);
builder.add(queryBuilder.keyword().onField("isTelSecret").matching(1).createQuery(), BooleanClause.Occur.SHOULD);
return builder.build();
}
解决方案 #2
或者,您可以保持代码不变,但使用 Hibernate Search DSL 而不是 BooleanQuery.Builder
。 Hibernate Search DSL "fixes" Lucene 的一些最令人困惑的方面,因此此查询将按预期工作(匹配除匹配子句的文档之外的所有文档):
BooleanJunction<?> booleanJunction = queryBuilder.bool();
for (Query qu : queries) {
booleanJunction.mustNot(qu);
}
return booleanJunction.createQuery();
更多详情...
如果您想知道为什么这不起作用...
默认情况下,布尔查询不会匹配任何内容,除非(正)子句与文档匹配,在这种情况下,将根据其他(正或负)子句过滤掉匹配的文档。
所以在你的例子中,查询不匹配任何东西,然后用 "must not" 子句过滤掉它,所以它仍然不匹配任何东西。
只需添加一个 MatchAllDocs
子句即可使其按预期工作:
BooleanQuery.Builder builder = new BooleanQuery.Builder();
builder.add(new MatchAllDocsQuery(), BooleanClause.Occur.MUST);
for (Query qu : queries) {
builder.add(qu, BooleanClause.Occur.MUST_NOT);
}
return builder.build();
我在一个实体中有三个字段:
- establishmentNameEn
- IsTelPublishDa
- isTelSecret
我对 establishmentNameEn 进行了模糊搜索。现在,如果字段 IsTelPublishDa 值为 0 或 isTelSecret 值为 1,我想应用条件排除文档。
我的最终查询是:(+establishmentNameEn:kamran~1 +(-IsTelPublishDa:[0 TO 0] -isTelSecret:[1 TO 1]))
但是没有返回结果。
查询代码:
private org.apache.lucene.search.Query excludeDoc(QueryBuilder queryBuilder) {
List<org.apache.lucene.search.Query> queries = new ArrayList<>();
queries.add(queryBuilder.keyword().onField("IsTelPublishDa").matching(0).createQuery());
queries.add(queryBuilder.keyword().onField("isTelSecret").matching(1).createQuery());
BooleanQuery.Builder builder = new BooleanQuery.Builder();
for (Query qu : queries) {
builder.add(qu, BooleanClause.Occur.MUST_NOT);
}
return builder.build();
}
主要方法:
Query fuzzyQuery = queryBuilder.keyword().fuzzy().withEditDistanceUpTo(1).onField("establishmentNameEn").matching(word).createQuery();
luceneQuery.add(fuzzyQuery);
luceneQuery.add(excludeDoc(queryBuilder));
BooleanQuery.Builder builder = new BooleanQuery.Builder();
for (Query qu : luceneQuery) {
builder.add(qu, BooleanClause.Occur.MUST);
}
这永远不会匹配任何东西,因为布尔查询只包含否定子句:
BooleanQuery.Builder builder = new BooleanQuery.Builder();
for (Query qu : queries) {
builder.add(qu, BooleanClause.Occur.MUST_NOT);
}
return builder.build();
这很令人困惑,但这就是 Lucene 的工作方式,当您使用 BooleanQuery.Builder
.
解决方案 #1
如果您想避免将来出现这种意外情况,请确保您的查询中始终包含肯定的子句。例如,重构您的代码以将 "MUST_NOT" 子句添加到顶级布尔查询:
// Main code
BooleanQuery.Builder builder = new BooleanQuery.Builder();
builder.add(queryBuilder.keyword().fuzzy().withEditDistanceUpTo(1).onField("establishmentNameEn").matching(word).createQuery(), BooleanClause.Occur.MUST);
builder.add(excludedDoc(queryBuilder), BooleanClause.Occur.MUST_NOT);
private org.apache.lucene.search.Query excludedDoc(QueryBuilder queryBuilder) {
BooleanQuery.Builder builder = new BooleanQuery.Builder();
builder.add(queryBuilder.keyword().onField("IsTelPublishDa").matching(0).createQuery(), BooleanClause.Occur.SHOULD);
builder.add(queryBuilder.keyword().onField("isTelSecret").matching(1).createQuery(), BooleanClause.Occur.SHOULD);
return builder.build();
}
解决方案 #2
或者,您可以保持代码不变,但使用 Hibernate Search DSL 而不是 BooleanQuery.Builder
。 Hibernate Search DSL "fixes" Lucene 的一些最令人困惑的方面,因此此查询将按预期工作(匹配除匹配子句的文档之外的所有文档):
BooleanJunction<?> booleanJunction = queryBuilder.bool();
for (Query qu : queries) {
booleanJunction.mustNot(qu);
}
return booleanJunction.createQuery();
更多详情...
如果您想知道为什么这不起作用...
默认情况下,布尔查询不会匹配任何内容,除非(正)子句与文档匹配,在这种情况下,将根据其他(正或负)子句过滤掉匹配的文档。
所以在你的例子中,查询不匹配任何东西,然后用 "must not" 子句过滤掉它,所以它仍然不匹配任何东西。
只需添加一个 MatchAllDocs
子句即可使其按预期工作:
BooleanQuery.Builder builder = new BooleanQuery.Builder();
builder.add(new MatchAllDocsQuery(), BooleanClause.Occur.MUST);
for (Query qu : queries) {
builder.add(qu, BooleanClause.Occur.MUST_NOT);
}
return builder.build();