搜索功能:lucene
全文检索:以文本作为检索对象,找出含有指定词汇的文本,全面准确和快速是衡量全文检索的关键指标,特点:只处理文本,不处理语义,搜索时英文不区分大小写,结果列表有相关度排序
全文检索不同于数据库的检索:
全文检索不同于数据库的SQL查询。(他们所解决的问题不一样,解决的方案也不一样,所以不应进行对比)。在数据库中的搜索就   是使用SQL,
    如:SELECT * FROM table WHERE content like ‘%ant%’。这样会有如下问题:
    1、匹配效果:如搜索ant会搜索出planting,plant,ant。这样就会搜出很多无关的信息。
    2、相关度排序:查出的结果没有相关度排序,不知道我想要的结果在哪一页。我们在使用百度搜索时,一般不需要翻页,为什么?因为百度做了相关度排序:为每一条结果打一个分数,这条结果越符合搜索条件,得分就越高,叫做相关度得分,结果列表会按照这个分数由高到低排列,所以第1页的结果就是我们最想要的结果。
    3、全文检索的速度大大快于SQL的like搜索的速度。这是因为查询方式不同造成的,以查字典举例:数据库的like就是一页一页的翻,一行一行的找,而全文检索是先查目录,得到结果所在的页码,再直接翻到这一页
lucene相当于索引库,
hello world:
indexwriter:创建索引库
指定索引库的目录位置:fsdirectory.open(new file(""));
指定分词器,创建索引库时按某种分词来创建索引库:new standaranalyzer(version.lucene_30)
限定分词:一个句子最多能分多少个词,最大分词默认值为10000
将article转化为document:
doc.add(new Field("id",article.getId().toString(),Store.YES,Index.ANALYZED));
  * Stroe:表示是否将该字段的值存储到数据区域
      (1):YES:将该字段的值存储到索引库的数据区域,如果将该值存储到数据区域,那么在检索的时候,就能够检索到该字段的值
      (2):NO:将该字段的值不存储到索引库的数据区域,如果将该值没有存储到数据区域,那么在检索的时候,就不能够检索到该字段的值,返回是null
  * Index:表示将数据一定要存储索引库的数据区域,是否对索引库的目录区域进行操作
      (1):ANOLAZER:将数据一定要存储到索引库的数据区域,此时将该值要存储到目录区域一份,同时对该值进行分词,将分词后的值放置到索引库的目录区域
      (2):NOT_ANOLAZER:将数据一定要存储到索引库的数据区域,此时将该值要存储到目录区域一份,同时对该值不进行分词,将整个词的值放置到索引库的目录区域
          例如:id,日期,姓名
      (3):NO:将数据一定要存储到索引库的数据区域,此时不将该值放置到目录区域,如果不放置到目录区域,此时不能通过索引库进行检索

field:向文档中添加字段及字段的值,参数1:为索引库中的字段命名,参数2:将值放置到数据库定义的字段中,参数3:yes:将该字段的值存储到索引库的数据区域,如果将该值存储到数据区域,那么在检索的时候,就能够检索到该字段的值  参数4:analyzed:表示一定要存储索引库的数据区域,此时将该值要存储到目录区域一份,同时,对该值进行分词,将分此后的值放置到索引库的目录区域not_anolazed:表示一定要存储索引库的数据区域,此时将该值要存储到目录区域一份,同时,对该值进行分词,将整个词的值放置到索引库的目录区域
no:表示一定要存储索引库的数据区域,此时不将该值放置到目录区域,如果不放知道目录区域,此时不能通过索引库进行检索
例如:id,日期,姓名不能进行分词
索引库中对应两个区域:目录区域,和数据区域:在索引库中产生一个内部编号,在检索时通过内部编号进行检索,默认是0)

关闭:indexwriter.close();
indexwriter.adddocument(文档),文档中有字段:ID,title,content
检索索引库:
IndexSearcher indexSearcher = new IndexSearcher();
   indexSearcher.search(query,n);

indexsearcher.search(query:封装检索的条件,n:返回的结果记录数)
queryparse:封装检索条件,针对每个字段进行查询
queryparse。parse(查询条件)
针对多个字段进行查询:queryparser=new multifieldqueryparser(版本号,new string[]{},分词器)
通过索引库中存在的内部编号获取document对象,将document对象转换为article了对象,显示article的对象
要保证数据库和索引库时一致的,具体索引库的操作,是调用相应的indexDao方法完成,此类类似于数据库层的DAO
lucene的CRUD:
1:创建索引库
2:删除索引库
team用于为索引库中某个字段指定值team  team=new  term(“”,id.tostring)
2:更新索引库updateDocument(term,document)
索引文件的检索与维护,更新是先删除后创建
测试类:

3:搜索索引库
若不关闭indexwriter,将产生异常,一个线程中,只能存在一个indexwriter对象,并用该对象操作索引库,如果还需要使用第二个indexwriter对象,需要将第一个indexwriter对象关闭,否则会出现异常
同时使用indexwriter和indexsearcher
索引库的优化:将多个索引库的文件合并为一个文件
Optimize:将一个索引库中的多个文件合并为一个文件,如果使用optimize进行优化,需要有足够大的硬盘空间
合并索引库文件:setmergefactor:指定参数用来合并索引库的文件,参数表示当索引库中的数据文件到了几个文件后就自动合并,eg:参数为3:索引库中的数据文件到了3个文件后就自动合并,此参数最小值是2,最大值是10;使用该方法时,不能自动执行,必须要向索引库中添加数据的时候,才能执行优化合并
内存索引库:RAMDrictory,是虚拟的文件夹和文件
当操作完之后,将虚拟内存中的索引库的数据放置到真实索引库中
分词器:创建和检索使用同一个分词器(分词器工作步骤:切分关键词,去除停用词,将大写英文字母转化为小写字母)
单字分词:eg:标准分词器,中文分词器ChineseAnalyzer
二分法分词:CJKAnglyzer,只能分两个字
词库分词:按照某种算法构造词mmanalyzer,ikanalyzer
使用庖丁分词的步骤:(经常用于中文检索)
1:引入jar包
2:ikanalyzer.cfg.xml配置文件,用户在这里可以配置自己的扩展字典,如果配置多个文件的话,用分号分开
3:引入文件,存放停用词
文字高亮:
创建一个高亮器:
1:导入相应jar包
2:创建高亮器对象highlighter(参数1:格式化formatter,参数2:碎片scorer)
3:设置高亮,生成一段摘要,摘要的大小默认为100个字
相关度排序:
boost:得分,sort:排序
得分与检索的文本的内容有关系
设置相关度的,参数:2f:表示原文本得分的2倍
sortfield:表示针对哪个字段进行排序,参数1:针对的字段,参数2:表示按照排列的数据类型
使用sortfield提供的静态方法即可获取
如果使用sort进行排列,得分将失去效果,参数3:表示对字段的排序,true:表示降序,false:升序
默认为升序
string和int类型在比较排序的时候不同eg:
过滤器:
范围进行过滤:参数1:过滤的字段,设置查询字段的最小值,设置查询字段的最大值,是否包含最小值,true包含最小值,false不包含最小值;是否包含最大值,true包含最大值,false不包含最大值
查询:
只针对一个或多个字段进行查询
范围查询:numericrangequery
关键词查询:termquery
通配符查询:wildcardquery:?表示一个字符,*表示多个字符
查询所有:mathalldocsquery
模糊查询:fuzzyquery,0.8F表示最小相似度
短语查询:phrasequery,query.add(参数1:表示titile字段的值,参数2:指定title字段的值出现的位置,位置从0开始)
setslope:表示两个词最大的间隔不超过n
布尔查询:booleanquery
compass:对lucene的封装,类似于hibernate
1:导入jar包
2:在src下建一个compass.cfg.xml
配置索引库的目录,导入映射配置,其他配置
compass API:
CompassConfiguration cfg = new CompassConfiguration().configure(); // compass.cfg.xml
Compass sf = cfg.buildCompass();
CompassSession session = sf.openSession();
CompassTransaction tx = session.beginTransaction();
session.xxxxxx(); // 操作
tx.commit();
session.close();

CompassSession
 create(obj)  建立索引
 save(obj)  保存索引(建立或更新索引)
 delete(class, id) 删除索引
 get/load(..)
 find(String).. 查询
主配置文件 compass.cfg.xml
 1,索引库信息(目录)
 2,导入映射配置
 3,其他配置(分词器、高亮器...)

映射配置
  * 类 -- Document
  * 属性 -- Field
<?xml version="1.0" encoding="UTF-8"?>
<compass-core-config xmlns="http://www.compass-project.org/schema/core-config"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.compass-project.org/schema/core-config
http://www.compass-project.org/schema/compass-core-config-2.2.xsd">

 <compass name="default">
  <!-- 配置索引库的目录 -->
  <connection>
   <file path="./indexDir/" />
  </connection>

  <!-- 导入映射配置 -->
  <mappings>
   <class name="cn.itcast.compassTest.Article" />
  </mappings>
  <!--
      其它配置 
      -->
  <settings>
   <!--   设置高亮器,返回摘要的大小,默认是返回100个词      -->
   <setting name="compass.engine.highlighter.default.fragmenter.simple.size"
    value="20" />
   <!--   生成html的前缀,默认值<b>,<font color='red'>      -->
   <setting name="compass.engine.highlighter.default.formatter.simple.pre"
    value="&lt;font color='red'&gt;" />
   <!-- 生成html的后缀,默认值</b>,</font>      -->
   <setting name="compass.engine.highlighter.default.formatter.simple.post"
    value="&lt;/font&gt;" />
   <!-- 分词器,使用极易分词      -->
   <setting name="compass.engine.analyzer.default.type" value="jeasy.analysis.MMAnalyzer" />
  </settings>


 </compass>
</compass-core-config>   
bean文件:
package cn.itcast.compassTest;

import org.compass.annotations.Index;
import org.compass.annotations.Searchable;
import org.compass.annotations.SearchableBoostProperty;
import org.compass.annotations.SearchableId;
import org.compass.annotations.SearchableProperty;
import org.compass.annotations.Store;
@Searchable
public class Article {
 //format,使用0补全id的字段值,字符串之间的比较:使用补零算法
 @SearchableId(name="id",format="00000000")
 private Integer id;
 @SearchableProperty(name="title",store=Store.YES,index=Index.ANALYZED)
 private String title;
 @SearchableProperty(name="content",store=Store.YES,index=Index.ANALYZED)
 private String content;
 //设置相关度得分,默认值是1F
 @SearchableBoostProperty
 private float boostValue = 1F;

 public float getBoostValue() {
  return boostValue;
 }
 public void setBoostValue(float boostValue) {
  this.boostValue = boostValue;
 }
 public Integer getId() {
  return id;
 }
 public void setId(Integer id) {
  this.id = id;
 }
 public String getTitle() {
  return title;
 }
 public void setTitle(String title) {
  this.title = title;
 }
 public String getContent() {
  return content;
 }
 public void setContent(String content) {
  this.content = content;
 }} 
//创建索引库
 public void createIndex(Article article){
  CompassSession session = CompassUtils.getSession();
  CompassTransaction tr = session.beginTransaction();
  try {
   session.create(article);
   tr.commit();
  } catch (Exception e) {
   tr.rollback();
   e.printStackTrace();
  } finally{
   session.close();
  }
 }
//查询索引库(支持分页)
 public ResultBean<Article> searchIndex(String queryString,int firstResult,int maxResult){
  CompassSession session = CompassUtils.getSession();
  CompassTransaction tr = session.beginTransaction();
  int count = 0;
  List<Article> list = new ArrayList<Article>();
  try {
   CompassHits hits = session.find(queryString);
   count = hits.length();//获取总的记录数
   int endResult = Math.min(firstResult+maxResult, count);
   for(int i=firstResult;i<endResult;i++){
    System.out.println("得分:"+hits.score(i));
    Article article = (Article) hits.data(i);
    list.add(article);
   }
   tr.commit();
  } catch (Exception e) {
   tr.rollback();
   e.printStackTrace();
  } finally{
   session.close();
  }
  return new ResultBean<Article>(count,list);
 }
/*设置高亮
    * 针对数据的content字段设置高亮的效果
    * 如果文本中存在高亮的效果,返回高亮后的值,否则返回null
*/   
   String text=hits.highlighter(i).fragment("content");
   System.out.println("高亮后的效果"+text);
   if(text!=null){
    article.setContent(text);
   }
/*CompassQuery query=session.queryBuilder().queryString(queryString).toQuery();
  query.addSort("id", SortDirection.REVERSE);//按照id的降序排列
*/  //过滤
  /*CompassQueryFilter filter=session.queryFilterBuilder().between("id", 5, 15, true, true);
  query.setFilter(filter);*/

使用短语查询:
/使用短语查询
 CompassQuery query6=session.queryBuilder().multiPhrase("title")
 .add("lucene")
 .add("框架")
 .setSlop(5)
 .toQuery()
使用布尔查询:三种组合形式
  //第一种组合,Must和Must,相当于and,求交集
//第二种组合,MustNot和Must,相当于非+and
//第三种组合,Should和Should,相当于or,求并集
//使用布尔查询,三种组合形式
 CompassQuery query7=session.queryBuilder().bool().addMust(query).addMust(query2).toQuery();
 CompassQuery query8=session.queryBuilder().bool().addMustNot(query).addMust(query2).toQuery();
 CompassQuery query9=session.queryBuilder().bool().addShould(query).addShould(query2).toQuery();