Hibernate Search: how to search a full name over separate columns

I have an entity called 'Patient' with string fields called 'firstName', 'lastName' and 'secondLastName' (in Spanish we use both, father and mother family names)

I have a view with a textbox to search patients by name, in which the user may type anything: firstName, lastName, secondLastName, or a combination of these, in any given order. For example, with my name:

firstName: Mauricio, lastName: Ubilla, secondLastName: Carvajal,

If I search "Mauricio Ubilla Carvajal" or even "Mauricio Ubilla" I expect to appear top in the result list. The questions are:

1- How should I define the index for these 3 fields? I did the following:

@Indexed   
class Patient {
    ...
    @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
    protected String firstName = new String();
    @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
    protected String lastName = new String();
    @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
    protected String secondLastName = new String();
    ...
}

2- How should I build the query? I did this:

QueryBuilder qb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Patient.class).get();        
Query luceneQuery = qb.keyword().onFields("firstName", "lastName", "secondLastName").matching(name).createQuery();

However, this is not working for me. It is not throwing any exception, it is just that it is not returning anything. Even if I just search "Mauricio" it doesn't return anything.

But, if I change the query only to match my firstName:

QueryBuilder qb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Patient.class).get();        
Query luceneQuery = qb.keyword().onFields("firstName").matching(name).createQuery();

If I search for "Mauricio" it works.

What am I doing wrong? Is there any way to define a composite index for the 3 columns? Should I build my query in a different way? Help me please :( Btw, I'm using Hibernate Search 4.5.1 Over Hibernate 4.3 and Java 1.7


You are using a very old version of Hibernate Search, so it's very possible that you are running into a bug that has been solved in a more recent version. You should really think about upgrading to at least Hibernate Search 5.6 / Hibernate ORM 5.1, or even better to Search 5.8 / ORM 5.2 (requires Java 8).

If you cannot... Another common solution is to index a transient property whose content is the concatenated names:

@Indexed   
class Patient {
    ...
    @Field
    protected String firstName = "";
    @Field
    protected String lastName = "";
    @Field
    protected String secondLastName = "";
    ...
    @javax.persistence.Transient
    @Field
    public String getFullName() {
        // TODO null safety
        return firstName + " " + lastName + " " + secondLastName;
    }
    ...
}

Then query on this fullName :

QueryBuilder qb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Patient.class).get();        
Query luceneQuery = qb.keyword().onFields("fullName").matching(name).createQuery();

Note that, on contrary to your initial solution, this will have a negative impact on performance, since indexing a @Transient field disables some optimizations. But at least it should work.


To answer your second question. You can search using a phrase as a sentence rather than a keyword.

Hibernate Search also supports combining queries using various strategies:

-SHOULD: the query should contain the matching elements of the subquery

-MUST: the query must contain the matching elements of the subquery

-MUST NOT: the query must not contain the matching elements of the subquery

The aggregations are similar to the boolean ones AND, OR and NOT.

    Query combinedQuery = queryBuilder
   .bool()

   .must(queryBuilder.phrase()
   .onField("productName).sentence("samsung galaxy s8")
   .createQuery())

   .must(queryBuilder.keyword()
   .onField("productCategory").matching("smartphone")
   .createQuery())

   .createQuery();


    // wrap Lucene query in an Hibernate Query object
    org.hibernate.search.jpa.FullTextQuery jpaQuery =
    fullTextEntityManager.createFullTextQuery(combinedQuery, Product.class);

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

Reference http://www.baeldung.com/hibernate-search

链接地址: http://www.djcxy.com/p/37102.html

上一篇: 添加一个标准:字符串应该在集合中

下一篇: Hibernate搜索:如何在单独的列上搜索全名