如何过滤多个字段上的搜索查询?

时间:2019-05-29 13:53:19

标签: java hibernate-search

我有一份研究清单。我想在首页中使用预输入功能搜索它们。
为此,我在Spring Boot(2.1.5)中使用了Hibernate Search。 我为我的Study表建立了索引,并且某些字段标记有@Field属性以进行索引。

搜索效果很好。
但是,现在我想添加一个过滤器以使用相同的预输入功能,但只搜索部分研究内容。

为此,我创建了一个类似于Hibernate Search文档的过滤器,但没有找到一种方法来过滤两个字段之间的OR。

我的实际过滤器,但仅在一个字段(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 :(得分:0)

编辑:显然,您使用的是全文过滤器,实际上您确实必须直接使用Lucene API。

在这种情况下,只需将布尔连接与“ should”子句一起使用。当布尔连接中只有“应该”子句时,至少其中一个必须匹配。

    @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

在您的情况下,您需要一个keyword query来定位两个字段:

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,但实际上是一个“或”:如果有任何字段匹配,查询将匹配。

有关查询的更高级组合,请查看boolean junctions

答案 1 :(得分:0)

这是我过去通过@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();
    }