hibernate-search结合lucene作全文检索

 

更多干货

转载:https://blog.csdn.net/feinifi/article/details/80830406 

我们知道hibernate作为orm框架在javaweb中的应用非常广泛,但是hibernate还不仅如此,在hibernate3.2之后还支持全文检索功能,他需要和lucene结合使用。

     通常,为了查询一个关键字,我们需要对我们的表查询时做like过滤,但是like只能对一个字段进行,如果要做到多个字段进行匹配,like就显得力不从心了,而且在匹配时数据库效率会大打折扣。

     hibernate-search的出现,帮我们解决了上面的问题,我们在做关键字过滤时,可以指定多个属性。hibernate search是基于apache lucene的全文检索工具。

    下面通过实例介绍如何通过hibernate search作全文检索。

一、准备数据库表和数据。

向表中插入10条记录,最终数据如下:

构建索引时,我们希望通过name,description字段进行构建,这样,我们在通过关键字查询时,name,description中任意一个出现关键字,那么就可以被查询出来。

二、构建maven项目,引入相关依赖。

<dependency>
       <groupId>org.apache.lucene</groupId>
       <artifactId>lucene-core</artifactId>
       <version>5.5.5</version>
 </dependency>
 <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-search-orm</artifactId>
      <version>5.10.2.Final</version>
 </dependency>
 <dependency>
       <groupId>org.apache.lucene</groupId>
       <artifactId>lucene-smartcn</artifactId>
       <version>3.6.2</version>
 </dependency>
 <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.38</version>
 </dependency>
创建实体Book

package com.xxx.hibernate.domain;
 
import java.io.Serializable;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
 
import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.Store;
@Entity
@Table(name="xx_books")
@Indexed
public class Book implements Serializable{
 
    private static final long serialVersionUID = 1L;
    private Integer id;
    @Field(index=Index.YES,analyze=Analyze.YES,store=Store.YES)
    private String name;
    @Field(index=Index.YES,analyze=Analyze.YES,store=Store.YES)
    private String description;
    private String publish;
    private String author;
    @Id
    @GeneratedValue(generator="increment")
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public String getPublish() {
        return publish;
    }
    public void setPublish(String publish) {
        this.publish = publish;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    @Override
    public String toString() {
        return "Book [id=" + id + ", name=" + name + ", description="
                + description + ", publish=" + publish + ", author=" + author
                + "]";
    }
    
}
需要注意的地方:

实体类配置Indexed注解,表明我们需要对其构建索引。

属性name,description需要通过Field注解,标识是否作为索引,是否分词,是否存储。

配置hibernate-cfg.xml,设置driver,url,username,password,pool_size,show_sql,dialect等属性。另外有两项重要的配置分别是存储实现hibernate.search.default.directory_provider和索引存放位置hibernate.search.default.indexBase。

<session-factory>
      <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
      <property name="connection.url">jdbc:mysql://localhost:3306/test?useSSL=false</property>
      <property name="connection.username">root</property>
      <property name="connection.password">PWD-pushmarketing2015!</property>
      <property name="connection.pool_size">5</property>
      <property name="dialect">org.hibernate.dialect.MySQL57Dialect</property>
      <property name="show_sql">true</property>
      <!-- hibernate search -->
      <property name="hibernate.search.default.directory_provider">filesystem</property>
      <property name="hibernate.search.default.indexBase">D:/data/indexs</property>
      <mapping class="com.xxx.hibernate.domain.Book"/>
  </session-factory>
这里,Book实体通过注解指定了表和id增长类型,所以这里就不用再配置xml映射文件。直接通过类来指定。

以上准备好了,就可以编码构建索引和搜索了。

三、编码,构建索引。

初始化SessionFactory,并提供获取Session静态方法getSession()。

private static SessionFactory factory;
private static Session session;
static{
    try {
        Configuration cfg = new Configuration();
        cfg.configure("hibernate-cfg.xml");
        factory = cfg.buildSessionFactory();
    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }
}
    
private static Session getSession(){
    if(session==null){
        session = factory.openSession();
    }
    return session;
}
构建索引方法:

public static void index(){
    Session session = getSession();
    FullTextSession fullTextSession = Search.getFullTextSession(session);
    try {
        fullTextSession.createIndexer().startAndWait();
        System.out.println("create index ok.");
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        session.close();
        factory.close();
    }
}
在main方法里面运行index()方法,构建索引。

控制台打印截图:

存放索引的文件夹截图:

到这里,索引创建成功。

四、编码,搜索。

通过第三步,我们已经对Book实体成功做了索引。这里,我们需要对索引做搜索,我们对name,description字段中含有"java"关键字的book进行搜索并打印出来。

@SuppressWarnings("unchecked")
public static void queryIndex(){
    Session session = getSession();
    FullTextSession fullTextSession = Search.getFullTextSession(session);
    QueryBuilder qb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(Book.class).get();
    Query query = null;
        try {
        query = qb.keyword().onFields("name","description").matching("action").createQuery();
        FullTextQuery fullTextQuery = fullTextSession.createFullTextQuery(query, Book.class);
        List<Book> list = fullTextQuery.list();
        System.out.println("query is done.");
        for(Book book:list){
            System.out.println(book);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally{
        session.close();
        factory.close();
    }
}
Hibernate: select this_.id as id1_0_0_, this_.author as author2_0_0_, this_.description as descript3_0_0_, this_.name
 as name4_0_0_, this_.publish as publish5_0_0_ from xx_books this_ where (this_.id in (?, ?))
query is done.
Book [id=1, name=java program, description=java program for beginners, publish=2018-01-01, author=james]
Book [id=7, name=think in java, description=java program guide, publish=2018-02-01, author=jack]
查询到了java关键字的记录。

这里好像有一个问题,就是javascript也是含有java的,这里没有被查询出来。但是通过sql like查询,java,javascript均能被查询出来。

另外一个问题,如果name,description均不作分词analyze=Analyze.NO,那么他们将作为整体来做索引,就是说如果单独搜索"java",那么就什么都查询不到。
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值