Lucene笔记二

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Sugar_map/article/details/82788385

本文的核心内容:Lucene索引加权和默认加权方式,Query查询,高亮查询,分页查询。


一:Lucene的默认打分机制

当一个文档出现在了搜索结果中,这就意味着该文档与用户给定的查询语句是相匹配的。Lucene会对匹配成功的文档给定一个分数。至少从Lucene这个层面,从打分公式的结果来看,分数值越高,代表文档相关性越高。

为了计算出一个文档的得分,我们必须考虑如下的因素:

.文档权重(Document boost):在索引时给某个文档设置的权重值。

· 域权重(Field boost):在查询的时候给某个域设置的权重值。

· 调整因子(Coord):基于文档中包含查询关键词个数计算出来的调整因子。一般而言,如果一个文档中相比其它的文档出现了更多的查询关键词,那么其值越大。

· 逆文档频率(Inerse document frequency):基于Term的一个因子,存在的意义是告诉打分公式一个词的稀有程度。其值越低,词越稀有(这里的值是指单纯的频率,即多少个文档中出现了该词;而非指Lucene中idf的计算公式)。打分公式利用这个因子提升包含稀有词文档的权重。

· 长度归一化(Length norm):基于域的一个归一化因子。其值由给定域中Term的个数决定(在索引文档的时候已经计算出来了,并且存储到了索引中)。域越的文本越长,因子的权重越低。这表明Lucene打分公式偏向于域包含Term少的文档。

· 词频(Term frequency):基于Term的一个因子。用来描述给定Term在一个文档中出现的次数,词频越大,文档的得分越大。

· 查询归一化因子(Query norm):基于查询语句的归一化因子。其值为查询语句中每一个查询词权重的平方和。查询归一化因子使得比较不同查询语句的得分变得可行,当然比较不同查询语句得分并不总是那么易于实现和可行的。

Lucene的打分方式:

我们只需要知道在进行文档打分的时候,哪些因素是起决定作用的就可以了。基本上,从前面的公式中可以提炼出以下的几个规则:

· 匹配到的关键词越稀有,文档的得分就越高。

· 文档的域越小(包含比较少的Term),文档的得分就越高。

· 设置的权重(索引和搜索时设置的都可以)越大,文档得分越高。

Lucene加权时机【加权->创建索引时加权】

// StringField 无法加权

// 加权检索不能通配符查询或者模糊查询

// 排名靠前 权值变动 检索结果也会发生变化 权值高的文档排名靠前

TextField name = new TextField("content", contents[i], TextField.Store.YES);

// 加权方法 默认加权权值 1.0f

name.setBoost(3.0f); // 上限

二:Lucene查询的Query

常用 Query 查询

  • TermQuery 词元检索
  //  基于词元的检索
  query = new TermQuery(new Term("name","aa"));
  • TermRangeQuery 词元范围检索
  //  基于词元范围的检索 字符或者字母范围
  //  参一:检索域 参二:起始字符  参三: 结束字符 参四:是不是包含起始 参五:是不是包含结束
  query = new TermRangeQuery("name",new BytesRef("aa"),new BytesRef("ae"),false,false);
  • NumericRangeQuery 数字范围检索
  //  基于数字范围的检索 id 数字 1-5
  //  参数一:检索域名 参数二:最小 参数三:最大 参数四:是不是包含最小 参数五:是不是包含最大
  query = NumericRangeQuery.newIntRange("id",3,5,true,false);
  • PrefixQuery 前缀检索
  //  基于前缀的检索 检索参数为 term term 中参数为检索域名 和 前缀
  query = new PrefixQuery(new Term("name","a"));
  • WildcardQuery 通配查询
  //  基于通配符的检索 ?  占位符一个字符 *  匹配零个或者多个字符
  query = new WildcardQuery(new Term("name","?b"));
  query = new WildcardQuery(new Term("name","*c"));
  • FuzzyQuery 模糊查询
  //  基于模糊的检索 只要在一定误差范围内都可以检索到 符合条件内容和相似内容
  query = new FuzzyQuery(new Term("name","az"));
  query = new FuzzyQuery(new Term("content"," 一 "));
  • BooleanQuery 布尔查询
  //  多条件检索 检索 id 为 1 的文档 并且 content 内容有 “ 海 ”  文档
  // BooleanClause.Occur.MUST 并
  // BooleanClause.Occur.MUST_NOT 非
  // BooleanClause.Occur.SHOULD  或
  BooleanQuery booleanQuery = new BooleanQuery();
  // name 域中必须有 aa
  booleanQuery.add(new TermQuery(new Term("name","aa")), BooleanClause.Occur.MUST);
  • PhraseQuery 短语查询
  //  基于短语的检索 应用于 英文短语查询 i am gaozhy,welcome to bejing
  //  词与词的偏移量
  query = new PhraseQuery(2,"content"," 一 "," 三 ");

基于 QueryParser 的高级搜索 ( 可以替换 Query 查询 )

语法: [] {} * ? ~ ^ "" + - AND OR NOT

基于词元的检索 : parse("content: 河 ");

基于词元范围的检索 : parse("name:[aa TO ae}"); 不支持数字

基于前缀和通配符检索 : parse("name:a?"); parse("name:a*");

基于模糊检索 : parse("name:aa~"); “~” 模糊检索

基于 boolean 检索 : AND NOT OR + - 基于短语检索 parse("name:"hello "~1");

三:Lucene的高亮、分页查询

/**
  *  分页检索 高亮效果
  * limit 0,10
  * 1.  第一种方式:将所有的结果检索,对结果直接截取分页 lucene
  * 2.  第二种方式: searchAfter(ScoreDoc,query,pageSize);
  */
  @Test
  public void searchByHighLighter(){
  int nowPage = 1;
  int pageSize = 2;
  try {
  FSDirectory fsDirectory = 
  FSDirectory.open(Paths.get("D:\\lucene\\index\\secondIndex"));
  ​
  DirectoryReader directoryReader = DirectoryReader.open(fsDirectory);
  //  所有文档数
  directoryReader.maxDoc();
  //  有索引的文档数
  directoryReader.numDocs();
  IndexSearcher indexSearcher = new IndexSearcher(directoryReader);
  QueryParser queryParser = new QueryParser("content",new StandardAnalyzer());
  Query query = queryParser.parse(" 爱 ");
  TopDocs topDocs = null;
  //  第一页直接检索
  if(nowPage==1){
  topDocs = indexSearcher.search(query,pageSize);
  }else{
  //  计算 start
  int start = (nowPage-1)*pageSize;
  topDocs = indexSearcher.search(query,start);
  //  最后一个 ScoreDoc 对象
  //  参数一:当前页的上一页的最后一个 ScoreDoc 对象 参数二:检索条件 参数:查几条
  // searchAfter :从参数一的 ScoreDoc 对象后 进行检索,并检索参数三 条文档
  topDocs = indexSearcher.searchAfter(topDocs.scoreDocs[topDocs.scoreDocs.length-1],query,pageSize);
  }
  //  获取命中数 符合条件总条数
  //  总页数:
  System.out.println(" 总命中数: "+topDocs.totalHits);
  //  指定高亮格式
  SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<span style='color:red'>", "</span>");
  //  创建 Scorer
  QueryScorer queryScorer = new QueryScorer(query);
  //  创建高亮器
  Highlighter highlighter = new Highlighter(formatter,queryScorer);
  ScoreDoc[] scoreDocs = topDocs.scoreDocs;
  for (ScoreDoc scoreDoc : scoreDocs) {
  System.out.println(" 文档得分: " + scoreDoc.score);
  int docId = scoreDoc.doc;
  Document document = indexSearcher.doc(docId);
  String highlighterBestFragment =highlighter.getBestFragment(new StandardAnalyzer(),"content",document.get("content"));
  System.out.println(document.get("id") + " " + document.get("name") + " " + highlighterBestFragment + " " + document.get("birthday"));
  }
  } catch (Exception e) {
  e.printStackTrace();
  }
  }

猜你喜欢

转载自blog.csdn.net/Sugar_map/article/details/82788385