hibernate-search结合lucene作全文检索

     我们知道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",那么就什么都查询不到。

相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页