Как отфильтровать поисковый запрос по нескольким полям? - PullRequest
0 голосов
/ 29 мая 2019

У меня есть список исследований.И я хочу найти их с помощью функции typeahead на первой странице.
Для этого я использую Hibernate Search с Spring Boot (2.1.5).Я проиндексировал свою таблицу STUDY, и некоторые поля помечены атрибутом @Field для индексации.

Поиск работает хорошо.
Но теперь я хочу добавить фильтр, чтобы использовать ту же функцию typeahead, но поискподмножество моих исследований.

Для этого я создал фильтр, подобный документации поиска Hibernate, но я не нашел способа фильтрации по двум полям с ИЛИ между ними.

Мой фактическийфильтровать, но фильтровать только по одному полю (avisDefinitifCet):

/**
 * etudeFilter
 */
public class EtudeFilterFactory {
    private String clasCet1ErPassage;
    private String avisDefinitifCet;

    public void setClasCet1ErPassage(String clasCet1ErPassage) {
        this.clasCet1ErPassage = clasCet1ErPassage;
    }

    public void setAvisDefinitifCet(String avisDefinitifCet) {
        this.avisDefinitifCet = avisDefinitifCet;
    }

    @Factory
    public Query getFilter() {
        System.out.println("Filter avisDefinitifCet : " + this.avisDefinitifCet.toLowerCase());
        return new TermQuery(new Term("avisDefinitifCet", this.avisDefinitifCet.toLowerCase()));
    }
}

Как мне выполнить фильтрацию по второму полю в моем случае clasCet1ErPassage?

С этой целью выполните поиск постандартный поисковый запрос и применение фильтра, подобного этому

SELECT *
FROM STUDY
WHERE 
A=t OR B=t OR C=t -- Normal search
AND (avisDefinitifCet='acceptation' OR clasCet1ErPassage='acceptation') -- Filter on two fields

Моя функция поиска:

public List<Etude> search(String text, Map<String, String> allParams) {
        text = stripAccents(text);
        // get the full text entity manager
        FullTextEntityManager fullTextEntityManager = getFullTextEntityManager(entityManager);

        // create the query using Hibernate Search query DSL
        QueryBuilder queryBuilder = fullTextEntityManager
                .getSearchFactory()
                .buildQueryBuilder()
                .forEntity(Etude.class)
                .get();

        // Simple Query String queries
        Query query = queryBuilder
                .simpleQueryString()
                .onFields("n0Cet")
                .andField("anneeCet")
                .andField("noDansAnneeCet")
                .andField("sigleEtude")
                .andField("titreEtude")
                .andField("traitement1")
                .andField("traitement2")
                .andField("traitement3")
                .andField("traitement4")
                .andField("traitement5")
                .andField("demandeurIgr.nomInvestigateurIgr")
                .andField("investigateurHorsIgr.nomInvestigateur")
                .andField("investigateurIgr.nomInvestigateurIgr")
                .andField("promoteur.nomPromoteur")
                .matching(text)
                .createQuery();

        // wrap Lucene query in an Hibernate Query object
        FullTextQuery fullTextQuery = fullTextEntityManager
                .createFullTextQuery(query, Etude.class)
                .setMaxResults(101);

        // Here allParams contains
        // avisDefinitifCet => 'acceptation',
        // clasCet1ErPassage => 'acceptation'
        allParams.forEach((key, value) -> {
            fullTextQuery.enableFullTextFilter("etudeFilter").setParameter(key, value);
        });

        return (List<Etude>) fullTextQuery.getResultList();
    }

Правильно ли я думаю о его реализации или я ошибаюсь?

Ответы [ 2 ]

0 голосов
/ 03 июня 2019

Вот что я использовал для решения своей проблемы благодаря @ yrodiere

@Factory
    public Query getFilter() {
        return new BooleanQuery.Builder()
                .add(new TermQuery(new Term("avisDefinitifCet", this.avisDefinitifCet.toLowerCase())), BooleanClause.Occur.SHOULD)
                .add(new TermQuery(new Term("clasCet1ErPassage", this.clasCet1ErPassage.toLowerCase())), BooleanClause.Occur.SHOULD)
                .build();
    }
0 голосов
/ 29 мая 2019

РЕДАКТИРОВАТЬ: Очевидно, вы используете полнотекстовые фильтры, где вы действительно должны использовать API Lucene напрямую.

В этом случае просто используйте булево соединение с предложениями must. Если в булевом соединении есть только предложения «следует», по крайней мере, одно из них должно совпадать.

    @Factory
    public Query getFilter() {
        String valueToMatch = this.avisDefinitifCet.toLowerCase();
        return new BooleanQuery.Builder()
            .add(new TermQuery(new Term("avisDefinitifCet", valueToMatch)), Occur.SHOULD)
            .add(new TermQuery(new Term("clasCet1ErPassage", valueToMatch)), Occur.SHOULD)
            .build();
    }

Предыдущий ответ:

Если вы новичок в Lucene, вам действительно стоит попробовать Hibernate Search DSL .

В вашем случае вам понадобится запрос для ключевого слова , предназначенный для двух полей:

EntityManager em = ...;

FullTextEntityManager fullTextEntityManager =
    org.hibernate.search.jpa.Search.getFullTextEntityManager(em);

QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory()
    .buildQueryBuilder().forEntity( Etude.class ).get();

Query luceneQuery = queryBuilder.keyword()
    .onField("avisDefinitifCet").andField("clasCet1ErPassage")
    .matching("acceptation")
    .createQuery();

Обратите внимание, что, несмотря на то, что метод вызывается andField, на самом деле это "ИЛИ": запрос будет совпадать, если какое-либо поле соответствует.

Для более сложного сочетания запросов взгляните на логические соединения .

...