文档章节

将Hibernate Search集成进已有项目中,实现全文检索功能

Harmel
 Harmel
发布于 2015/08/12 12:26
字数 832
阅读 5719
收藏 43

本来是准备使用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方法
    //........
}

注解说明:

@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>

© 著作权归作者所有

Harmel
粉丝 9
博文 33
码字总数 14582
作品 0
武汉
程序员
私信 提问
加载中

评论(10)

NewAdmin
NewAdmin

引用来自“NewAdmin”的评论

Caused by: java.lang.NoSuchMethodError: org.hibernate.cfg.annotations.reflection.XMLContext.<init>(Lorg/hibernate/boot/spi/ClassLoaderAccess;)V.集成之后出现这样的错误,不知道怎么解决啊

引用来自“Harmel”的评论

会不会是导入的包版本过低

引用来自“NewAdmin”的评论

我把hibernate search的optional文件夹里面的所有jar包都导入了,然后上面的错就解决了,现在出现了新的问题就是QueryBuilder qb = fts.getSearchFactory().buildQueryBuilder().forEntity(ServiceInfo.class).get();这行运行之后就出现java.lang.IllegalArgumentException: Entity for which to retrieve the scoped analyzer is not an @Indexed entity: com.example.domain.ServiceInfo异常,还没有找到解决办法呢

引用来自“Harmel”的评论

实体类没加@Indexed注解

引用来自“NewAdmin”的评论

com.example.domain.ServiceInfo @Entity @Indexed(index="ServiceInfo") @Analyzer(impl=IKAnalyzer.class) 这个在DAO层指向ServiceInfo类的时候查看到的,本来是想给你截图的,但是这个不能上传图片,所以就只能文字回你了

引用来自“Harmel”的评论

我也不知道怎么解决了,你不指定存储位置试试只加@Indexed去掉index属性
还是相同的报错信息,真心不知道怎么回事了。你集成的那个版本的hibernate search?或者你把实例工程给我看一下。QQ:1414536227
Harmel
Harmel

引用来自“NewAdmin”的评论

Caused by: java.lang.NoSuchMethodError: org.hibernate.cfg.annotations.reflection.XMLContext.<init>(Lorg/hibernate/boot/spi/ClassLoaderAccess;)V.集成之后出现这样的错误,不知道怎么解决啊

引用来自“Harmel”的评论

会不会是导入的包版本过低

引用来自“NewAdmin”的评论

我把hibernate search的optional文件夹里面的所有jar包都导入了,然后上面的错就解决了,现在出现了新的问题就是QueryBuilder qb = fts.getSearchFactory().buildQueryBuilder().forEntity(ServiceInfo.class).get();这行运行之后就出现java.lang.IllegalArgumentException: Entity for which to retrieve the scoped analyzer is not an @Indexed entity: com.example.domain.ServiceInfo异常,还没有找到解决办法呢

引用来自“Harmel”的评论

实体类没加@Indexed注解

引用来自“NewAdmin”的评论

com.example.domain.ServiceInfo @Entity @Indexed(index="ServiceInfo") @Analyzer(impl=IKAnalyzer.class) 这个在DAO层指向ServiceInfo类的时候查看到的,本来是想给你截图的,但是这个不能上传图片,所以就只能文字回你了
我也不知道怎么解决了,你不指定存储位置试试只加@Indexed去掉index属性
NewAdmin
NewAdmin

引用来自“NewAdmin”的评论

Caused by: java.lang.NoSuchMethodError: org.hibernate.cfg.annotations.reflection.XMLContext.<init>(Lorg/hibernate/boot/spi/ClassLoaderAccess;)V.集成之后出现这样的错误,不知道怎么解决啊

引用来自“Harmel”的评论

会不会是导入的包版本过低

引用来自“NewAdmin”的评论

我把hibernate search的optional文件夹里面的所有jar包都导入了,然后上面的错就解决了,现在出现了新的问题就是QueryBuilder qb = fts.getSearchFactory().buildQueryBuilder().forEntity(ServiceInfo.class).get();这行运行之后就出现java.lang.IllegalArgumentException: Entity for which to retrieve the scoped analyzer is not an @Indexed entity: com.example.domain.ServiceInfo异常,还没有找到解决办法呢

引用来自“Harmel”的评论

实体类没加@Indexed注解
com.example.domain.ServiceInfo @Entity @Indexed(index="ServiceInfo") @Analyzer(impl=IKAnalyzer.class) 这个在DAO层指向ServiceInfo类的时候查看到的,本来是想给你截图的,但是这个不能上传图片,所以就只能文字回你了
NewAdmin
NewAdmin

引用来自“NewAdmin”的评论

Caused by: java.lang.NoSuchMethodError: org.hibernate.cfg.annotations.reflection.XMLContext.<init>(Lorg/hibernate/boot/spi/ClassLoaderAccess;)V.集成之后出现这样的错误,不知道怎么解决啊

引用来自“Harmel”的评论

会不会是导入的包版本过低

引用来自“NewAdmin”的评论

我把hibernate search的optional文件夹里面的所有jar包都导入了,然后上面的错就解决了,现在出现了新的问题就是QueryBuilder qb = fts.getSearchFactory().buildQueryBuilder().forEntity(ServiceInfo.class).get();这行运行之后就出现java.lang.IllegalArgumentException: Entity for which to retrieve the scoped analyzer is not an @Indexed entity: com.example.domain.ServiceInfo异常,还没有找到解决办法呢

引用来自“Harmel”的评论

实体类没加@Indexed注解
上面的错误信息就是在加入@Indexed注解之后还是出现了,真不知道是咋回事呢。
Harmel
Harmel

引用来自“NewAdmin”的评论

Caused by: java.lang.NoSuchMethodError: org.hibernate.cfg.annotations.reflection.XMLContext.<init>(Lorg/hibernate/boot/spi/ClassLoaderAccess;)V.集成之后出现这样的错误,不知道怎么解决啊

引用来自“Harmel”的评论

会不会是导入的包版本过低

引用来自“NewAdmin”的评论

我把hibernate search的optional文件夹里面的所有jar包都导入了,然后上面的错就解决了,现在出现了新的问题就是QueryBuilder qb = fts.getSearchFactory().buildQueryBuilder().forEntity(ServiceInfo.class).get();这行运行之后就出现java.lang.IllegalArgumentException: Entity for which to retrieve the scoped analyzer is not an @Indexed entity: com.example.domain.ServiceInfo异常,还没有找到解决办法呢
实体类没加@Indexed注解
NewAdmin
NewAdmin

引用来自“NewAdmin”的评论

Caused by: java.lang.NoSuchMethodError: org.hibernate.cfg.annotations.reflection.XMLContext.<init>(Lorg/hibernate/boot/spi/ClassLoaderAccess;)V.集成之后出现这样的错误,不知道怎么解决啊

引用来自“Harmel”的评论

会不会是导入的包版本过低
目前的版本是3.3.2,hibernate也是这个版本,不知道怎么回事呢。
NewAdmin
NewAdmin

引用来自“NewAdmin”的评论

Caused by: java.lang.NoSuchMethodError: org.hibernate.cfg.annotations.reflection.XMLContext.<init>(Lorg/hibernate/boot/spi/ClassLoaderAccess;)V.集成之后出现这样的错误,不知道怎么解决啊

引用来自“Harmel”的评论

会不会是导入的包版本过低
我把hibernate search的optional文件夹里面的所有jar包都导入了,然后上面的错就解决了,现在出现了新的问题就是QueryBuilder qb = fts.getSearchFactory().buildQueryBuilder().forEntity(ServiceInfo.class).get();这行运行之后就出现java.lang.IllegalArgumentException: Entity for which to retrieve the scoped analyzer is not an @Indexed entity: com.example.domain.ServiceInfo异常,还没有找到解决办法呢
Harmel
Harmel

引用来自“NewAdmin”的评论

Caused by: java.lang.NoSuchMethodError: org.hibernate.cfg.annotations.reflection.XMLContext.<init>(Lorg/hibernate/boot/spi/ClassLoaderAccess;)V.集成之后出现这样的错误,不知道怎么解决啊
会不会是导入的包版本过低
NewAdmin
NewAdmin
Caused by: java.lang.NoSuchMethodError: org.hibernate.cfg.annotations.reflection.XMLContext.<init>(Lorg/hibernate/boot/spi/ClassLoaderAccess;)V.集成之后出现这样的错误,不知道怎么解决啊
王峰
王峰
博主,效率怎样?
Hibernate Search 5.11.0.Final 发布,数据检索框架

Hibernate Search 5.11.0.Final 已发布,这是 5.11 分支的首个稳定版本,更新亮点如下: HSEARCH-3433: Hibernate Search 的 ORM 集成现在依赖于 Hibernate ORM 5.4.0.Final ; HSEARCH-3420...

王练
2018/12/26
0
0
Hibernate Search 3.3 Beta1 发布

Hibernate Search的作用是对数据库中的数据进行检索的。它是hibernate对著名的全文检索系统Lucene的一个集成方案,作用在于对数据表中某些内容庞大的字段(如声明为text的字段)建立全文索引...

红薯
2010/08/26
307
0
Hibernate Search 6.0.0.Alpha3 发布,数据检索框架

Hibernate Search 6.0.0.Alpha3 已发布,这是仍处于开发中的 6.0 分支的第三个版本。该版本主要增加了对更多字段类型和谓词的支持,并带来更一致、更简洁的 API。 入门 Hibernate Search 6 如...

局长
03/24
0
0
Hibernate搜索框架--Hibernate Search

Hibernate Search的作用是对数据库中的数据进行检索的。它是hibernate对著名的全文检索系统Lucene的一个集成方案,作用在于对数据表中某些内容庞大的字段(如声明为text的字段)建立全文索引...

匿名
2008/10/28
26.1K
2
Hibernate Search 4.4.0.Alpah1

Hibernate Search 发布了 4.4.0 的首个 Alpha 版本,该版本修复了 16 个问题,详情请看 Jira release notes. 下载地址:http://sourceforge.net/projects/hibernate/files/hibernate-search/......

红薯
2013/08/05
913
0

没有更多内容

加载失败,请刷新页面

加载更多

八、RabbitMQ的集群原理

集群架构 写在前面 RabbitMQ集群是按照低延迟环境设计的,千万不要跨越WAN或者互联网来搭建RabbitMQ集群。如果一定要在高延迟环境下使用RabbitMQ集群,可以参考使用Shovel和Federation工具。...

XuePeng77
今天
1
0
mac系统下,brew 安装mysql,用终端可以连接,navicat却连接不上?

问题: 1.报错? 2059 - Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(../Frameworks/caching_sha2_password.so, 2): image not found 2.自己通过设置,已经把密......

写bug的攻城狮
昨天
2
0
老生常谈,HashMap的死循环

问题 最近的几次面试中,我都问了是否了解HashMap在并发使用时可能发生死循环,导致cpu100%,结果让我很意外,都表示不知道有这样的问题,让我意外的是面试者的工作年限都不短。 由于HashMap...

群星纪元
昨天
5
0
拉普拉斯算子

拉普拉斯算子是二阶微分算子。 我们知道,一维离散信号一阶微分公式如下: 相应的,一维离散信号二阶微分公式如下: 由于图像有x和y两个方向,因此图像信号属于二维离散信号。其在x,y两个...

yepanl
昨天
3
0
记录"正则表达式"

详细请查看我的博客:https://blog.enjoytoshare.club/article/RegularExpression.html 1 写在前面 正则表达式(Regular Expression)在代码中常常简写为regex。正则表达式通常被用来检索、替...

wugenqiang
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部