如果条件为真,则排除文档

Exclude document(s) if condition true

我在一个实体中有三个字段:

  1. establishmentNameEn
  2. IsTelPublishDa
  3. 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();