HibernateSearch全文检索技术-工作单索引的建立和搜索
全文检索
我们在向表中插入数据的同时,向外置索引库中也放入响应的数据。等查询的时候,先查询索引库,然后再查询表。
第一步:建立索引: 向表中插入数据的同时,向外置索引库中也放入相应的数据。 表: id arrivecity 1 上海浦东 2 深圳宝安
索引库:(先分词-再存储,分词的效果依赖于中文分词器) id name 1 1 2 上海 3 浦东
第二步:通过索引查询 当要模糊查询:到达地带有“上海”, 先从索引库中直接查询有没有叫“上海”,获取了该词条所在的数据在数据库中的主键值。 接着:拿主键到数据库中查询,select * from table where id in(,,,,,,,) 因为:Oracle主键上自动带有唯一索引,因此,根据主键查询,自动会使用索引,效率很高。
对工作单数据建立索引
技术:Lucene(建立索引)+hibernate Search(操作的api) Hibernate Search是给Hibernate持久化模型架构来使用的一套全文检索工具,其全文检索依赖于Lucence引擎。
引入Maven坐标(引入hibernate search和IK分词器的jar包)
<PRoperties> <hibernate-search.version>3.4.2.Final</hibernate-search.version> <IKAnalyzer.version>3.2.8</IKAnalyzer.version> </properties> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-search</artifactId> <version>${hibernate-search.version}</version> </dependency> <!-- ik分词器 --> <dependency> <groupId>IKAnalyzer</groupId> <artifactId>IKAnalyzer</artifactId> <version>${IKAnalyzer.version}</version> </dependency>lucence版本必须和Hibernate版本对应
<!--IK分词器--> <dependency> <groupId>com.janeluo</groupId> <artifactId>ikanalyzer</artifactId> <version>2012_u6</version> </dependency>IK分词器的配置: 将IKAnalyzer.cfg.xml和stopWord.dic复制到src/resources下.
索引存放的基础目录配置:
<!-- 索引文件存放的目录 --> <prop key="hibernate.search.default.indexBase">f:/index</prop>索引的内容配置(通过注解方式配置实体类,可对哪些数据进行索引) @Indexed 对实体建立索引 @DocumentId id @Field 字段 @Analyzer 使用分词器
Hibernate Search是基于lucence的,无需手动编写lucence代码即可进行Hibernate操作,会自动创建索引、修改索引、删除索引。 测试原理:在保存数据的时候,Hibernate Search,会在向数据库保存数据(完整)的同时,在索引库中也保存索引数据(分词后的数据,部分数据)。
查看索引:使用lukeall工具。Luke 是查询LUCENE索引文件的工具, 而且用 Luke 的Search可以做查询. 执行: java -jar lukeall-3.5.0.jar 在path中输入索引的文件夹的路径
实现搜索
//自定义的Spring Data实现类无需实现接口,只需要类名以Impl结尾, //且被<jpa:repositories base-package="cn.aric.bos.dao"/>扫描到即可 //原理:spring data jpa会自动到<jpa:repositories base-package="cn.aric.bos.dao"/>中, //优先寻找接口类名+Impl后缀的类,作为实现类,并自动继承simple。。。Repository public class WorkOrderManageDAOImpl{ //想在spring data jpa中获取EntityManager @PersistenceContext//自动注入 private EntityManager entityManager; /** * 通过luncence查询数据 * 说明: * @return */ public Page<WorkOrderManage> searchByLucence(Pageable pageable, String conditionName, String conditionValue){ //分析:将关键字和值交给lucence(Hibernatesearch的api),绑定数据库的表查询, //Hibernate search会“自动”先从全文搜索中找id,然后通过id查询数据库 //-----lucence的query对象 //---第一类搜索:一类长词分词模糊匹配 //参数1:lucence版本 //参数2:索引的字段的名字(查询的字段的名字) //参数3:分词器 QueryParser queryParser = new QueryParser(Version.LUCENE_31, conditionName, new IKAnalyzer()); //查询的关键字(解析器会自动分词后再查询) Query fenciQuery=null; try { fenciQuery = queryParser.parse(conditionValue); } catch (ParseException e) { throw new RuntimeException("不能解析分词这个关键字: " + conditionValue, e); } ////---第二类搜索:短词直接匹配 //参数:直接字段名和值 Query duanciQuery=new WildcardQuery(new Term(conditionName,"*"+conditionValue+"*")); //将两个query结合起来---生成lunce的最终查询对象 BooleanQuery query = new BooleanQuery(); query.add(fenciQuery, Occur.SHOULD);//must:相当于and,SHOULD相当于or query.add(duanciQuery, Occur.SHOULD); //根据EntityManager来创建一个全文实体管理对象 FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager); //++++返回的是全文检索的查询对象---------最终要要Hibernate search。。。。--- //参数1。lucence Query对象 //参数2:实体类,带有索引注解的实体类 FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(query, WorkOrderManage.class); //-----上述代码,Hibernate search结合了lucence和jpa的查询数据库的查询,查询内部,都hs封装 //---封装结果集page对象 int total = fullTextQuery.getResultSize();//列表的总的数量 //现在分页数据,是Hibernate search来分调用jpa fullTextQuery.setFirstResult(pageable.getPageNumber()*pageable.getPageSize());//起始索引 fullTextQuery.setMaxResults(pageable.getPageSize());//每页最大记录数 List<WorkOrderManage> content = fullTextQuery.getResultList();//数据列表 //结果—手动封装 Page<WorkOrderManage> page = new PageImpl<WorkOrderManage>(content, pageable, total); return page; } }运行原理
1、构造LuceneQuery查询索引库 2、EntityManager 构造 FullTextEntityManager 查询数据库 3、合并EntityManager 和 LuceneQuery —– FullTextQuery 查询索引库和数据库 4、查询索引库 fullTextQuery.getResultSize(); 查询索引,去重id 5、查询数据库 fullTextQuery.getResultList(); 根据索引库返回 id ,查询数据库