Lucene 使用代码实例之搜索文档

纠结的忘忆 贡献于2014-04-24

作者   创建于2011-07-19 16:33:06   修改者  修改于1899-12-30 00:00:00字数33622

文档摘要:1,Query类:这是一个抽象类,用于将用户输入的查询字符串封装成Lucene能够识别的Query,它具有TermQuery,BooleanQuery,PrefixQuery等多种实现。2,Term类:用于描述搜索的基本单位,其构造函数是Term(“fieldName”,”queryWord”),其中第一个参数代表要在文档的哪一个Field上进行搜索,第二个参数代表要搜索的关键词。
关键词:

Lucene使用代码实例之搜索文档 1,Query类:这是一个抽象类,用于将用户输入的查询字符串封装成Lucene能够识别的Query,它具有TermQuery, BooleanQuery, PrefixQuery等多种实现。 2,Term类:用于描述搜索的基本单位,其构造函数是Term(“fieldName”,”queryWord”),其中第一个参数代表要在文档的哪一个Field上进行搜索,第二个参数代表要搜索的关键词。 3,TermQuery类:TermQuery是抽象类Query的一个具体实现,也是Lucene支持的最为基本的一个查询类。TermQuery的构造函数是TermQuery(new Term(“fieldName”,”queryWord”)),唯一的参数是一个Term对象。 4,IndexSearcher类:用于在建立好的索引上进行搜索的句柄类,其打开索引方式被设置为只读,因此允许多个IndexSearcher实例操作同一个索引。 5,Hits类:搜索结果类。 代码:利用索引搜索文档 package TestLucene; import java.io.File; import org.apache.lucene.document.Document; import org.apache.lucene.index.Term; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.TermQuery; import org.apache.lucene.store.FSDirectory; /** * This class is used to demonstrate the * process of searching on an existing * Lucene index * */ public class TxtFileSearcher { public static void main(String[] args) throws Exception{ String queryStr = "lucene"; //This is the directory that hosts the Lucene index File indexDir = new File("D:\\luceneIndex"); FSDirectory directory = FSDirectory.getDirectory(indexDir,false); IndexSearcher searcher = new IndexSearcher(directory); if(!indexDir.exists()){ System.out.println("The Lucene index is not exist"); return; } Term term = new Term("contents",queryStr.toLowerCase()); TermQuery luceneQuery = new TermQuery(term); Hits hits = searcher.search(luceneQuery); for(int i = 0; i < hits.length(); i++){ Document document = hits.doc(i); System.out.println("File: " + document.get("path")); } } } 在代码中,类IndexSearcher的构造函数接受一个类型为Directory的对象,传入的FSDirctory对象代表索引存储在磁盘上的位置,IndexSearcher实例化后,其以只读方式打开了这个索引。 然后程序构造了一个Term对象,指定要在文档内容中搜索包含关键词“lucene”的文档,程序利用这个Term对象构造出TermQuery对象,并把其传入到IndexSearcher的search方法中进行查询,返回的结果保存在Hits对象中。 最后程序利用循环代码将搜索到的文档路径全部打印出来。 本文来源于金色坐标 http://www.kingxy.com/ , 原文地址:http://www.kingxy.com/archives/88.html 构建各种Lucene Query (一) 2009-11-25 17:41 1 搜索流程中的第二步就是构建一个Query。下面就来介绍Query及其构建。 2 3 当 用户输入一个关键字,搜索引擎接收到后,并不是立刻就将它放入后台开始进行关键字的检索,而应当首先对这个关键字进行一定的分析和处理,使之成为一种后台 可以理解的形式,只有这样,才能提高检索的效率,同时检索出更加有效的结果。那么,在Lucene中,这种处理,其实就是构建一个Query对象。 4 5 就Query对象本身言,它只是Lucene的search包中的一个抽象类,这个抽象类有许多子类,代表了不同类型的检索。如常见的TermQuery就是将一个简单的关键字进行封装后的对象,类似的还有BooleanQuery,即布尔型的查找。 6 7 IndexSearcher对象的search方法中总是需要一个Query对象(或是Query子类的对象),本节就来介绍各种Query类。 8 9 11.4.1 按词条搜索—TermQuery 10 TermQuery是最简单、也是最常用的Query。TermQuery可以理解成为“词条搜索”,在搜索引擎中最基本的搜索就是在索引中搜索某一词条,而TermQuery就是用来完成这项工作的。 11 12 在Lucene中词条是最基本的搜索单位,从本质上来讲一个词条其实就是一个名/值对。只不过这个“名”是字段名,而“值”则表示字段中所包含的某个关键字。 13 14 要使用TermQuery进行搜索首先需要构造一个Term对象,示例代码如下: 15 16 Term aTerm = new Term("contents", "java"); 17 18 然后使用aTerm对象为参数来构造一个TermQuery对象,代码设置如下: 19 20 Query query = new TermQuery(aTerm); 21 22 这样所有在“contents”字段中包含有“java”的文档都会在使用TermQuery进行查询时作为符合查询条件的结果返回。 23 24 下面就通过代码11.4来介绍TermQuery的具体实现过程。 25 26 代码11.4 TermQueryTest.java 27 28 package ch11; 29 30 import org.apache.lucene.analysis.standard.StandardAnalyzer; 31 32 import org.apache.lucene.document.Document; 33 34 import org.apache.lucene.document.Field; 35 36 import org.apache.lucene.index.IndexWriter; 37 38 import org.apache.lucene.index.Term; 39 40 import org.apache.lucene.search.Hits; 41 42 import org.apache.lucene.search.IndexSearcher; 43 44 import org.apache.lucene.search.Query; 45 46 import org.apache.lucene.search.TermQuery; 47 48 49 50 public class TermQueryTest 51 52 { 53 54 public static void main(String[] args) throws Exception 55 56 { 57 58 //生成Document对象 59 60 Document doc1 = new Document(); 61 62 //添加“name”字段的内容 63 64 doc1.add(Field.Text("name", "word1 word2 word3")); 65 66 //添加“title”字段的内容 67 68 doc1.add(Field.Keyword("title", "doc1")); 69 70 //生成索引书写器 71 72 IndexWriter writer = new IndexWriter("c:\\index", new StandardAnalyzer(), true); 73 74 75 76 //将文档添加到索引中 77 78 writer.addDocument(doc1); 79 80 //关闭索引 81 82 writer.close(); 83 84 85 86 //生成查询对象query 87 88 Query query = null; 89 90 91 92 //生成hits结果对象,保存返回的检索结果 93 94 Hits hits = null; 95 96 97 98 //生成检索器 99 100 IndexSearcher searcher = new IndexSearcher("c:\\index"); 101 102 103 104 // 构造一个TermQuery对象 105 106 query = new TermQuery(new Term("name","word1")); 107 108 //开始检索,并返回检索结果到hits中 109 110 hits = searcher.search(query); 111 112 //输出检索结果中的相关信息 113 114 printResult(hits, "word1"); 115 116 117 118 // 再次构造一个TermQuery对象,只不过查询的字段变成了"title" 119 120 query = new TermQuery(new Term("title","doc1")); 121 122 //开始第二次检索,并返回检索结果到hits中 123 124 hits = searcher.search(query); 125 126 //输出检索结果中的相关信息 127 128 printResult(hits, "doc1"); 129 130 131 132 } 133 134 135 136 public static void printResult(Hits hits, String key) throws Exception 137 138 { 139 140 System.out.println("查找 \"" + key + "\" :"); 141 142 if (hits != null) 143 144 { 145 146 if (hits.length() == 0) 147 148 { 149 150 System.out.println("没有找到任何结果"); 151 152 } 153 154 else 155 156 { 157 158 System.out.println("找到" + hits.length() + "个结果"); 159 160 for (int i = 0; i < hits.length(); i++) 161 162 { 163 164 Document d = hits.doc(i); 165 166 String dname = d.get("title"); 167 168 System.out.print(dname + " "); 169 170 } 171 172 System.out.println(); 173 174 System.out.println(); 175 176 } 177 178 } 179 180 } 181 182 } 183 184 在代码11.4中使用TermQuery进行检索的运行结果如图11-8所示。 185 186 注意:字段值是区分大小写的,因此在查询时必须注意大小写的匹配。 187 188 从图11-8中可以看出,代码11.4两次分别以“word1”和“doc1”为关键字进行检索,并且都只得到了一个检索结果。 189 190 在代码11.4中通过构建TermQuery的对象,两次完成了对关键字的查找。两次查找过程中不同的是,第一次构建的TermQuery是查找“name”这个字段,而第二次构建的TermQuery则查找的是“title”这个字段。 191 192 11.4.2 “与或”搜索—BooleanQuery 193 BooleanQuery 也是实际开发过程中经常使用的一种Query。它其实是一个组合的Query,在使用时可以把各种Query对象添加进去并标明它们之间的逻辑关系。在本 节中所讨论的所有查询类型都可以使用BooleanQuery综合起来。BooleanQuery本身来讲是一个布尔子句的容器,它提供了专门的API方 法往其中添加子句,并标明它们之间的关系,以下代码为BooleanQuery提供的用于添加子句的API接口: 194 195 public void add(Query query, boolean required, boolean prohibited); 196 197 注意:BooleanQuery是可以嵌套的,一个BooleanQuery可以成为另一个BooleanQuery的条件子句。 198 199 下面以11.5为例来介绍进行“与”操作的布尔型查询。 200 201 代码11.5 BooleanQueryTest1.java 202 203 package ch11; 204 205 import org.apache.lucene.analysis.standard.StandardAnalyzer; 206 207 import org.apache.lucene.document.Document; 208 209 import org.apache.lucene.document.Field; 210 211 import org.apache.lucene.index.IndexWriter; 212 213 import org.apache.lucene.index.Term; 214 215 import org.apache.lucene.search.BooleanQuery; 216 217 import org.apache.lucene.search.Hits; 218 219 import org.apache.lucene.search.IndexSearcher; 220 221 import org.apache.lucene.search.Query; 222 223 import org.apache.lucene.search.TermQuery; 224 225 226 227 public class BooleanQueryTest1 228 229 { 230 231 public static void main (String [] args) throws Exception { 232 233 //生成新的Document对象 234 235 Document doc1 = new Document(); 236 237 doc1.add(Field.Text("name", "word1 word2 word3")); 238 239 doc1.add(Field.Keyword("title", "doc1")); 240 241 242 243 Document doc2 = new Document(); 244 245 doc2.add(Field.Text("name", "word1 word4 word5")); 246 247 doc2.add(Field.Keyword("title", "doc2")); 248 249 250 251 Document doc3 = new Document(); 252 253 doc3.add(Field.Text("name", "word1 word2 word6")); 254 255 doc3.add(Field.Keyword("title", "doc3")); 256 257 258 259 //生成索引书写器 260 261 IndexWriter writer = new IndexWriter("c:\\index", new StandardAnalyzer(), true); 262 263 //添加到索引中 264 265 writer.addDocument(doc1); 266 267 writer.addDocument(doc2); 268 269 writer.addDocument(doc3); 270 271 writer.close(); 272 273 274 275 Query query1 = null; 276 277 Query query2 = null; 278 279 BooleanQuery query = null; 280 281 Hits hits = null; 282 283 284 285 //生成IndexSearcher对象 286 287 IndexSearcher searcher = new IndexSearcher("c:\\index"); 288 289 290 291 query1 = new TermQuery(new Term("name","word1")); 292 293 query2 = new TermQuery(new Term("name","word2")); 294 295 296 297 // 构造一个布尔查询 298 299 query = new BooleanQuery(); 300 301 302 303 // 添加两个子查询 304 305 query.add(query1, true, false); 306 307 query.add(query2, true, false); 308 309 310 311 hits = searcher.search(query); 312 313 printResult(hits, "word1和word2"); 314 315 316 317 } 318 319 320 321 public static void printResult(Hits hits, String key) throws Exception 322 323 { 324 325 System.out.println("查找 \"" + key + "\" :"); 326 327 if (hits != null) 328 329 { 330 331 if (hits.length() == 0) 332 333 { 334 335 System.out.println("没有找到任何结果"); 336 337 } 338 339 else 340 341 { 342 343 System.out.println("找到" + hits.length() + "个结果"); 344 345 for (int i = 0; i < hits.length(); i++) 346 347 { 348 349 Document d = hits.doc(i); 350 351 String dname = d.get("title"); 352 353 System.out.print(dname + " "); 354 355 } 356 357 System.out.println(); 358 359 System.out.println(); 360 361 } 362 363 } 364 365 } 366 367 } 368 369 代码11.5首先构造了两个TermQuery,然后构造了一个BooleanQuery的对象,并将两个TermQuery当成它的查询子句加入Boolean查询中。 370 371 再来看一下BooleanQuery的add方法,除了它的第一个参数外,它还有另外两个布尔型的参数。第1个参数的意思是当前所加入的查询子句是否必须满足,第2个参数的意思是当前所加入的查询子句是否不需要满足。这样,当这两个参数分别选择true和false时,会有4种不同的组合。 372 373 true &false:表明当前加入的子句是必须要满足的。 374 375 false&true:表明当前加入的子句是不可以被满足的。 376 377 false&false:表明当前加入的子句是可选的。 378 379 true&true:错误的情况。 380 381 由前面的示例可以看出由于加入的两个子句都选用了true&false的组合,因此它们两个都是需要被满足的,也就构成了实际上的“与”关系,运行效果如图11-9所示。 382 383 如果是要进行“或”运算,则可按如下代码来构建查询子句: 384 385 query.add(query1, false, false); 386 387 query.add(query2, false, false); 388 389 代码的运行效果如图11-10所示。 390 391 392 393 图11-9 BooleanQuery测试1 图11-10 BooleanQuery测试2 394 395 由于布尔型的查询是可以嵌套的,因此可以表示多种条件下的组合。不过,如果子句的数目太多,可能会导致查找效率的降低。因此,Lucene给出了一个默认的限制,就是布尔型Query的子句数目不能超过1024。 396 397 11.4.3 在某一范围内搜索—RangeQuery 398 有时用户会需要一种在一个范围内查找某个文档,比如查找某一时间段内的所有文档,此时,Lucene提供了一种名为RangeQuery的类来满足这种需求。 399 400 RangeQuery表示在某范围内的搜索条件,实现从一个开始词条到一个结束词条的搜索功能,在查询时“开始词条”和“结束词条”可以被包含在内也可以不被包含在内。它的具体用法如下: 401 402 RangeQuery query = new RangeQuery(begin, end, included); 403 404 在参数列表中,最后一个boolean值表示是否包含边界条件本身,即当其为TRUE时,表示包含边界值,用字符可以表示为“[begin TO end]”;当其为FALSE时,表示不包含边界值,用字符可以表示为“{begin TO end}”。 IndexSearch类 查询器 搜索入口,继承自Search 1.public IndexSearcher(Directory directory) 使用方法 String IndexPath="D:/IndexPath"; Directory directory=FSDirectory.getDirectory(IndexPath); IndexSearcher searcher=new IndexSearcher(directory); 支持RAM存储的索引,提高检索速度,建议使用,因为此方法将索引存放的路径与搜索分离 2.public IndexSearcher(String path) 直接操作索引目录.不支持RAM存储的索引 IndexSearcher searcher=new IndexSearcher("D:/IndexPath"); 3.public IndexSearcher(IndexReader r) IndexSearcher searcher=IndexSearcher(reader); 4.private IndexSearcher(IndexReader r, boolean closeReader) 在3的基础上对了判断在关闭IndexSearcher时是否要关闭所带的IndexReader对象的boolean类型参数 多索引目录就是要在多个索引目录的中进行比较搜索,类似概念在SQL中就是select * from TableA union select * from TableB。 IndexSearcher[] searchers = new IndexSearcher[2]; searchers[0] = new IndexSearcher(IndexPath0); searchers[1] = new IndexSearcher(IndexPath1); IndexSearcher类的主要方法Search通过重载实现多种检索方式.通过其参数控制检索。 参数解释 Weigth weigth 权重 指定索引中文档重要性参数,改变默认其值 HitCollector results 保存搜索的所有结果. Filter filter 指定对结果进行过滤的方式 Query query 每个Search必须的对象参数.指定检索的方式 Sort sort 指定检索排序的方法.可自定义排序方式进行结果的排序和输出 Query 有很多的子类 指定了不同的查询方式,query是用户输入的内容,analyzer是用来将用户输入的内容也作分析处理 TermQuery Term t=new Term(”contents”,”lucene”);构造TermQuery把查询条件视为一个key,要求和查询内容完全匹配,比如Field.Keyword类型就可以使用TermQuery RangeQuery 区间检索 RangeQuery 表示一个范围的搜索条件,在年龄,日期,工资等数字类的索引库中常用R,angeQuery query = new RangeQuery(begin, end, included);类似sql中betwee...and.....最后一个boolean值表示是否包含边界条件本身,用字符表示为 ”[begin TO end]” 或者”{begin TO end}” PrefixQuery 字符串前缀检索,如"sys*" BooleanQuery逻辑组合检索 组合的Query,你可以把各种Query添加进去并标明他们的逻辑关系,添加条件用public void add(Query query, boolean required, boolean prohibited)方法,后两个boolean变量是 标示AND OR NOT三种关系 字符表示为”AND OR NOT” 或 “+ -”,一个BooleanQuery中可以添加多个Query,如果超过setMaxClauseCount(int)的值(默认1024个)的话,会抛出 TooManyClauses错误. PhraseQuery短语检索 PhraseQuery所以提供了一个setSlop()参数,在查询中,lucene会尝试调整单词的距离和位置,这个参数表示可以接受调整次数限制,如果实际的内容可以在这么多步内调整为完全匹配,那么就被视为匹配.在默认情况下slop的值是0,所以默认是不支持非严格匹配的,通过设置slop参数(比如”red pig”匹配”red fat pig”就需要1个slop来把pig后移动1位),我们可以让lucene来模糊查询.值得注意的是,PhraseQuery不保证前后单词的次序,在上面的例子中,”pig red”需要2个slop,也就是如果slop如果大于等于2,那么”pig red”也会被认为是匹配的. WildcardQuery通配符检索 使用?和*来表示一个或多个字母比如sys*可以匹配system ,systop,systaltic…, FuzzyQuery模糊搜索 一般不处理中文,处理于英文的各种时态变化和复数形式,匹配结果的相关度是不一样的. QueryParser使用 QueryParser将用户输入转为Query或者Query组,将Query的字符表示(Query.toString)转化为实际的Query对象, Hit搜索结果的处理:Hits对象 Hits对象是搜索结果的集合 主要有下面几个方法 1.length() , 记录有多少条结果返回 2.doc(n) 返回第n个记录 3.id(in) 返回第n个记录的Document ID 4.score(n) 第n个记录的相关度(积分) Lucene搜索方法总结 1.多字段搜索 使用multifieldqueryparser可以指定多个搜索字段。 query query = multifieldqueryparser.parse(”name*”, new string[] { fieldname, fieldvalue }, analyzer); indexreader reader = indexreader.open(directory); indexsearcher searcher = new indexsearcher(reader); hits hits = searcher.search(query); 2.多条件搜索 除了使用queryparser.parse分解复杂的搜索语法外,还可以通过组合多个query来达到目的。 query query1 = new termquery(new term(fieldvalue,“name1′)); //词语搜索 query query2 = new wildcardquery(new term(fieldname,“name*”)); //通配符 //query query3 = new prefixquery(new term(fieldname,“name1′)); //字段搜索field:keyword,自动在结尾添加* //query query4 = new rangequery(new term(fieldnumber, numbertools.longtostring(11l)), new term(fieldnumber, numbertools.longtostring(13l)), true); //范围搜索 //query query5 = new filteredquery(query, filter); //带过滤条件的搜索 booleanquery query = new booleanquery(); query.add(query1, booleanclause.occur.must); query.add(query2, booleanclause.occur.must); indexsearcher searcher = new indexsearcher(reader); hits hits = searcher.search(query); 3.过滤 使用filter对搜索结果进行过滤,可以获得更小范围内更精确的结果。 举个例子,我们搜索上架时间在2005-10-1到2005-10-30之间的商品。 对于日期时间,我们需要转换一下才能添加到索引库,同时还必须是索引字段。// index document.add(fielddate, datefield.datetostring(date), field.store.yes, field.index.un_tokenized); //… // search filter filter = new datefilter(fielddate, datetime.parse(”2005-10-1′), datetime.parse(”2005-10-30′)); hits hits = searcher.search(query, filter); 除了日期时间,还可以使用整数。比如搜索价格在100 ~ 200之间的商品。 lucene.net numbertools对于数字进行了补位处理,如果需要使用浮点数可以自己参考源码进行。// index document.add(new field(fieldnumber, numbertools.longtostring((long)price), field.store.yes, field.index.un_tokenized)); //… // search filter filter = new rangefilter(fieldnumber, numbertools.longtostring(100l), numbertools.longtostring(200l), true, true); hits hits = searcher.search(query, filter); 使用query作为过滤条件。queryfilter filter = new queryfilter(queryparser.parse( ”name2′, fieldvalue, analyzer)); 我们还可以使用filteredquery进行多条件过滤。 filter filter = new datefilter(fielddate, datetime.parse(”2005-10-10′), datetime.parse(”2005-10-15′)); filter filter2 = new rangefilter(fieldnumber, numbertools.longtostring(11l), numbertools.longtostring(13l), true, true); query query = queryparser.parse(”name*”, fieldname, analyzer); query = new filteredquery(query, filter); query = new filteredquery(query, filter2); indexsearcher searcher = new indexsearcher(reader); hits hits = searcher.search(query); 4.分布搜索 我们可以使用multireader或multisearcher搜索多个索引库。 multireader reader = new multireader(new indexreader[] { indexreader.open(@”c:\index”), indexreader.open(@”\\server\index”) }); indexsearcher searcher = new indexsearcher(reader); hits hits = searcher.search(query); 或 indexsearcher searcher1 = new indexsearcher(reader1); indexsearcher searcher2 = new indexsearcher(reader2); multisearcher searcher = new multisearcher(new searchable[] { searcher1, searcher2 }); hits hits = searcher.search(query); 还可以使用parallelmultisearcher进行多线程并行搜索。 5.显示搜索语法字符串 我们组合了很多种搜索条件,或许想看看与其对等的搜索语法串是什么样的。 booleanquery query = new booleanquery(); query.add(query1, true, false); query.add(query2, true, false); //… console.writeline(”syntax: {0}”, query.tostring()); 输出: syntax: +(name:name* value:name*) +number:[0000000000000000b to 0000000000000000d] 呵呵,就这么简单。 6.如何删除索引 lucene提供了两种从索引中删除document的方法,一种是 void deleteDocument(int docNum) 这种方法是根据document在索引中的编号来删除,每个document加进索引后都会有个唯一编号,所以根据编号删除是一种精确删除,但是这个编号是索引的内部结构,一般我们不会知道某个文件的编号到底是几,所以用处不大。另一种是 void deleteDocuments(Term term) 这种方法实际上是首先根据参数term执行一个搜索操作,然后把搜索到的结果批量删除了。我们可以通过这个方法提供一个严格的查询条件,达到删除指定document的目的。 下面给出一个例子: Directory dir = FSDirectory.getDirectory(PATH, false); IndexReader reader = IndexReader.open(dir); Term term = new Term(field, key); reader.deleteDocuments(term); reader.close(); ms还有操作 deleteDocuments(Term); deleteDocuments(Term[]); deleteDocuments(Query); deleteDocuments(Query[]); 7.如何更新索引 注:据多人反应,新版本的lucene以及提供了更新索引的方法。 writer.updateDocument(doc); ————————————————————javaeye分割线—————————————— lucene并没有提供专门的索引更新方法,我们需要先将相应的document删除,然后再将新的document加入索引。例如: Directory dir = FSDirectory.getDirectory(PATH, false); IndexReader reader = IndexReader.open(dir); Term term = new Term(“title”, “lucene introduction”); reader.deleteDocuments(term); reader.close(); IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(), true); Document doc = new Document(); doc.add(new Field("title", "lucene introduction", Field.Store.YES, Field.Index.TOKENIZED)); doc.add(new Field("content", "lucene is funny", Field.Store.YES, Field.Index.TOKENIZED)); writer.addDocument(doc); writer.optimize(); writer.close(); 8.多样化的搜索 /** ***一个关键字,对一个字段进行查询**** */ QueryParser qp = new QueryParser("content",analyzer); query = qp.parse(keyword); Hits hits = searcher.search(query); /** ***模糊查询**** */ Term term = new Term("content",keyword); FuzzyQuery fq = new FuzzyQuery(term); Hits hits = searcher.search(fq); /** ***一个关键字,在两个字段中查询**** */ /* * 1.BooleanClause.Occur[]的三种类型:MUST : + and MUST_NOT : - not SHOULD : or * 2.下面查询的意思是:content中必须包含该关键字,而title有没有都无所谓 * 3.下面的这个查询中,Occur[]的长度必须和Fields[]的长度一致。每个限制条件对应一个字段 */ BooleanClause.Occur[] flags = new BooleanClause.Occur[]{BooleanClause.Occur.SHOULD,BooleanClause.Occur.MUST}; query=MultiFieldQueryParser.parse(keyword,new String[]{"title","content"},flags,analyzer); /** ***两个(多个)关键字对两个(多个)字段进行查询,默认匹配规则**** */ /* * 1.关键字的个数必须和字段的个数相等 * 2.由于没有指定匹配规定,默认为"SHOULD"因此,下面查询的意思是:"title"中含有keyword1或"content"含有keyword2. *在此例中,把keyword1和keyword2相同 */ query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new String[]{"title","content"},analyzer); /** ***两个(多个)关键字对两个(多个)字段进行查询,手工指定匹配规则**** */ /* * 1.必须 关键字的个数==字段名的个数==匹配规则的个数 * 2.下面查询的意思是:"title"必须不含有keyword1,并且"content"中必须含有keyword2 */ BooleanClause.Occur[] flags = new BooleanClause.Occur[]{BooleanClause.Occur.MUST_NOT,BooleanClause.Occur.MUST}; query=MultiFieldQueryParser.parse(new String[]{keyword,keyword},new String[]{"title","content"},flags,analyzer); /** ***对日期型字段进行查询**** */ /** ***对数字范围进行查询**** */ /* * 1.两个条件必须是同一个字段 * 2.前面一个条件必须比后面一个条件小,否则找不到数据 * 3.new RangeQuery中的第三个参数,表示是否包含"=" true: >=或<= false: >或< * 4.找出55>=id>=53 or 60>=id>=57: */ Term lowerTerm1 = new Term("id","53"); Term upperTerm1 = new Term("id","55"); RangeQuery rq1 = new RangeQuery(lowerTerm1,upperTerm1,true); Term lowerTerm2 = new Term("id","57"); Term upperTerm2 = new Term("id","60"); RangeQuery rq2 = new RangeQuery(lowerTerm2,upperTerm2,true); BooleanQuery bq = new BooleanQuery(); bq.add(rq1,BooleanClause.Occur.SHOULD); bq.add(rq2,BooleanClause.Occur.SHOULD); Hits hits = searcher.search(bq); 9.结果排序 排序的关键点有两个: 1:首先你要排序的字段必须是被index的,并且是untokenized的。 如: doc.add(new Field("click", dv.get("click").toString(), Field.Store.NO, Field.Index.UN_TOKENIZED)); 2:在检索时候: 如: /***** 排序 *****/ /* * 1.被排序的字段必须被索引过(Indexecd),在索引时不能 用Field.Index.TOKENIZED * (用UN_TOKENIZED可以正常实现.用NO时查询正常,但排序不能正常设置升降序) * 2.SortField类型 * SCORE、DOC、AUTO、STRING、INT、FLOAT、CUSTOM此类型主要是根据字段的类型选择 * 3.SortField的第三个参数代表是否是降序true:降序 false:升序 */ Sort sort = new Sort(new SortField[]{new SortField("click", SortField.INT, true)}); Hits hits = searcher.search(querystring,sort); /* *按日期排序 */ Sort sort = new Sort(new SortField[]{new SortField("createTime", SortField.INT, false)}); /***** 过滤器******/ QueryParser qp1 = new QueryParser("content",analyzer); Query fquery = qp1.parse("我"); BooleanQuery bqf = new BooleanQuery(); bqf.add(fquery,BooleanClause.Occur.SHOULD); QueryFilter qf = new QueryFilter(bqf); Hits hits = searcher.search(query); 10.将小索引文件合并到大的索引文件中去(此方法性能不佳) /**将小索引文件合并到大的索引文件中去 * @param from 将要合并到to文件的文件 * @param to 将from文件合并到该文件 * @param analyzer */ private void mergeIndex(File from,File to,Analyzer analyzer) { IndexWriter indexWriter = null; try{ System.out.println("正在合并索引文件!\t"); indexWriter = new IndexWriter(to,analyzer, false); indexWriter.setMergeFactor(100000); indexWriter.setMaxFieldLength(Integer.MAX_VALUE); indexWriter.setMaxBufferedDocs(Integer.MAX_VALUE); indexWriter.setMaxMergeDocs(Integer.MAX_VALUE); FSDirectory[] fs = {FSDirectory.getDirectory(from,false)}; indexWriter.addIndexes(fs); indexWriter.optimize(); indexWriter.close(); System.out.println("已完成合并!\t"); } catch(Exception e) { Utility.writeLog("合并索引文件出错!mergeIndex()"+e.getMessage(),""); } finally { try{ if(indexWriter!=null) indexWriter.close(); } catch(Exception e ){ } } } 合并时间是从每天的凌晨3点钟开始,一直到早上9点左右,足足用5个小时才合并完成,其中大索引文件大小为4G,小索引为10MB. 11.问题2:单字共现频率的局部统计的原理 解答: 高频字串统计的理论基础是N -元模型。 设W1 W2 ...WN 是长度为N 的字串,则字串W 的似然度为 p ( W) = p ( w i | w1 w2 ...w i - 1) (1) 上面公式的意义反映连续个N 字之间的结合程度,如果若干种不同的历史组合W1 W2 ...WN的最后N - 1 个字相同,就把它们都看作一类。在这一假设下,每一个字出现的概率不再与前面的历史有关,只与最近的N - 1 个字相关,字串的先验概率为 p ( W) = p ( w i - ( n - 1) w i - ( n - 2) ...w i - 1) (2) 当p ( W) 超过一定的阈值时,说明这N 个字的结合能力较强,我们就可以认为该字串能被看成一个“词”。 正是根据以上所说原理,预先对待分词文本每个单字进行出现次数统计并记录它们在文中出现的位置(存储方式如附件图例所示),预处理后我们遍历单字频次统计 列表出现次数大于2的所有单字在文中出现的位置i,判断位置i+1的单字出现次数是否也大于2,若是则判断位置i+2的单字出现次数是否也大于2,如此类 推直至位置i+n+1的单字出现次数小于2,获得候选词组 w(i,i+1...i+n)并放入候选词汇集合,最后对候选词汇集合进行前缀后缀处理获得合适的高频词汇集合result 12.索引合并 writer.addIndexes(indexDirs); Lucene多字段搜索 最近在学习Lucene的过程中遇到了需要多域搜索并排序的问题,在网上找了找,资料不是很多,现在都列出来,又需要的可以自己认真看看,都是从其他网站粘贴过来的,所以比较乱,感谢原创的作者们! 使用MultiFieldQueryParser类即可。 示例代码: package com.lucene.search; 网管网bitsCN.com import java.io.File; import java.io.IOException; 54com.cn import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; public class Searcher { feedom.net public static void main(String[] args) throws Exception { File indexDir = new File("C:\\target\\index\\book"); if (!indexDir.exists() || !indexDir.isDirectory()) { throw new IOException(); } search(indexDir); } public static void search(File indexDir) throws Exception { Directory fsDir = FSDirectory.getDirectory(indexDir); IndexSearcher searcher = new IndexSearcher(fsDir); String[] queries = { "中文版", "8*" }; String[] fields = { "name", "isbn" }; BooleanClause.Occur[] clauses = { BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD }; Query query = MultiFieldQueryParser.parse(queries, fields, clauses, new StandardAnalyzer()); Hits hits = searcher.search(query); System.out.println("共有" + searcher.maxDoc() + "条索引,命中" + hits.length() + "条"); for (int i = 0; i < hits.length(); i++) { int DocId = hits.id(i); String DocName = hits.doc(i).get("name"); String DocIsbn = hits.doc(i).get("isbn"); String DocPblDt = hits.doc(i).get("pbl_dt"); System.out.println(DocId + ":" + DocName + " ISBN:" + DocIsbn + " PBLDT:" + DocPblDt); } } } package com.lucene.search; import java.io.File; import java.io.IOException; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; public class Searcher { public static void main(String[] args) throws Exception { File indexDir = new File("C:\\target\\index\\book"); if (!indexDir.exists() || !indexDir.isDirectory()) { throw new IOException(); } search(indexDir); } public static void search(File indexDir) throws Exception { Directory fsDir = FSDirectory.getDirectory(indexDir); IndexSearcher searcher = new IndexSearcher(fsDir); String[] queries = { "中文版", "8*" }; String[] fields = { "name", "isbn" }; BooleanClause.Occur[] clauses = { BooleanClause.Occur.SHOULD, BooleanClause.Occur.SHOULD }; Query query = MultiFieldQueryParser.parse(queries, fields, clauses, new StandardAnalyzer()); Hits hits = searcher.search(query); System.out.println("共有" + searcher.maxDoc() + "条索引,命中" + hits.length() + "条"); for (int i = 0; i < hits.length(); i++) { int DocId = hits.id(i); String DocName = hits.doc(i).get("name"); String DocIsbn = hits.doc(i).get("isbn"); String DocPblDt = hits.doc(i).get("pbl_dt"); System.out.println(DocId + ":" + DocName + " ISBN:" + DocIsbn + " PBLDT:" + DocPblDt); } } }注意:BooleanClause.Occur[]数组,它表示多个条件之间的关系: BooleanClause.Occur.MUST表示and, feedom.net BooleanClause.Occur.MUST_NOT表示not, 54com.cn BooleanClause.Occur.SHOULD表示or. --------------------------------------------------------------------------------------------------------- 多个关键字直接的关系是或,所以直接使用多域搜索对象查询出来的结果就是这样。 更灵活的控制方式为: BooleanQuery booleanQuery = new BooleanQuery(); QueryParser parser = new QueryParser("title",分词器); Query titleQuery = parser .parser("中国人民共和国"); booleanQuery.add(titleQuery,....SHOULD); QueryParser parser = new QueryParser("content",分词器); Query contentQuery = parser .parser("中国人民共和国"); booleanQuery.add(contentQuery ,....SHOULD); -------------------------------------------------------------------------------------------------- package com.lucene.search; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.queryParser.MultiFieldQueryParser; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.MultiSearcher; import org.apache.lucene.search.Query; public class Multisearcher { private static String INDEX_STORE_PATH1 = "C:\\multi\\1"; private static String INDEX_STORE_PATH2 = "C:\\multi\\2"; public static void main(String[] args) throws Exception { Multisearcher.multisearcher(); } public static void multisearcher() throws Exception { IndexWriter writer = new IndexWriter(INDEX_STORE_PATH1, new StandardAnalyzer(), true); writer.setUseCompoundFile(false); Document doc1 = new Document(); Field f1 = new Field("bookname", "钢铁是怎样炼成的", Field.Store.YES, Field.Index.TOKENIZED); Field f11 = new Field("price", "20.5", Field.Store.YES, Field.Index.UN_TOKENIZED); doc1.add(f1); doc1.add(f11); Document doc2 = new Document(); Field f2 = new Field("bookname", "钢铁战士", Field.Store.YES, Field.Index.TOKENIZED); Field f22 = new Field("price", "18.4", Field.Store.YES, Field.Index.UN_TOKENIZED); doc2.add(f2); doc2.add(f22); Document doc3 = new Document(); Field f3 = new Field("bookname", "钢和铁是两种不同的元素", Field.Store.YES, Field.Index.TOKENIZED); Field f33 = new Field("price", "7.6", Field.Store.YES, Field.Index.UN_TOKENIZED); doc3.add(f3); doc3.add(f33); writer.addDocument(doc1); writer.addDocument(doc2); writer.addDocument(doc3); writer.close(); //创建第二个索引器; IndexWriter writer2 = new IndexWriter(INDEX_STORE_PATH2, new StandardAnalyzer(), true); writer2.setUseCompoundFile(false); Document doc4 = new Document(); Field f4 = new Field("bookname", "钢要比铁有更多的元素", Field.Store.YES, Field.Index.TOKENIZED); Field f44 = new Field("price", "22.5", Field.Store.YES, Field.Index.UN_TOKENIZED); doc4.add(f4); doc4.add(f44); Document doc5 = new Document(); Field f5 = new Field("bookname", "钢和铁是两种重要的金属", Field.Store.YES, Field.Index.TOKENIZED); Field f55 = new Field("price", "15.9", Field.Store.YES, Field.Index.UN_TOKENIZED); doc5.add(f5); doc5.add(f55); Document doc6 = new Document(); Field f6 = new Field("bookname", "钢铁是两种重要的金属", Field.Store.YES, Field.Index.TOKENIZED); Field f66 = new Field("price", "19.00", Field.Store.YES, Field.Index.UN_TOKENIZED); doc6.add(f6); doc6.add(f66); writer2.addDocument(doc4); writer2.addDocument(doc5); writer2.addDocument(doc6); writer2.close(); String query1 = "钢"; String query2 = "[10 TO 20]";//注意格式:中括号还有关键字TO是大写的 String[] queries = { query1, query2 }; //指定两个域 Field String field1 = "bookname"; String field2 = "price"; String[] fields = { field1, field2 }; //指定查询字句之间的关系 BooleanClause.Occur[] clauses = { BooleanClause.Occur.MUST, BooleanClause.Occur.MUST }; //转成多域查询 MultiFieldQuery Query q = MultiFieldQueryParser.parse(queries, fields, clauses, new StandardAnalyzer()); //打印Query的内容 System.out.println(q.toString()); //创建两个IndexSearcher,以实现在多个索引目录进行查询 IndexSearcher searcher1 = new IndexSearcher(INDEX_STORE_PATH1); IndexSearcher searcher2 = new IndexSearcher(INDEX_STORE_PATH2); IndexSearcher[] searchers = { searcher1, searcher2 }; //使用MultiSearcher进行多域搜索 MultiSearcher searcher = new MultiSearcher(searchers); Hits hits = searcher.search(q); for (int i = 0; i < hits.length(); i++) { System.out.println(hits.doc(i)); } } } ------------------------------------------------------------------------------------------------------------------------------------------ 默认情况下,IndexSearcher类的search方法返回查询结果时,是按文档的分值排序的,可以使用重载的search方法对结果排序 IndexSearcher.search(Query,Sort); new Sort() 和 Sort.RELEVANCE,以及null一样,采用默认排序,要定义排序字段,方法是将字段传入Sort对象 Sort sort = new Sort(String field); 也可以对多个字段排序Sort sort = new Sort(String[] fields); 例: Sort sort = new Sort(new SortField[]{new SortField(“title”),new SortField(“name”)}); Hits hits=searcher.search(query,Sort); 多字段查找MultiFieldQueryParser 只在某些Term中查找,不关心在哪个字段 Query query = new MultiFieldQueryParser.parse(“word”,new String[]{“title”,”content”},analyzer); //在title和content中找word 多字段时默认是OR关系,要改变它,使用以下方法: Query query = MultiFieldQueryParser.parse(“word”,new String[]{“title”,”content”},new int[]{MultiFieldQueryParser.REQUIRED_FIELD,MultiFieldQueryParser.PROHIBITED_FIELD},analyzer); 其中: REQUIRED_FIELD 表示该条件必须有 PROHIBITED_FIELD 表示必须不含 搜索多个索引文件MultiSearcher 1) 建立多个索引:使用不同的索引目录,实例化不同的IndexWriter 2) 建立多索引搜索器: Searcher[] searchers = new SEARCHER[2]; Searchers[0] = new IndexSearcher(dir1); //搜索索引目录一 Searchers[1]= new IndexSearcher(dir2);//搜索索引目录二 Searcher searcher = new MultiSearcher(serarchers); 3) 开始查询:Hits hits = searcher.search(query); --------------------------------------------------------------------------------------------------------------------------------------- BooleanQuery typeNegativeSearch = new BooleanQuery(); QueryParser parser = new QueryParser("contents", new Analyzer()); parser.setDefaultOperator(QueryParser.AND_OPERATOR); query = parser.parse(queryString); QueryParser parser2 = new QueryParser("adISELL", new Analyzer()); query2 = parser2.parse("\"2\""); QueryParser parser3 = new QueryParser("adISELL", new Analyzer()); query3 = parser3.parse("\"2\""); QueryParser parser4 = new QueryParser("adISELL", new Analyzer()); query4 = parser4.parse("\"2\""); QueryParser parser4 = new QueryParser("adISELL", new Analyzer()); query4 = parser4.parse("\"2\""); 。。。。 QueryParser parser..n = new QueryParser("adISELL", new Analyzer()); query..n = parser..n.parse("\"2\""); typeNegativeSearch.add(query,Occur.MUST); typeNegativeSearch.add(query2,Occur.MUST); typeNegativeSearch.add(query3,Occur.MUST); typeNegativeSearch.add(query4,Occur.MUST); ..... typeNegativeSearch.add(query..n,Occur.MUST); hits = searcher.search(typeNegativeSearch); 1, 几种span的querySpanTermQuery:检索效果完全同TermQuery,但内部会记录一些位置信息 ,供SpanQuery的其它API使用,是其它属于SpanQuery的Query的基础。 SpanFirstQuery:查找方式为从Field的内容起始位置开始,在一个固定的宽度内查找所指定的 词条。 SpanNearQuery:功能类似PharaseQuery。SpanNearQuery查找所匹配的不一定是短语,还有可 能是另一个SpanQuery的查询结果作为整体考虑,进行嵌套查询。 SpanOrQuery:把所有SpanQuery查询结果综合起来,作为检索结果。 SpanNotQuery:从第一个SpanQuery查询结果中,去掉第二个SpanQuery查询结果,作为检索结 果。 2, 多条件索引关系 BooleanClause用于表示布尔查询子句关系的类,包括:BooleanClause.Occur.MUST, BooleanClause.Occur.MUST_NOT,BooleanClause.Occur.SHOULD。有以下6种组合: 1.MUST和MUST:取得连个查询子句的交集。 2.MUST和MUST_NOT:表示查询结果中不能包含MUST_NOT所对应得查询子句的检索结果。 3.MUST_NOT和MUST_NOT:无意义,检索无结果。 4.SHOULD与MUST、SHOULD与MUST_NOT:SHOULD与MUST连用时,无意义,结果为MUST子句的检索 结果。与MUST_NOT连用时,功能同MUST。 5.SHOULD与SHOULD:表示“或”关系,最终检索结果为所有检索子句的并集。 关于IndexSearcher检索器。 在学习IndexSearcher检索器之前,先大致了解一下下面几项: 1、首先,要知道Weight(接口)存在的目的: 使得检索不改变一个Query,使得Query可以重用。所以就出现了Weight,一个Weight可以保存与某次检索相关的IndexSearcher检索器的独立状态值。其实Weight间接保存了IndexSearcher索引器的独立状态信息。 每次检索,即初始化一个IndexSearcher检索器,都需要一个Query,例如 Query query = new TermQuery(term); Hits hits = searcher.search(query); 而Query抽象了用户的检索意向信息,可以使用Query的public Query rewrite(IndexReader reader)方法来实现对先前的检索意向信息的修改(重写)。 用户的一次检索,是与一个Weight对应的,当然可以不保存本次检索相关的IndexSearcher检索器的状态信息到一个Weight中,这样的坏处就是Query不能重用,每次都要重新实例化一个。 Weight接口定义了如下的内容: public interface Weight extends java.io.Serializable { Query getQuery(); // 通过一个Weight可以获取到一个Query实例 float getValue(); // Weight相关的Query的权重值 float sumOfSquaredWeights() throws IOException; // 一个Query可以有很多子句(比如一个BooleanQuery可以包含多个TermQuery子句),获取到所有子句的权重值的平方 void normalize(float norm); // 指派查询的标准化因子 Scorer scorer(IndexReader reader) throws IOException; // 根据一个IndexReader,通过Weight获取得分 Explanation explain(IndexReader reader, int doc) throws IOException; // 为编号为doc的Document设置计算得分的描述信息 } 2、其次,知道Sort类是为一次检索设定排序方式的。 这些排序的方式是在SortField类中定义的,一共定义了7种,当然包括客户化定制排序方式。 3、再次,知道Explanation类是关于某次检索中,封装了对某个Document的得分计算的描述。 4、接着,知道TopDocs类是关于某次实际的检索出来结果集的信息,包括Hits数量,及其最大得分的信息。TopDocs的子类TopFieldDocs类指定了排序方式(Sort),为Fields进行排序。 5、然后,知道FieldSelector是一个筛选器接口,将某个Document中的满足接受条件的Field返回。在FieldSelector中定义了FieldSelectorResult accept(String fieldName);方法。 6、最后,理解TopDocCollector类的用于IndexSearcher的目的。其实TopDocCollector内部定义了一个collect()方法,该方法可以实现根据Document的得分来排序。TopDocCollector类继承自HitCollector,而HitCollector抽象类定义了实现查询(queries)、排序(sorting)、过滤(filtering)的功能。 现在,可以通过IndexSearcher索引器的源代码来解读它具有哪些功能。其实已经很容易读了,在理解上面6项的基础上。IndexSearcher的源代码实现如下所示: package org.apache.lucene.search; import org.apache.lucene.document.Document; import org.apache.lucene.document.FieldSelector; import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.Term; import org.apache.lucene.store.Directory; import java.io.IOException; import java.util.BitSet; // IndexSearcher继承自Searcher抽象类,在Searcher抽象类中定义了一些search()方法,返回Hits。 public class IndexSearcher extends Searcher { IndexReader reader; private boolean closeReader; // 实例化一个IndexSearcher检索器 public IndexSearcher(String path) throws CorruptIndexException, IOException { this(IndexReader.open(path), true); } public IndexSearcher(Directory directory) throws CorruptIndexException, IOException { this(IndexReader.open(directory), true); } public IndexSearcher(IndexReader r) { this(r, false); } private IndexSearcher(IndexReader r, boolean closeReader) { reader = r; this.closeReader = closeReader; } public IndexReader getIndexReader() { return reader; } // 一个检索器与一个IndexReader是密切相关的 public void close() throws IOException { if(closeReader) reader.close(); } // 获取包含词条term的Document的数量 public int docFreq(Term term) throws IOException { return reader.docFreq(term); } // 获取编号为i的Document public Document doc(int i) throws CorruptIndexException, IOException { return reader.document(i); } // 指定了一个筛选器FieldSelector(该筛选器要接受满足条件的某个Document中的Field,将不满足的过滤掉) public Document doc(int i, FieldSelector fieldSelector) throws CorruptIndexException, IOException { return reader.document(i, fieldSelector); } // 检索得到的最大可能的Document的数量 + 1 public int maxDoc() throws IOException { return reader.maxDoc(); } // 查询的核心方法,返回TopDocs,参数指定Weight、Filter、返回Document的数量 public TopDocs search(Weight weight, Filter filter, final int nDocs) throws IOException { if (nDocs <= 0) throw new IllegalArgumentException("nDocs must be > 0"); TopDocCollector collector = new TopDocCollector(nDocs); search(weight, filter, collector); return collector.topDocs(); } // 查询的方法,返回TopFieldDocs public TopFieldDocs search(Weight weight, Filter filter, final int nDocs, Sort sort) throws IOException { TopFieldDocCollector collector = new TopFieldDocCollector(reader, sort, nDocs); search(weight, filter, collector); return (TopFieldDocs)collector.topDocs(); } // 返回值是void,实际检索的结果集存放在HitCollector中 public void search(Weight weight, Filter filter, final HitCollector results) throws IOException { HitCollector collector = results; if (filter != null) { // Filter不为null的时候才执行下面代码 final BitSet bits = filter.bits(reader); collector = new HitCollector() { public final void collect(int doc, float score) { if (bits.get(doc)) { results.collect(doc, score); } } }; } Scorer scorer = weight.scorer(reader); if (scorer == null) return; scorer.score(collector); } // 在先前创建Query并执行检索的基础上,重新改写这个Query,而不是重新实例化一个Query public Query rewrite(Query original) throws IOException { Query query = original; for (Query rewrittenQuery = query.rewrite(reader); rewrittenQuery != query; rewrittenQuery = query.rewrite(reader)) { query = rewrittenQuery; } return query; } public Explanation explain(Weight weight, int doc) throws IOException { return weight.explain(reader, doc); } } 在检索的时候,首先就是要实例化一个IndexSearcher检索器,而这个过程其实就是使用IndexReader打开一个索引目录。 然后通过提交的Query,就可以使用IndexSearcher的search()方法进行检索了。 从IndexSearcher的源代码来看,每个search()方法都需要一个Query实例。因为只有用户提交查询(根据提交的关键字构造一个Query),才能执行检索。也就是说,在检索中Query是非常重要的。实际上Query对于检索的实现具有很大的灵活性,主要是通过Query抽象类的炉体子类的实现来体现的。

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 5 金币 [ 分享文档获得金币 ] 1 人已下载

下载文档