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 = new RAMDirectory(); IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(Version.LUCENE_30), IndexWriter.MaxFieldLength.UNLIMITED); for(int i=0;i<10;i++) { Document doc = new Document(); doc.add(new Field("id", ""+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); } // 会将缓存中所有变更,刷新到索引目录,返回一个包含这些变更的新的reader IndexReader reader = writer.getReader(); // #1 创建近实时 reader IndexSearcher searcher = new IndexSearcher(reader); // #A Query query = new TermQuery(new Term("text", "aaa")); TopDocs docs = searcher.search(query, 1); assertEquals(10, docs.totalHits); // #B writer.deleteDocuments(new Term("id", "7")); // #2 Document doc = new Document(); // #3 doc.add(new Field("id", // #3 "11", // #3 Field.Store.NO, // #3 Field.Index.NOT_ANALYZED_NO_NORMS)); // #3 doc.add(new Field("text", // #3 "bbb", // #3 Field.Store.NO, // #3 Field.Index.ANALYZED)); // #3 writer.addDocument(doc); // #3 // reopen 完成更多变更,效率很高: // 只会打开上次open、reopen的文件 // 未发生任何改变的被共享(共享先前的reader) IndexReader newReader = reader.reopen(); // #4 assertFalse(reader == newReader); // #5 reader.close(); // #6 searcher = new IndexSearcher(newReader); TopDocs hits = searcher.search(query, 10); // #7 assertEquals(9, hits.totalHits); // #7 query = new TermQuery(new Term("text", "bbb")); // #8 hits = searcher.search(query, 1); // #8 assertEquals(1, hits.totalHits); // #8 newReader.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的 评分机制
- 评分公式(详见之前博客的推导公式):
explain() 方法理解搜索结果评分:
- 开销和查询是一样的,不要过度使用
-
public class Explainer { public static void main(String[] args) throws Exception { if (args.length != 2) { System.err.println("Usage: Explainer <index dir> <query>"); System.exit(1); } String indexDir = args[0]; String queryExpression = args[1]; Directory directory = FSDirectory.open(new File(indexDir)); QueryParser parser = new QueryParser(Version.LUCENE_30, "contents", new SimpleAnalyzer()); Query query = parser.parse(queryExpression); System.out.println("Query: " + queryExpression); IndexSearcher searcher = new IndexSearcher(directory); TopDocs topDocs = searcher.search(query, 10); for (ScoreDoc match : topDocs.scoreDocs) { Explanation explanation = searcher.explain(query, match.doc); //#A System.out.println("----------"); Document doc = searcher.doc(match.doc); System.out.println(doc.get("title")); System.out.println(explanation.toString()); //#B } searcher.close(); directory.close(); } }
Lucene 多样化查询:
- 详见之前博客内容
解析查询表达式:QueryParser
- 需要转义的字符:
- Query.toString()
- 查看 QueryParser 对象解析后的样子
TermQuery
- 将 查询自动解析为 输出的样子
项范围查询:
- [] 边界值包含在内,{} 不包含在内
通配符查询仅仅在末尾有一个*
- 会被优化为前缀查询
- 二者都会转化大小写,不过能人为设置不转化
布尔查询::
- AND OR NOT 必须全部大写
- 默认是OR (a b 默认认为是 a OR b)
- 可修改默认:
- NOT 不能单独使用
短语查询:
- 双引号括起来的项,转化为短语查询
- “this is tom cat*”
- 分析结果 tom cat
- 注意 前俩是停用词
- 最后的* 在双引号内不考虑
- 分析结果 tom cat
- 不设置slop 默认值为0
- SpanNearQuery 确保按照顺序
- PhraseQuery 松散的,不一定按照顺序
- “this is tom cat*”
模糊查询:
- ~0.7 指定最小相似 程度
MatchAllDocsQuery
- *:* 会被解析为 MatchAllDocsQuery
分组查询:
- 小括号,来建立子查询
域选择:
- 要求用户知道被搜索的域是不太友善的
- 默认的域在创建QueryParser 时创建
- 也可以指定默认域为所有域
- title:lucene 限定查询域为title
- filed (a b c)
- filed:a OR filed:b OR filed:c
为子查询加权
- junit 加权为 2.0 testing 1.0
是否一定使用QueryParser
- QueryParser 提供了快捷强大的查询构建
- 不能适合所有的场合
来源:oschina
链接:https://my.oschina.net/u/3847203/blog/2999334