我们在向表中插入数据的同时,向外置索引库中也放入响应的数据。等查询的时候,先查询索引库,然后再查询表。
第一步:建立索引:
向表中插入数据的同时,向外置索引库中也放入相应的数据。
表:
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 ,查询数据库