0
votes

I build a simple full text search combined with a filter, below my JUnit test :

@Test
public void D_testFilterFactory() throws Exception {

    // get the full text entity manager
    FullTextEntityManager fullTextEntityManager = org.hibernate.search.jpa.Search.getFullTextEntityManager(em);

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

    // Build Query !
    Query query = queryBuilder.keyword().wildcard().onField("itemDesc").matching("*").createQuery();

    FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(query, InspectionMaster.class);

    // wrap Lucene query in an Hibernate Query object
    logService.log("TEST : Test search on itemDesc = '*' return " + fullTextQuery.getResultSize() + " documents");

    // test filter !
    fullTextQuery.enableFullTextFilter("siteFilter").setParameter("siteID", "NEW");
    logService.log("TEST : Test search on itemDesc = '*' with filter on site.siteId = 'NEW' return " + fullTextQuery.getResultSize() + " documents");

}

My Filter is declared in entity with :

@Entity
@Indexed
@FullTextFilterDefs( {
    @FullTextFilterDef(name = "siteFilter", impl = siteFilterFactory.class)
})
@Table(name="LGIMAS")
public class InspectionMaster implements Serializable {

I also build a filterFactory :

public class siteFilterFactory {
    private String siteID;

    /**
     * injected parameter
     */
    public void setSiteID(String siteID) {
        this.siteID = siteID;
    }

    @Key
    public FilterKey getKey() {
        StandardFilterKey key = new StandardFilterKey();
        key.addParameter( siteID );
        return key;
    }

    @Factory
    public Filter getFilter() {
        Query query = new TermQuery( new Term("site.siteId", siteID ) );
        return new CachingWrapperFilter(new QueryWrapperFilter(query));
    }
}

Of course, field "site.siteId" is an embedded index field of my entity:

   @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="SITID")
    @IndexedEmbedded
    private Site site;

I have following return :

*** LOG [Mon Apr 25 23:28:09 CEST 2016] TEST : Test search on itemDesc = '*' return 18 documents
*** LOG [Mon Apr 25 23:28:09 CEST 2016] TEST : Test search on itemDesc = '*' with filter on site.siteId = 'NEW' return 0 documents

Not what is expected, I have 18 documents in my table including two documents with site.siteId = 'NEW'.

I try to use a TermQuery only, without filtering : public void C_testFilter() throws Exception {

    // get the full text entity manager
    Session hibernateSession = em.unwrap(Session.class);
    FullTextSession fullTextSession = Search.getFullTextSession(hibernateSession);

    BooleanQuery bq = new BooleanQuery();
    TermQuery filterNEW = new TermQuery(new Term("site.siteId", "NEW"));
    bq.add(filterNEW, BooleanClause.Occur.MUST);
    Query q = new QueryParser(Version.LUCENE_36, "cs-method", new StandardAnalyzer(Version.LUCENE_36)).parse(bq.toString());

    org.hibernate.Query hibernateQuery = fullTextSession.createFullTextQuery(q, InspectionMaster.class);
    logService.log("TEST : Test filter on site.siteId = 'NEW' " + hibernateQuery.list().size() + " documents");

}

With this code all work as expected :

*** LOG [Mon Apr 25 23:42:49 CEST 2016] TEST : Test filter on site.siteId = 'NEW' 2 documents

Any help would be very welcome. Thank !

1

1 Answers

1
votes

So I finally capitulate with filter, doesn't work and I didn't found why !

For those in the same case, find below my full search function, working like a charme (but without "filter") :

  public Page<InspectionMaster> search(String text, String filterStatus, String filterSite, Pageable pageable) {

        // get the full text entity manager
        FullTextEntityManager fullTextEntityManager = org.hibernate.search.jpa.Search.getFullTextEntityManager(em);

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

        // Add wildcard to always have a full search capability
        text = "*" + text.toLowerCase() + "*";

        // Prepare filter on Status and Site
        Query filterStatusQuery;
        if (filterStatus.isEmpty()) {
            filterStatusQuery = queryBuilder.all().createQuery();
        } else {
            filterStatusQuery = queryBuilder.keyword().onField("status").matching(StatusType.fromDescription(filterStatus)).createQuery();
        }
        Query filterSiteQuery;
        if (filterSite.isEmpty()) {
            filterSiteQuery = queryBuilder.all().createQuery();
        } else {
            filterSiteQuery = queryBuilder.keyword().onField("site.siteId").matching(filterSite).createQuery();
        }

        // Prepare full text search
        Query fullTextQuery = queryBuilder
                      .bool()
                        .should( queryBuilder.keyword().wildcard().onField("site.sitedescription").matching(text).createQuery() )
                        .should( queryBuilder.keyword().wildcard().onField("vendorNr").matching(text).createQuery() )
                        .should( queryBuilder.keyword().wildcard().onField("vendorDesc").matching(text).createQuery() )
                        .should( queryBuilder.keyword().wildcard().onField("itemNr").matching(text).createQuery() )
                        .should( queryBuilder.keyword().wildcard().onField("itemDesc").matching(text).createQuery() )
                        .should( queryBuilder.keyword().wildcard().onField("whmPickLocation").matching(text).createQuery() )
                      .createQuery();

        // Build final Query !
        Query finalQuery = queryBuilder
                  .bool()
                    .must( filterStatusQuery )
                    .must( filterSiteQuery )
                    .must( fullTextQuery )
                .createQuery();         

        // wrap Lucene query in an Hibernate Query object
        FullTextQuery jpaQuery = fullTextEntityManager.createFullTextQuery(finalQuery, InspectionMaster.class);

        jpaQuery.setFirstResult(pageable.getOffset());
        jpaQuery.setMaxResults(pageable.getPageSize());

        int resultSize = jpaQuery.getResultSize();

        // execute search and return results (sorted by relevance as default)
        @SuppressWarnings("unchecked")
        List<InspectionMaster> results = jpaQuery.getResultList();      

    return new PageImpl<>(results, pageable, resultSize);
  }       

This allow a search with "3" criteria :

  • 1 "must" criteria (like a filter) on Status
  • 1 "must" criteria (second filter) on site
  • 1 fulltext search on all other fields

Hope this help someone !