2017-10-18 142 views
0

我有一个名为'Patient'的字符串字段名为'firstName','lastName'和'secondLastName'的实体(在西班牙语中,我们同时使用父亲和母亲姓氏)Hibernate搜索:如何通过单独的列搜索全名

我有一个文本框按照名称搜索患者的视图,其中用户可以按任何给定顺序键入任何内容:firstName,lastName,secondLastName或这些的组合。 例如,我的名字:

姓:毛, 名字:Ubilla, secondLastName:卡瓦哈尔,

如果我搜索“毛Ubilla卡瓦哈尔”,甚至“毛Ubilla”我希望能出现顶部结果列表。 问题是:

1-我应该如何定义这3个字段的索引?我做了以下几点:

@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-我该如何构建查询?我这样做:

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

但是,这不适合我。它没有抛出任何异常,只是它没有返回任何东西。 即使我只搜索“Mauricio”,它也不会返回任何内容。

但是,如果我更改查询只符合我的姓:如果我搜索

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

“毛”它的工作原理。

我在做什么错?有什么办法可以为3列定义组合索引吗?我应该以不同的方式构建我的查询吗? 请帮助我顺便说一句:( ,我使用Hibernate Search的4.5.1在休眠4.3和Java 1.7

回答

2

您使用的是很旧版本的Hibernate搜索的,所以这是非常可能的,你正在运行到一个错误你应该考虑升级到至少Hibernate Search 5.6/Hibernate ORM 5.1,或者甚至更好的搜索5.8/ORM 5.2(需要Java 8)

如果你不能。另一个常见的解决方案是索引一个瞬变属性,其内容是连接名称:

@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; 
    } 
    ... 
} 

这个fullName然后查询:

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

需要注意的是,就违背了你最初的解决方案,这会对性能产生负面影响,因为索引一个@Transient场禁用一些优化。但至少它应该工作。

+0

谢谢获得!这就是我所做的,它工作正常。同时感谢您对升级到更新版本hibernate的建议。好像我很快就要做。 –

0

回答你的第二个问题。您可以使用短语作为句子而不是关键字。

Hibernate Search的使用也不同战略支持相结合的查询:

-SHOULD:查询应包含的子查询匹配元素

- 必须:查询必须包含子查询的匹配元素

- 必须:查询不得包含子查询的匹配元素

聚合类似于布尔逻辑的AND,OR和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(); 

此引用从链接http://www.baeldung.com/hibernate-search