2019独角兽企业重金招聘Python工程师标准>>>
QueryParser 类的使用
- matchVersion 值的是 版本(为了兼容)
- 解析表达式
- 不成功抛出 ParseException
- 多个项时,默认是OR
IndexSearcher
- IndexReader 打开索引文件、提供底层redaer API 的繁重工作
- 需要较大系统开销
- 在搜索其间最好打开一个大家公用就好
- 需要限制其打开的频率(可以类似 数据库 connection处理)
- reopen 消耗较少的系统资源
- 如果索引变更,会返回新的reader ,和旧的不一样
- 此时依然有很多程序在使用旧的reader ,请保证线程安全
- 如下所示,如果不一样,想看到新的索引,需要创建新的IndexSearcher
实现搜索功能
- search() 方法
- 其他高级搜索包括过滤和排序
使用TopDocs 类
- TopDocs.totalHits
- TopDocs.scoreDocs:匹配的顶部文档数组
搜索结果分页
- 分页两种实现:
- 重新查询往往更好,Lucene的高性能查询弥补了其浪费资源的短板
- 操作系统的I/O缓存机制,使得重新查询很快结束
- 重新查询往往更好,Lucene的高性能查询弥补了其浪费资源的短板
近实时搜索
- 不必关闭writer、再向该writer 提交
- 长期打开一个IndexWriter 完成持续变更
- 允许对新创建的、还未提交的段进行搜索
-
public class NearRealTimeTest extends TestCase {public void testNearRealTime() throws Exception {Directory dir &#61; new RAMDirectory();IndexWriter writer &#61; new IndexWriter(dir, new StandardAnalyzer(Version.LUCENE_30), IndexWriter.MaxFieldLength.UNLIMITED);for(int i&#61;0;i<10;i&#43;&#43;) {Document doc &#61; new Document();doc.add(new Field("id", ""&#43;i, Field.Store.NO, Field.Index.NOT_ANALYZED_NO_NORMS));doc.add(new Field("text", "aaa", Field.Store.NO, Field.Index.ANALYZED));writer.addDocument(doc);}// 会将缓存中所有变更&#xff0c;刷新到索引目录&#xff0c;返回一个包含这些变更的新的readerIndexReader reader &#61; writer.getReader(); // #1 创建近实时 readerIndexSearcher searcher &#61; new IndexSearcher(reader); // #AQuery query &#61; new TermQuery(new Term("text", "aaa"));TopDocs docs &#61; searcher.search(query, 1);assertEquals(10, docs.totalHits); // #Bwriter.deleteDocuments(new Term("id", "7")); // #2Document doc &#61; new Document(); // #3doc.add(new Field("id", // #3"11", // #3Field.Store.NO, // #3Field.Index.NOT_ANALYZED_NO_NORMS)); // #3doc.add(new Field("text", // #3"bbb", // #3Field.Store.NO, // #3Field.Index.ANALYZED)); // #3writer.addDocument(doc); // #3// reopen 完成更多变更&#xff0c;效率很高&#xff1a;// 只会打开上次open、reopen的文件// 未发生任何改变的被共享&#xff08;共享先前的reader&#xff09; IndexReader newReader &#61; reader.reopen(); // #4assertFalse(reader &#61;&#61; newReader); // #5reader.close(); // #6searcher &#61; new IndexSearcher(newReader); TopDocs hits &#61; searcher.search(query, 10); // #7assertEquals(9, hits.totalHits); // #7query &#61; new TermQuery(new Term("text", "bbb")); // #8hits &#61; searcher.search(query, 1); // #8assertEquals(1, hits.totalHits); // #8newReader.close();writer.close();}
}/*#1 Create near-real-time reader#A Wrap reader in IndexSearcher#B Search returns 10 hits#2 Delete 1 document#3 Add 1 document#4 Reopen reader#5 Confirm reader is new#6 Close old reader#7 Verify 9 hits now#8 Confirm new document matched
*/
理解Lucene的 评分机制
- 评分公式(详见之前博客的推导公式)&#xff1a;
explain() 方法理解搜索结果评分&#xff1a;
- 开销和查询是一样的&#xff0c;不要过度使用
-
public class Explainer {public static void main(String[] args) throws Exception {if (args.length !&#61; 2) {System.err.println("Usage: Explainer
");System.exit(1);}String indexDir &#61; args[0];String queryExpression &#61; args[1];Directory directory &#61; FSDirectory.open(new File(indexDir));QueryParser parser &#61; new QueryParser(Version.LUCENE_30,"contents", new SimpleAnalyzer());Query query &#61; parser.parse(queryExpression);System.out.println("Query: " &#43; queryExpression);IndexSearcher searcher &#61; new IndexSearcher(directory);TopDocs topDocs &#61; searcher.search(query, 10);for (ScoreDoc match : topDocs.scoreDocs) {Explanation explanation&#61; searcher.explain(query, match.doc); //#ASystem.out.println("----------");Document doc &#61; searcher.doc(match.doc);System.out.println(doc.get("title"));System.out.println(explanation.toString()); //#B}searcher.close();directory.close();}
}
Lucene 多样化查询&#xff1a;
- 详见之前博客内容
解析查询表达式&#xff1a;QueryParser
- 需要转义的字符&#xff1a;
- Query.toString()
- 查看 QueryParser 对象解析后的样子
TermQuery
- 将 查询自动解析为 输出的样子
项范围查询&#xff1a;
- [] 边界值包含在内&#xff0c;{} 不包含在内
通配符查询仅仅在末尾有一个*
- 会被优化为前缀查询
- 二者都会转化大小写&#xff0c;不过能人为设置不转化
布尔查询&#xff1a;&#xff1a;
- AND OR NOT 必须全部大写
- 默认是OR &#xff08;a b 默认认为是 a OR b&#xff09;
- 可修改默认&#xff1a;
- NOT 不能单独使用
短语查询&#xff1a;
- 双引号括起来的项&#xff0c;转化为短语查询
- “this is tom cat*”
- 分析结果 tom cat
- 注意 前俩是停用词
- 最后的* 在双引号内不考虑
- 分析结果 tom cat
- 不设置slop 默认值为0
- SpanNearQuery 确保按照顺序
- PhraseQuery 松散的&#xff0c;不一定按照顺序
- “this is tom cat*”
模糊查询&#xff1a;
- ~0.7 指定最小相似 程度
MatchAllDocsQuery
- *&#xff1a;* 会被解析为 MatchAllDocsQuery
分组查询&#xff1a;
- 小括号&#xff0c;来建立子查询
域选择&#xff1a;
- 要求用户知道被搜索的域是不太友善的
- 默认的域在创建QueryParser 时创建
- 也可以指定默认域为所有域
- title&#xff1a;lucene 限定查询域为title
- filed &#xff08;a b c&#xff09;
- filed&#xff1a;a OR filed&#xff1a;b OR filed&#xff1a;c
为子查询加权
- junit 加权为 2.0 testing 1.0
是否一定使用QueryParser
- QueryParser 提供了快捷强大的查询构建
- 不能适合所有的场合