將Hibernate Search集成進已有項目中,實現全文檢索功能

jopen 9年前發布 | 23K 次閱讀 Hibernate 持久層框架 Hibernate Search

本來是準備使用Lucene的但是新版本的API過于繁瑣,最后還是決定使用Hibernate Search來實現全文檢索。這篇博文以我以前做的博客為例來實現全文檢索。

1、修改Hibernate配置文件,因為我的系統采用的是SSH2來開發的所以我修改的是spring配置文件

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
            <prop key="hibernate.hbm2ddl.auto">update</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.search.default.directory_provider">filesystem</prop>
            <prop key="hibernate.search.default.indexBase">E:/index</prop>
        </props>
    </property>
    <property name="mappingResources">
        <list>
            <value>cn/harmel/blog/domain/User.hbm.xml</value>
            <value>cn/harmel/blog/domain/Category.hbm.xml</value>
            <value>cn/harmel/blog/domain/Article.hbm.xml</value>
            <value>cn/harmel/blog/domain/Comment.hbm.xml</value>
            <value>cn/harmel/blog/domain/Attachment.hbm.xml</value>
        </list>
    </property>
</bean>


其實就是配置如下兩個屬性:

hibernate.search.default.directory_provider = filesystem


hibernate.search.default.indexBase = 索引存儲目錄


2、給實體標注注解

package cn.harmel.blog.domain;

import java.util.Date; import java.util.HashSet; import java.util.Set;

import org.hibernate.search.annotations.Analyzer; import org.hibernate.search.annotations.DocumentId; import org.hibernate.search.annotations.Field; import org.hibernate.search.annotations.Indexed; import org.wltea.analyzer.lucene.IKAnalyzer;

/*   文章      @author Harmel    / @Indexed @Analyzer(impl = IKAnalyzer.class) public class Article {

    @DocumentId     private Long id;     @Field     private String title;     @Field     private String content;     @Field     private String description;     private Date postTime;     private Date lastEditTime;     private int viewCount;

    private Category category;     private Set<Comment> comments = new HashSet<Comment>();     private Set<Attachment> attachments = new HashSet<Attachment>();

    // 此處省略一些getter和setter方法     //........ }</pre>


注解說明:

@Indexed:讓實體支持索引

@Analyzer :設置分詞器,我這里使用的是開源的IK中文分詞器

@DocumentID:索引文檔ID

@Field :索引字段,該注解默認屬性值為

store=Store.NO:是否將數據存儲在索引中,經實驗無論store=Store.NO還是store=Store.YES都不會影響最終的搜索。如果store=Store.NO值是通過數據庫中獲取,如果store=Store.YES值是直接從索引文檔中獲取。

index=Index.YES:是否索引

analyze=Analyze.YES:是否分詞

標注了注解后的實體在保存和更新的時候,會自動生成或修改索引。

3、查詢索引

public PageModel<Article> searchArticle(int pageNum, int pageSize, String keyword) {
    FullTextSession fts = Search.getFullTextSession(sessionFactory.getCurrentSession());
    QueryBuilder qb = fts.getSearchFactory().buildQueryBuilder().forEntity(Article.class).get();
    Query luceneQuery = qb.keyword().onFields("title", "content", "description").matching(keyword).createQuery();
    FullTextQuery query = fts.createFullTextQuery(luceneQuery, Article.class);
    query.setFirstResult((pageNum - 1) * pageSize);
    query.setMaxResults(pageSize);
    List<Article> data = query.list();
    //封裝分頁數據
    PageModel<Article> model = new PageModel<>(pageNum, pageSize, data.size());
    //將數據高亮
    model.setData(SearchUtils.hightLight(luceneQuery, data, "title", "content", "description"));
    return model;
}


將數據高亮工具方法

/**
* 高亮顯示文章
* 
* @param query {@link org.apache.lucene.search.Query}
* @param data 未高亮的數據
* @param fields 需要高亮的字段
* @return 高亮數據
*/
public static List<Article> hightLight(Query query, List<Article> data, String... fields) {
    List<Article> result = new ArrayList<Article>();
    Formatter formatter = new SimpleHTMLFormatter("<b style=\"color:red\">", "</b>");
    QueryScorer queryScorer = new QueryScorer(query);
    Highlighter highlighter = new Highlighter(formatter, queryScorer);
    // 使用IK中文分詞
    Analyzer analyzer = new IKAnalyzer();
    for (Article a : data) {
    // 構建新的對象進行返回,避免頁面錯亂(我的頁面有錯亂)
    Article article = new Article();
    for (String fieldName : fields) {
        // 獲得字段值,并給新的文章對象賦值
        Object fieldValue = ReflectionUtils
            .invokeMethod(BeanUtils.getPropertyDescriptor(Article.class, fieldName).getReadMethod(),a);
        ReflectionUtils.invokeMethod(BeanUtils.getPropertyDescriptor(Article.class, fieldName).getWriteMethod(),
            article, fieldValue);
        String hightLightFieldValue = null;
        try {
            hightLightFieldValue = highlighter.getBestFragment(analyzer, fieldName, String.valueOf(fieldValue));
        } catch (Exception e) {
            throw new RuntimeException("高亮顯示關鍵字失敗", e);
        }
        // 如果高亮成功則重新賦值
        if (hightLightFieldValue != null) {
            ReflectionUtils.invokeMethod(BeanUtils.getPropertyDescriptor(Article.class, fieldName).getWriteMethod(),
                article,hightLightFieldValue);
        }
        }
        // 賦值ID
        ReflectionUtils.invokeMethod(BeanUtils.getPropertyDescriptor(Article.class, "id").getWriteMethod(),
            article, a.getId());
        result.add(article);
    }
    return result;
}


4、頁面迭代顯示

<s:iterator value="#request.pageModel.data">
<div class="article">
    <div class="article_title_area">
        <span class="article_title"><a href="${pageContext.request.contextPath }/article/show.action?id=${id }">${title }</a></span>
        <span class="article_date">發表時間:<s:date name="postTime" format="yyyy-MM-dd HH:mm:ss"/></span>
    </div>
    <div class="article_content">${description }</div>
    <div class="article_count_info">
        <span>閱讀(${viewCount })</span>
        <span>評論(${comments.size() })</span>
    </div>
</div>
</s:iterator>
來自:http://my.oschina.net/harmel/blog/491159

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!