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

hibernate search 我就很少說了,它是基於lucene的全文檢索工具,記得上大學那時候接觸了compass全文檢索工具,後來也沒怎麼用,再後來這傢伙不更新了,因此hibernate就推出了本身的基於lucene的全文檢索工具就是這傢伙hibernate Search。 java

不用說自然的優點就是能夠無縫的和hibernate集成甚至不須要什麼配置,一直在更新中,最近想在本身的博客裏面加入搜索功能,本想用比較熱乎的solr,找了半天資料仍是放棄了,用在個人博客裏面有點大題小作了,因此天然就鎖定了hibernate search,簡單嘛,並且不須要什麼配置對hibernate jpa都頗有好,雖然我用的是spring data jpa 可是我想也不會影響它的使用。 linux


廢話就不說了,咱們進入正題,從配置開始: spring

1.persistence.xml 文件裏面加入: apache


<property name="hibernate.search.default.directory_provider" value="filesystem"/>
            <property name="hibernate.search.default.indexBase" value="e:/index"/>
若是是linux系統就把路徑換一下,配置搞定,是否是很簡單,其餘地方不須要任何改動。 api


2.實體: app

這不用解釋了吧,你想要在那個實體上面作檢索就配置那個實體,說白了就是加一些註解。 maven

我就簡略的寫了,至於註解的含義你們在網上找找。 ide

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


@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包缺失的問題,很扯淡是否是。


最後仍是看看效果吧:

還行吧。

相關文章
相關標籤/搜索