hibernate search5.3.0全文检索集成到spring data jpa

hibernate search 我就不多说了,它是基于lucene的全文检索工具,记得上大学那时候接触了compass全文检索工具,后来也没怎么用,再后来这家伙不更新了,所以hibernate就推出了自己的基于lucene的全文检索工具就是这家伙hibernate Search。

不用说天然的优势就是可以无缝的和hibernate集成甚至不需要什么配置,一直在更新中,最近想在自己的博客里面加入搜索功能,本想用比较热乎的solr,找了半天资料还是放弃了,用在我的博客里面有点大题小做了,所以自然就锁定了hibernate search,简单嘛,而且不需要什么配置对hibernate jpa都很有好,虽然我用的是spring data jpa 但是我想也不会影响它的使用。

废话就不说了,我们进入正题,从配置开始:

1.persistence.xml 文件里面加入:

<property name="hibernate.search.default.directory_provider" value="filesystem"/>
            <property name="hibernate.search.default.indexBase" value="e:/index"/>
如果是linux系统就把路径换一下,配置搞定,是不是很简单,其他地方不需要任何改动。

2.实体:

这不用解释了吧,你想要在那个实体上面做检索就配置那个实体,说白了就是加一些注解。

我就简略的写了,至于注解的含义大家在网上找找。

@Indexed
@Analyzer(impl=SmartChineseAnalyzer.class)
public class Posts implements java.io.Serializable {

@Id  //这里不需要加什么,如果你用的是hibernate做持久层需要加@DocumentId 这个注解
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}

@Column(name = "post_title", nullable = false,length=1000)
@Field
@Boost(2)
public String getPtitle() {
return ptitle;
}
public void setPtitle(String ptitle) {
this.ptitle = ptitle;
}

@Lob
@Field
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}

还需要我解释么,我觉得不需要了。

就这么简单,加几个注解就可以了,系统在运行时会自动生成索引文件

3.检索服务:

这个主要是放在service层,因为我用的是spring data jpa

@Service("postService")
public class PostServiceImpl implements PostService{

@Autowired
private EntityManagerFactory  emf;

这里我在这个实现类里面注入了在applicationContext.xml 里面配置的EntityManagerFactory, 我想你应该懂这些

public QueryResult<Posts> search(int nowpage,int size,String keyWord) {
		QueryResult<Posts> queryResult = new QueryResult<Posts>();
		EntityManager em = emf.createEntityManager();
		FullTextEntityManager fManager = Search.getFullTextEntityManager(em);
		QueryBuilder qb = fManager.getSearchFactory().buildQueryBuilder().forEntity(Posts.class).get();
		Query q = qb.keyword().onFields("ptitle","description","content").matching(keyWord).createQuery();

		FullTextQuery fq = fManager.createFullTextQuery(q, Posts.class);
		queryResult.setTotalRecord(fq.getResultSize());

		List<Posts> re = fq.setFirstResult(nowpage).setMaxResults(size).getResultList();

		re = hightLight(q, re, Posts.class, null, "ptitle","description","content");

		queryResult.setResultList(re);

		return queryResult;
	}
/**
	* @param org.apache.lucene.search.Query luceneQuery
	     * @param searchResults 搜索结果集
	     * @param searchResultClass 搜索结果类型
	     * @param excludeFields 要排除高亮的字段
	     * @param fieldNames 需要高亮的字段
	     * @return 高亮后的searchResults
	     */
	private <E> List<E> hightLight(Query luceneQuery, List<E> searchResults, Class<E> searchResultClass, List<String> excludeFields, String... fieldNames) {
	        SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<b><font color=\"red\">", "</font></b>");
	        QueryScorer queryScorer = new QueryScorer(luceneQuery);
	        Highlighter highlighter = new Highlighter(formatter, queryScorer);
	        Analyzer analyzer = new SmartChineseAnalyzer();

	        for (E e : searchResults) {
	            for (String fieldName : fieldNames) {

	                if(null != excludeFields && excludeFields.contains(fieldName)){
	                    continue;
	                }

	                Object fieldValue = ReflectionUtils.invokeMethod(BeanUtils.getPropertyDescriptor(searchResultClass, fieldName).getReadMethod(), e); 

	                String hightLightFieldValue = null;

	                if(fieldValue instanceof String){

	                    try {
	                        hightLightFieldValue = highlighter.getBestFragment( analyzer, fieldName , String.valueOf(fieldValue));
	                    } catch (Exception e1) {
	                        e1.printStackTrace();
	                    }
	                    ReflectionUtils.invokeMethod(BeanUtils.getPropertyDescriptor(searchResultClass, fieldName).getWriteMethod(), e, hightLightFieldValue);

	                }
	            }
	        }
	        return searchResults;
	    }

解释:onFields("ptitle","description","content") 这几个就是你要检索的字段,有几个写几个。

这里面加入了分页效果,高亮效果,这段代码我也是在网上找的修改了一下,如果谁还有更好的可以留言分享一下。

package com.weirblog.fenye;

import java.util.List;
/**
 * 查询结果集,包括数据和总数
 * @author db2admin
 *
 * @param <T>
 */
public class QueryResult<T> {
	/** 查询得出的数据List **/
	private List<T> resultList;
	/** 查询得出的总数 **/
	private int totalRecord;

	public List<T> getResultList()
	{
		return resultList;
	}

	public void setResultList(List<T> resultList)
	{
		this.resultList = resultList;
	}

	public int getTotalRecord()
	{
		return totalRecord;
	}

	public void setTotalRecord(int totalRecord)
	{
		this.totalRecord = totalRecord;
	}
}
package com.weirblog.fenye;

import java.util.List;

/**
 * 分页数据包装,包括分页信息和List数据
 */
public class PageView<T> {
	/** 分页数据 **/
	private List<T> records;
	/** 页码开始索引和结束索引 **/
	private PageIndex pageIndex;
	/** 总页数 **/
	private int totalPage = 1;
	/** 每页显示记录数 **/
	private int maxResult = 10;
	/** 当前页 **/
	private int currentPage = 1;
	/** 总记录数 **/
	private int totalRecord;
	/** 每次显示多少页,必须保证大于3页,保证左右链接都可以使用 **/
	private int viewPageCount = 10;

	/** 要获取记录的开始索引 **/
	public int getFirstResult() {
		return (this.currentPage - 1);
//		return (this.currentPage - 1) * this.maxResult;
	}

	public int getViewPageCount() {
		return viewPageCount;
	}

	public void setViewPageCount(int viewPageCount) {
		this.viewPageCount = viewPageCount;
	}

	public PageView(int maxResult, int currentPage) {
		this.maxResult = maxResult;
		this.currentPage = (currentPage <= 0 ? 1 : currentPage);
	}

	public PageView(int currentPage) {
		this.currentPage = (currentPage <= 0 ? 1 : currentPage);
	}

	public void setQueryResult(QueryResult<T> qr) {
		setTotalRecord(qr.getTotalRecord());
		setRecords(qr.getResultList());
	}

	public int getTotalRecord() {
		return totalRecord;
	}

	public void setTotalRecord(int totalRecord) {
		this.totalRecord = totalRecord;
		setTotalPage(this.totalRecord % this.maxResult == 0 ? this.totalRecord
				/ this.maxResult : this.totalRecord / this.maxResult + 1);
	}

	public List<T> getRecords() {
		return records;
	}

	public void setRecords(List<T> records) {
		this.records = records;
	}

	public PageIndex getPageIndex() {
		return pageIndex;
	}

	public int getTotalPage() {
		return totalPage;
	}

	public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
		this.pageIndex = PageIndex.getPageIndex(viewPageCount, currentPage,
				totalPage);
	}

	public int getMaxResult() {
		return maxResult;
	}

	public int getCurrentPage() {
		return currentPage;
	}
}

这些关于分页的封装我就不解释了。

4.controller层:

@RequestMapping("/search")
	public String search(Integer page,String keyWord,Model model) {
		PageView<Posts> pageView = new PageView<Posts>(2, page!=null ? page:1);
		pageView.setQueryResult(postService.search(pageView.getFirstResult(), pageView.getMaxResult(), keyWord));
		model.addAttribute("pageView", pageView);
		return "/search";
	}

这个也应该不需要解释什么。

还有一些就是jar包了我用的是最新稳定版本5.3.0

hibernate-search-engine-5.3.0.Final

hibernate-search-orm-5.3.0.Final

lucene-analyzers-common-4.10.4

lucene-core-4.10.4

xml-apis-1.3.03

E:\gj\hibernate-search-5.3.0.Final\dist\lib\required

重复的去掉

hibernate 需要也是最新的了4.3.10

lucene需要:

lucene 这些有的hibernate search包里面没有 自己去lucene官网上下载,还有一个办法就是自己搭建一个maven工程加入:

<dependency>
   <groupId>org.hibernate</groupId>
   <artifactId>hibernate-search-orm</artifactId>
   <version>5.3.0.Final</version>
</dependency>

就是这样才搞定了jar包缺失的问题,很扯淡是不是。

最后还是看看效果吧:

还行吧。

时间: 2024-11-10 13:15:55

hibernate search5.3.0全文检索集成到spring data jpa的相关文章

使用 Spring Data JPA 简化 JPA 开发

从一个简单的 JPA 示例开始 本文主要讲述 Spring Data JPA,但是为了不至于给 JPA 和 Spring 的初学者造成较大的学习曲线,我们首先从 JPA 开始,简单介绍一个 JPA 示例:接着重构该示例,并引入 Spring 框架,这两部分不会涉及过多的篇幅,如果希望能够深入学习 Spring 和 JPA,可以根据本文最后提供的参考资料进一步学习. 自 JPA 伴随 Java EE 5 发布以来,受到了各大厂商及开源社区的追捧,各种商用的和开源的 JPA 框架如雨后春笋般出现,为

[z]使用 Spring Data JPA 简化 JPA 开发

文章来自http://www.ibm.com/developerworks/cn/opensource/os-cn-spring-jpa/,内容非常清晰. 从一个简单的 JPA 示例开始 本文主要讲述 Spring Data JPA,但是为了不至于给 JPA 和 Spring 的初学者造成较大的学习曲线,我们首先从 JPA 开始,简单介绍一个 JPA 示例:接着重构该示例,并引入 Spring 框架,这两部分不会涉及过多的篇幅,如果希望能够深入学习 Spring 和 JPA,可以根据本文最后提供

快速搭建springmvc+spring data jpa工程

一.前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程,并提供了一个简单的demo作为参考. 二.创建maven工程 http://www.cnblogs.com/hujunzheng/p/5450255.html 三.配置文件说明 1.application.properties jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/springdata?u

Spring Data JPA初使用

我们都知道Spring是一个非常优秀的JavaEE整合框架,它尽可能的减少我们开发的工作量和难度. 在持久层的业务逻辑方面,Spring开源组织又给我们带来了同样优秀的Spring Data JPA. 通常我们写持久层,都是先写一个接口,再写接口对应的实现类,在实现类中进行持久层的业务逻辑处理. 而现在,Spring Data JPA帮助我们自动完成了持久层的业务逻辑处理,我们要做的,仅仅是声明一个持久层接口. 1.下载开发所需要的发布包. 1)spring-framework-3.1.2.RE

Spring Data JPA初使用(转载)

我们都知道Spring是一个非常优秀的JavaEE整合框架,它尽可能的减少我们开发的工作量和难度. 在持久层的业务逻辑方面,Spring开源组织又给我们带来了同样优秀的Spring Data JPA. 通常我们写持久层,都是先写一个接口,再写接口对应的实现类,在实现类中进行持久层的业务逻辑处理. 而现在,Spring Data JPA帮助我们自动完成了持久层的业务逻辑处理,我们要做的,仅仅是声明一个持久层接口. 1.下载开发所需要的发布包. 1)spring-framework-3.1.2.RE

java(样品集成框架spring、spring mvc、spring data jpa、hibernate)

这是你自己的参考springside集成框架的开源项目.主要的整合spring.spring mvc.spring data jpa.hibernate几个框架,对于这些框架中仍然感觉更舒适spring data jpa该框架,该框架编写dao上课时间,只需要编写一个接口声明,spring data jpa会自己主动的实现事实上现类,使用起来比較方便,至于具体的用法还请自己百度吧,由于我也不清楚. 个人感觉另一个比較不错的地方就是可以打印sql语句,都知道hibernate打印的sql语句并不会

JPA、Hibernate、Spring data jpa之间的关系,以及和springboot的整合

什么么是JPA? 全称Java Persistence API,可以通过注解或者XML描述[对象-关系表]之间的映射关系,并将实体对象持久化到数据库中. 为我们提供了: 1)ORM映射元数据:JPA支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中: 如:@Entity.@Table.@Column.@Transient等注解. 2)JPA 的API:用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和

Hibernate中使用Spring Data JPA

1.pom.xml中引入相关依赖 <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </propertie

Spring ORM+Hibernate?Out!换 Spring Data JPA 吧!

转载请注明出处:http://blog.csdn.net/anxpp/article/details/51415698,谢谢! 在一切开始之前,先举个简单的例子,以提高大家的兴致! 如果一张表user有三个字段,id.name和age,要查找指定姓氏在某年龄以上的user,在传统的Spring+Hibernate中,dao层我们是这样写的: UserDao: public interface UserDao{ List<User> findByNameLikeAndAgeGreaterThan