Исключить документ (ы), если условие истинно - PullRequest
2 голосов
/ 20 января 2020

У меня есть три поля в сущности:

  1. creationNameEn
  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);
}

1 Ответ

2 голосов
/ 21 января 2020

Это никогда ничего не будет совпадать, потому что логический запрос содержит только отрицательные предложения:

    BooleanQuery.Builder builder = new BooleanQuery.Builder();
    for (Query qu : queries) {
        builder.add(qu, BooleanClause.Occur.MUST_NOT);
    }

    return builder.build();

Это довольно странно, но именно так работает Lucene, и вы используете низкоуровневый API Lucene, когда вы вы используете BooleanQuery.Builder.

Solution # 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. DSL Hibernate Search «исправляет» некоторые из наиболее запутанных аспектов Lucene, поэтому этот запрос будет работать должным образом (для всех документов, кроме тех, которые соответствуют пунктам):

    BooleanJunction<?> booleanJunction = queryBuilder.bool();
    for (Query qu : queries) {
        booleanJunction.mustNot(qu);
    }
    return booleanJunction.createQuery();

Подробнее ...

Если вы хотите узнать, почему именно это не работает ...

Булевы запросы не будут ничего совпадать по умолчанию, если только (положительное) предложение не соответствует документу, в этом случае соответствие документы будут отфильтрованы на основе других (положительных или отрицательных) предложений.

Таким образом, в вашем случае запрос ничего не соответствует, а затем он отфильтровывается с помощью предложений "не должен", поэтому он по-прежнему ничего не соответствует.

Простое добавление предложения 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();
...