1 package junit;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.text.ParseException;
6 import java.util.ArrayList;
7 import java.util.List;
8
9 import org.apache.commons.lang.math.NumberUtils;
10 import org.apache.lucene.document.Document;
11 import org.apache.lucene.document.Field;
12 import org.apache.lucene.document.NumericField;
13 import org.apache.lucene.index.IndexReader;
14 import org.apache.lucene.index.Term;
15 import org.apache.lucene.queryParser.MultiFieldQueryParser;
16 import org.apache.lucene.search.BooleanClause;
17 import org.apache.lucene.search.BooleanQuery;
18 import org.apache.lucene.search.Filter;
19 import org.apache.lucene.search.FuzzyQuery;
20 import org.apache.lucene.search.IndexSearcher;
21 import org.apache.lucene.search.MultiPhraseQuery;
22 import org.apache.lucene.search.NumericRangeFilter;
23 import org.apache.lucene.search.PhraseQuery;
24 import org.apache.lucene.search.PrefixQuery;
25 import org.apache.lucene.search.Query;
26 import org.apache.lucene.search.ScoreDoc;
27 import org.apache.lucene.search.TermQuery;
28 import org.apache.lucene.search.TermRangeQuery;
29 import org.apache.lucene.search.TopDocs;
30 import org.apache.lucene.search.WildcardQuery;
31 import org.apache.lucene.search.highlight.Formatter;
32 import org.apache.lucene.search.highlight.Fragmenter;
33 import org.apache.lucene.search.highlight.Highlighter;
34 import org.apache.lucene.search.highlight.QueryScorer;
35 import org.apache.lucene.search.highlight.SimpleFragmenter;
36 import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
37 import org.apache.lucene.search.regex.RegexQuery;
38 import org.apache.lucene.store.FSDirectory;
39 import org.apache.lucene.util.Version;
40 import org.junit.Test;
41 import org.wltea.analyzer.lucene.IKAnalyzer;
42
43 import com.ljq.entity.Person;
44 import com.ljq.utils.Consts;
45 import com.ljq.utils.DateUtils;
46 import com.ljq.utils.LuceneUtil;
47 import com.ljq.utils.XMLPropertyConfig;
48
49 /**
50 * Lucene搜索方式大合集<br/><br/>
51 *
52 * Lucene搜索种类很多。这里就介绍几个最常用的。其中TermQuery\BooleanQuery\RegexQuery功能最强大,最为常用。
53 *
54 * @author 林计钦
55 * @version 1.0 2013-6-7 上午09:34:08
56 */
57 public class IndexQueryTest {
58
59 /**
60 * 词条搜索(单个关键字查找)<br/><br/>
61 *
62 * 主要对象是TermQuery,调用方式如下:<br/>
63 * Term term=new Term(字段名, 搜索关键字);<br/>
64 * Query query=new TermQuery(term);<br/>
65 * Hits hits=searcher.search(query);<br/>
66 * @throws Exception
67 */
68 @Test
69 public void termQuery() throws Exception {
70 IndexReader reader = IndexReader.open(FSDirectory.open(new File(XMLPropertyConfig.getConfigXML().getString("index_path"))), true);
71 IndexSearcher searcher = new IndexSearcher(reader);
72
73 //Term term=new Term("ids", "1");
74 //Term term=new Term("ages", "20");
75 //Term term=new Term("birthdays", "2008-06-12");
76 //Term term=new Term("name", "张三");
77 Term term=new Term("city", "厦门");
78
79 Query query=new TermQuery(term);
80 TopDocs topDocs=searcher.search(query, 1000);
81 System.out.println("共检索出 " + topDocs.totalHits + " 条记录");
82 System.out.println();
83
84 ScoreDoc[] scoreDocs = topDocs.scoreDocs;
85 for (ScoreDoc scDoc : scoreDocs) {
86 Document document = searcher.doc(scDoc.doc);
87 String id = document.get("id");
88 String name = document.get("name");
89 String age = document.get("age");
90 String city = document.get("city");
91 String birthday = document.get("birthday");
92 float score = scDoc.score; //相似度
93
94 System.out.println(String.format("id:%s, name:%s, age:%s, city:%s, birthday:%s, 相关度:%s.",
95 id, name, age, city, DateUtils.longToString(Long.parseLong(birthday), Consts.FORMAT_SHORT), score));
96 }
97
98 searcher.close();
99 reader.close();
100 }
101
102 /**
103 * 组合搜索(允许多个关键字组合搜索)<br/><br/>
104 *
105 * 主要对象是BooleanQuery,调用方式如下:<br/>
106 * Term term1=new Term(字段名, 搜索关键字);<br/>
107 * TermQuery query1=new TermQuery(term1);<br/><br/>
108 *
109 * Term term2=new Term(字段名, 搜索关键字);<br/>
110 * TermQuery query2=new TermQuery(term2);<br/><br/>
111 *
112 * BooleanQuery booleanQuery=new BooleanQuery();<br/>
113 * booleanQuery.add(query1, 参数);<br/>
114 * booleanQuery.add(query2, 参数);<br/><br/>
115 *
116 * Hits hits=searcher.search(booleanquery);<br/>
117 * 此方法中的核心在BooleanQuery的add方法上,其第二个参数有三个可选值,对应着逻辑上的与或非关系。<br/><br/>
118 *
119 * 参数如下:<br/>
120 * BooleanClause.Occur.MUST:必须包含,类似于逻辑运算的与<br/>
121 * BooleanClause.Occur.MUST_NOT:必须不包含,类似于逻辑运算的非<br/>
122 * BooleanClause.Occur.SHOULD:可以包含,类似于逻辑运算的或<br/>
123 * 这三者组合,妙用无穷。<br/>
124 * @throws Exception
125 */
126 @Test
127 public void booleanQuery() throws Exception {
128 IndexReader reader = IndexReader.open(FSDirectory.open(new File(XMLPropertyConfig.getConfigXML().getString("index_path"))), true);
129 IndexSearcher searcher = new IndexSearcher(reader);
130
131 //组合条件:
132 //年龄(或):10、20、30、40
133 //名字(与): 四
134 //城市(非): 莆田
135 TermQuery ageQuery10=new TermQuery(new Term("ages", "10"));
136 TermQuery ageQuery20=new TermQuery(new Term("ages", "20"));
137 TermQuery ageQuery30=new TermQuery(new Term("ages", "30"));
138 TermQuery ageQuery40=new TermQuery(new Term("ages", "40"));
139
140 TermQuery nameQuery=new TermQuery(new Term("name", "四"));
141
142 TermQuery cityQuery=new TermQuery(new Term("city", "莆田"));
143
144 BooleanQuery booleanQuery=new BooleanQuery();
145 booleanQuery.add(ageQuery10, BooleanClause.Occur.SHOULD);
146 booleanQuery.add(ageQuery20, BooleanClause.Occur.SHOULD);
147 booleanQuery.add(ageQuery30, BooleanClause.Occur.SHOULD);
148 booleanQuery.add(ageQuery40, BooleanClause.Occur.SHOULD);
149 booleanQuery.add(nameQuery, BooleanClause.Occur.MUST);
150 booleanQuery.add(cityQuery, BooleanClause.Occur.MUST_NOT);
151
152 TopDocs topDocs=searcher.search(booleanQuery, 1000);
153 System.out.println("共检索出 " + topDocs.totalHits + " 条记录");
154 System.out.println();
155
156 ScoreDoc[] scoreDocs = topDocs.scoreDocs;
157 for (ScoreDoc scDoc : scoreDocs) {
158 Document document = searcher.doc(scDoc.doc);
159 String id = document.get("id");
160 String name = document.get("name");
161 String age = document.get("age");
162 String city = document.get("city");
163 String birthday = document.get("birthday");
164 float score = scDoc.score; //相似度
165
166 System.out.println(String.format("id:%s, name:%s, age:%s, city:%s, birthday:%s, 相关度:%s.",
167 id, name, age, city, DateUtils.longToString(Long.parseLong(birthday), Consts.FORMAT_SHORT), score));
168 }
169
170 searcher.close();
171 reader.close();
172 }
173
174 /**
175 * 范围搜索(允许搜索指定范围内的关键字结果)<br/><br/>
176 *
177 * 主要对象是TermRangeQuery,调用方式如下:<br/>
178 * TermRangeQuery rangequery=new TermRangeQuery(字段名, 起始值, 终止值, 起始值是否包含边界, 终止值是否包含边界); <br/><br/>
179 *
180 * Hits hits=searcher.search(rangequery);<br/>
181 * 此方法中的参数是Boolean类型的,表示是否包含边界 。<br/>
182 * true 包含边界<br/>
183 * false不包含边界<br/>
184 * @throws Exception
185 */
186 @Test
187 public void rangeQuery() throws Exception {
188 IndexReader reader = IndexReader.open(FSDirectory.open(new File(XMLPropertyConfig.getConfigXML().getString("index_path"))), true);
189 IndexSearcher searcher = new IndexSearcher(reader);
190
191 TermRangeQuery idQuery=new TermRangeQuery("ids", "1", "3", true, true);
192 TermRangeQuery ageQuery=new TermRangeQuery("ages", "10", "30", true, true);
193 TermRangeQuery timeQuery=new TermRangeQuery("birthdays", "2011-03-09", "2013-01-07", true, true);
194
195 TopDocs topDocs=searcher.search(timeQuery, 1000);
196 System.out.println("共检索出 " + topDocs.totalHits + " 条记录");
197 System.out.println();
198
199 ScoreDoc[] scoreDocs = topDocs.scoreDocs;
200 for (ScoreDoc scDoc : scoreDocs) {
201 Document document = searcher.doc(scDoc.doc);
202 String id = document.get("id");
203 String name = document.get("name");
204 String age = document.get("age");
205 String city = document.get("city");
206 String birthday = document.get("birthday");
207 float score = scDoc.score; //相似度
208
209 System.out.println(String.format("id:%s, name:%s, age:%s, city:%s, birthday:%s, 相关度:%s.",
210 id, name, age, city, DateUtils.longToString(Long.parseLong(birthday), Consts.FORMAT_SHORT), score));
211 }
212
213 searcher.close();
214 reader.close();
215 }
216
217 /**
218 * 前缀搜索(搜索起始位置符合要求的结果)<br/><br/>
219 *
220 * 主要对象是PrefixQuery,调用方式如下:<br/>
221 * Term term=new Term(字段名, 搜索关键字);<br/>
222 * PrefixQuery prefixquery=new PrefixQuery(term);<br/>
223 * Hits hits=searcher.search(prefixquery);<br/>
224 *
225 * @throws Exception
226 */
227 @Test
228 public void prefixQuery() throws Exception {
229 IndexReader reader = IndexReader.open(FSDirectory.open(new File(XMLPropertyConfig.getConfigXML().getString("index_path"))), true);
230 IndexSearcher searcher = new IndexSearcher(reader);
231
232 Term term=new Term("name", "王");
233 PrefixQuery prefixquery=new PrefixQuery(term);
234
235 TopDocs topDocs=searcher.search(prefixquery, 1000);
236 System.out.println("共检索出 " + topDocs.totalHits + " 条记录");
237 System.out.println();
238
239 ScoreDoc[] scoreDocs = topDocs.scoreDocs;
240 for (ScoreDoc scDoc : scoreDocs) {
241 Document document = searcher.doc(scDoc.doc);
242 String id = document.get("id");
243 String name = document.get("name");
244 String age = document.get("age");
245 String city = document.get("city");
246 String birthday = document.get("birthday");
247 float score = scDoc.score; //相似度
248
249 System.out.println(String.format("id:%s, name:%s, age:%s, city:%s, birthday:%s, 相关度:%s.",
250 id, name, age, city, DateUtils.longToString(Long.parseLong(birthday), Consts.FORMAT_SHORT), score));
251 }
252
253 searcher.close();
254 reader.close();
255 }
256
257 /**
258 * 短语搜索(根据零碎的短语组合成新的词组进行搜索)<br/><br/>
259 *
260 * 主要对象是PhraseQuery,调用方式如下:<br/>
261 * Term term1=new Term(字段名, 搜索关键字);<br/>
262 * Term term2=new Term(字段名, 搜索关键字);<br/><br/>
263 *
264 * PhraseQuery phrasequery=new PhraseQuery();<br/>
265 * phrasequery.setSlop(参数);<br/>
266 * phrasequery.add(term1);<br/>
267 * phrasequery.add(term2);<br/>
268 * Hits hits=searcher.search(phrasequery);<br/>
269 * 其中setSlop的参数是设置两个关键字之间允许间隔的最大值。<br/>
270 * @throws Exception
271 */
272 @Test
273 public void phraseQuery() throws Exception {
274 IndexReader reader = IndexReader.open(FSDirectory.open(new File(XMLPropertyConfig.getConfigXML().getString("index_path"))), true);
275 IndexSearcher searcher = new IndexSearcher(reader);
276
277 Term term1=new Term("name", "林");
278 Term term2=new Term("name", "钦");
279
280 PhraseQuery phrasequery=new PhraseQuery();
281 phrasequery.setSlop(100);
282 phrasequery.add(term1);
283 phrasequery.add(term2);
284
285 TopDocs topDocs=searcher.search(phrasequery, 1000);
286 System.out.println("共检索出 " + topDocs.totalHits + " 条记录");
287 System.out.println();
288
289 ScoreDoc[] scoreDocs = topDocs.scoreDocs;
290 for (ScoreDoc scDoc : scoreDocs) {
291 Document document = searcher.doc(scDoc.doc);
292 String id = document.get("id");
293 String name = document.get("name");
294 String age = document.get("age");
295 String city = document.get("city");
296 String birthday = document.get("birthday");
297 float score = scDoc.score; //相似度
298
299 System.out.println(String.format("id:%s, name:%s, age:%s, city:%s, birthday:%s, 相关度:%s.",
300 id, name, age, city, DateUtils.longToString(Long.parseLong(birthday), Consts.FORMAT_SHORT), score));
301 }
302
303 searcher.close();
304 reader.close();
305 }
306
307 /**
308 * 多短语搜索(先指定一个前缀关键字,然后其他的关键字加在此关键字之后,组成词语进行搜索)<br/><br/>
309 *
310 * 主要对象是MultiPhraseQuery,调用方式如下:<br/>
311 *
312 * Term term=new Term(字段名,前置关键字);<br/>
313 * Term term1=new Term(字段名,搜索关键字);<br/>
314 * Term term2=new Term(字段名,搜索关键字);<br/><br/>
315 *
316 * MultiPhraseQuery multiPhraseQuery=new MultiPhraseQuery();<br/><br/>
317 *
318 * multiPhraseQuery.add(term);<br/>
319 * multiPhraseQuery.add(new Term[]{term1, term2});<br/><br/>
320 *
321 * Hits hits=searcher.search(multiPhraseQuery);<br/>
322 * @throws Exception
323 */
324 @Test
325 public void multiPhraseQuery() throws Exception {
326 IndexReader reader = IndexReader.open(FSDirectory.open(new File(XMLPropertyConfig.getConfigXML().getString("index_path"))), true);
327 IndexSearcher searcher = new IndexSearcher(reader);
328
329 //查询“计张”、“计钦”组合的关键词,先指定一个前缀关键字,然后其他的关键字加在此关键字之后,组成词语进行搜索
330 Term term=new Term("name", "计"); //前置关键字
331 Term term1=new Term("name", "张"); //搜索关键字
332 Term term2=new Term("name", "钦"); //搜索关键字
333
334 MultiPhraseQuery multiPhraseQuery=new MultiPhraseQuery();
335 multiPhraseQuery.add(term);
336 multiPhraseQuery.add(new Term[]{term1, term2});
337
338
339 TopDocs topDocs=searcher.search(multiPhraseQuery, 1000);
340 System.out.println("共检索出 " + topDocs.totalHits + " 条记录");
341 System.out.println();
342
343 ScoreDoc[] scoreDocs = topDocs.scoreDocs;
344 for (ScoreDoc scDoc : scoreDocs) {
345 Document document = searcher.doc(scDoc.doc);
346 String id = document.get("id");
347 String name = document.get("name");
348 String age = document.get("age");
349 String city = document.get("city");
350 String birthday = document.get("birthday");
351 float score = scDoc.score; //相似度
352
353 System.out.println(String.format("id:%s, name:%s, age:%s, city:%s, birthday:%s, 相关度:%s.",
354 id, name, age, city, DateUtils.longToString(Long.parseLong(birthday), Consts.FORMAT_SHORT), score));
355 }
356
357 searcher.close();
358 reader.close();
359 }
360
361 /**
362 * 模糊搜索(顾名思义)<br/><br/>
363 *
364 * 主要对象是FuzzyQuery,调用方式如下:<br/><br/>
365 *
366 * Term term=new Term(字段名, 搜索关键字);<br/>
367 * FuzzyQuery fuzzyquery=new FuzzyQuery(term,参数);<br/>
368 * Hits hits=searcher.search(fuzzyquery);<br/>
369 * 此中的参数是表示模糊度,是小于1的浮点小数,比如0.5f
370 * @throws Exception
371 */
372 @Test
373 public void fuzzyQuery() throws Exception {
374 IndexReader reader = IndexReader.open(FSDirectory.open(new File(XMLPropertyConfig.getConfigXML().getString("index_path"))), true);
375 IndexSearcher searcher = new IndexSearcher(reader);
376
377 Term term=new Term("name", "三张");
378 FuzzyQuery fuzzyquery=new FuzzyQuery(term, 0.5f);
379
380 TopDocs topDocs=searcher.search(fuzzyquery, 1000);
381 System.out.println("共检索出 " + topDocs.totalHits + " 条记录");
382 System.out.println();
383
384 ScoreDoc[] scoreDocs = topDocs.scoreDocs;
385 for (ScoreDoc scDoc : scoreDocs) {
386 Document document = searcher.doc(scDoc.doc);
387 String id = document.get("id");
388 String name = document.get("name");
389 String age = document.get("age");
390 String city = document.get("city");
391 String birthday = document.get("birthday");
392 float score = scDoc.score; //相似度
393
394 System.out.println(String.format("id:%s, name:%s, age:%s, city:%s, birthday:%s, 相关度:%s.",
395 id, name, age, city, DateUtils.longToString(Long.parseLong(birthday), Consts.FORMAT_SHORT), score));
396 }
397
398 searcher.close();
399 reader.close();
400 }
401
402 /**
403 * 通配符搜索(顾名思义)<br/><br/>
404 *
405 * 主要对象是:WildcardQuery,调用方式如下:<br/><br/>
406 *
407 * Term term=new Term(字段名,搜索关键字+通配符);<br/>
408 * WildcardQuery wildcardquery=new WildcardQuery(term);<br/>
409 * Hits hits=searcher.search(wildcardquery);<br/><br/>
410 *
411 * 其中的通配符分两种,即*和?<br/>
412 * * 表示任意多的自负<br/>
413 * ?表示任意一个字符
414 * @throws Exception
415 */
416 @Test
417 public void wildcardQuery() throws Exception {
418 IndexReader reader = IndexReader.open(FSDirectory.open(new File(XMLPropertyConfig.getConfigXML().getString("index_path"))), true);
419 IndexSearcher searcher = new IndexSearcher(reader);
420
421 Term term=new Term("name", "三?");
422 WildcardQuery wildcardQuery=new WildcardQuery(term);
423
424 TopDocs topDocs=searcher.search(wildcardQuery, 1000);
425 System.out.println("共检索出 " + topDocs.totalHits + " 条记录");
426 System.out.println();
427
428 ScoreDoc[] scoreDocs = topDocs.scoreDocs;
429 for (ScoreDoc scDoc : scoreDocs) {
430 Document document = searcher.doc(scDoc.doc);
431 String id = document.get("id");
432 String name = document.get("name");
433 String age = document.get("age");
434 String city = document.get("city");
435 String birthday = document.get("birthday");
436 float score = scDoc.score; //相似度
437
438 System.out.println(String.format("id:%s, name:%s, age:%s, city:%s, birthday:%s, 相关度:%s.",
439 id, name, age, city, DateUtils.longToString(Long.parseLong(birthday), Consts.FORMAT_SHORT), score));
440 }
441
442 searcher.close();
443 reader.close();
444 }
445
446 /**
447 * 正则表达式搜索(顾名思义,这个类引入lucene-queries-3.5.0.jar包)<br/><br/>
448 *
449 * 主要对象是:RegexQuery,调用方式如下 <br/>
450 * String regex = ".*"; <br/>
451 * Term term = new Term (search_field_name, regex); <br/>
452 * RegexQuery query = new RegexQuery (term); <br/>
453 * TopDocs hits = searcher.search (query, 100); <br/>
454 * @throws Exception
455 */
456 @Test
457 public void regexQuery() throws Exception {
458 IndexReader reader = IndexReader.open(FSDirectory.open(new File(XMLPropertyConfig.getConfigXML().getString("index_path"))), true);
459 IndexSearcher searcher = new IndexSearcher(reader);
460
461 String regex = "林*";
462 Term term=new Term("name", regex);
463 RegexQuery query = new RegexQuery(term);
464
465 TopDocs topDocs=searcher.search(query, 1000);
466 System.out.println("共检索出 " + topDocs.totalHits + " 条记录");
467 System.out.println();
468
469 ScoreDoc[] scoreDocs = topDocs.scoreDocs;
470 for (ScoreDoc scDoc : scoreDocs) {
471 Document document = searcher.doc(scDoc.doc);
472 String id = document.get("id");
473 String name = document.get("name");
474 String age = document.get("age");
475 String city = document.get("city");
476 String birthday = document.get("birthday");
477 float score = scDoc.score; //相似度
478
479 System.out.println(String.format("id:%s, name:%s, age:%s, city:%s, birthday:%s, 相关度:%s.",
480 id, name, age, city, DateUtils.longToString(Long.parseLong(birthday), Consts.FORMAT_SHORT), score));
481 }
482
483 searcher.close();
484 reader.close();
485 }
486
487 /**
488 * 数值范围过滤器,如:int、long、float类型等
489 *
490 * @throws Exception
491 */
492 @Test
493 public void numericFilter() throws Exception{ //CustomScoreQuery
494 //Filter filter = NumericRangeFilter.newLongRange("id", 1l, 3l, true, true);
495 Filter filter = NumericRangeFilter.newIntRange("age", 1, 39, true, true);
496 List<Person> persons=search(filter, new String[]{"name","city"}, "厦门");
497 for(Person person : persons){
498 System.out.println(String.format("id:%s, name:%s, age:%s, city:%s, birthday:%s.",
499 person.getId(), person.getName(), person.getAge(), person.getCity(), DateUtils.dateToString(person.getBirthday(), Consts.FORMAT_SHORT)));
500 }
501 }
502
503 /**
504 * 时间范围过滤器
505 * @throws Exception
506 */
507 @Test
508 public void dateFilter() throws Exception{
509 //2008-06-12
510 long min=DateUtils.stringToDate("2008-06-12", Consts.FORMAT_SHORT).getTime();
511 //2013-01-07
512 long max=DateUtils.stringToDate("2013-01-07", Consts.FORMAT_SHORT).getTime();
513 Filter filter = NumericRangeFilter.newLongRange("birthday", min, max, true, true);
514 List<Person> persons=search(filter, new String[]{"name","city"}, "厦门");
515 for(Person person : persons){
516 System.out.println(String.format("id:%s, name:%s, age:%s, city:%s, birthday:%s.",
517 person.getId(), person.getName(), person.getAge(), person.getCity(), DateUtils.dateToString(person.getBirthday(), Consts.FORMAT_SHORT)));
518 }
519 }
520
521 /**
522 * 创建索引
523 *
524 * @throws Exception
525 */
526 @Test
527 public void createIndex() throws Exception {
528 List<Document> docs = new ArrayList<Document>();
529 for (Person person : getPersons()) {
530 Document doc = new Document();
531 //声明为NumericField的字段,只能用NumericRangeFilter对象范围查询,不能用作关键字查询。
532 //NumericField不推荐,统一用Field
533 doc.add(new NumericField("id", Field.Store.YES, true).setLongValue(person.getId()));
534 doc.add(new NumericField("age", Field.Store.YES, true).setIntValue(person.getAge()));
535 doc.add(new NumericField("birthday", Field.Store.YES, true).setLongValue(person.getBirthday().getTime()));
536
537 doc.add(new Field("ids", person.getId()+"", Field.Store.YES, Field.Index.NOT_ANALYZED));
538 doc.add(new Field("ages", person.getAge()+"", Field.Store.YES, Field.Index.NOT_ANALYZED));
539 doc.add(new Field("birthdays", DateUtils.dateToString(person.getBirthday(), Consts.FORMAT_SHORT),
540 Field.Store.YES, Field.Index.NOT_ANALYZED));
541 doc.add(new Field("name", person.getName(), Field.Store.YES, Field.Index.ANALYZED));
542 doc.add(new Field("city", person.getCity(), Field.Store.YES, Field.Index.ANALYZED));
543
544 docs.add(doc);
545 }
546 LuceneUtil.createIndex(docs);
547 }
548
549 private List<Person> search(Filter filter, String[] fields, String keyword) {
550 List<Person> result = new ArrayList<Person>();
551
552 IndexSearcher indexSearcher = null;
553 TopDocs topDocs = null;
554 try {
555 // 创建索引搜索器,且只读
556 IndexReader indexReader = IndexReader.open(FSDirectory.open(new File(XMLPropertyConfig.getConfigXML().getString("index_path"))), true);
557 indexSearcher = new IndexSearcher(indexReader);
558
559 MultiFieldQueryParser queryParser = new MultiFieldQueryParser(Version.LUCENE_35,
560 fields, new IKAnalyzer());
561 Query query = queryParser.parse(keyword);
562
563 // 返回前number条记录
564 if(filter == null){
565 topDocs=indexSearcher.search(query, 100000);
566 }else {
567 topDocs=indexSearcher.search(query, filter, 100000);
568 }
569
570 // 信息展示
571 int totalCount = topDocs.totalHits;
572 System.out.println("共检索出 " + totalCount + " 条记录");
573
574 //高亮显示
575 Formatter formatter = new SimpleHTMLFormatter("<font color='red'>", "</font>");
576 QueryScorer fragmentScorer = new QueryScorer(query);
577 Highlighter highlighter = new Highlighter(formatter, fragmentScorer);
578 Fragmenter fragmenter = new SimpleFragmenter(100);
579 highlighter.setTextFragmenter(fragmenter);
580
581 ScoreDoc[] scoreDocs = topDocs.scoreDocs;
582
583 for (ScoreDoc scDoc : scoreDocs) {
584 Document document = indexSearcher.doc(scDoc.doc);
585 String id = document.get("id");
586 String name = document.get("name");
587 String age = document.get("age");
588 String city = document.get("city");
589 String birthday = document.get("birthday");
590 float score = scDoc.score; //相似度
591 System.out.println("相似度:"+score);
592
593 String lighterName = highlighter.getBestFragment(new IKAnalyzer(), "name", name);
594 if (null == lighterName) {
595 lighterName = name;
596 }
597
598 String lighterAge = highlighter.getBestFragment(new IKAnalyzer(), "age", age);
599 if (null == lighterAge) {
600 lighterAge = age;
601 }
602
603 String lighterCity= highlighter.getBestFragment(new IKAnalyzer(), "city", city);
604 if (null == lighterCity) {
605 lighterCity = city;
606 }
607
608 String lighterBirthday = highlighter.getBestFragment(new IKAnalyzer(), "birthday", birthday);
609 if (null == lighterBirthday) {
610 lighterBirthday = birthday;
611 }
612
613 Person person = new Person();
614 person.setId(Long.parseLong(id));
615 person.setName(lighterName);
616 person.setAge(NumberUtils.toInt(age));
617 person.setCity(lighterCity);
618 person.setBirthday(DateUtils.longToDate(Long.parseLong(lighterBirthday)));
619 result.add(person);
620 }
621 } catch (Exception e) {
622 e.printStackTrace();
623 } finally {
624 try {
625 indexSearcher.close();
626 } catch (IOException e) {
627 e.printStackTrace();
628 }
629 }
630
631 return result;
632 }
633
634 private List<Person> getPersons() {
635 try {
636 List<Person> persons = new ArrayList<Person>();
637 persons.add(new Person(1l, "张三", 10, "福州", DateUtils.stringToDate("2013-01-07", Consts.FORMAT_SHORT)));
638 persons.add(new Person(2l, "张四", 20, "莆田", DateUtils.stringToDate("2012-01-08", Consts.FORMAT_SHORT)));
639 persons.add(new Person(3l, "王五", 30, "泉州", DateUtils.stringToDate("2011-03-09", Consts.FORMAT_SHORT)));
640 persons.add(new Person(4l, "李四", 40, "厦门", DateUtils.stringToDate("2010-04-10", Consts.FORMAT_SHORT)));
641 persons.add(new Person(5l, "李白", 50, "漳州", DateUtils.stringToDate("2009-05-11", Consts.FORMAT_SHORT)));
642 persons.add(new Person(6l, "林计张三张三张三张三张三张三张三张三张三张三张三张三张三计钦", 60, "龙岩", DateUtils.stringToDate("2008-06-12", Consts.FORMAT_SHORT)));
643 return persons;
644 } catch (ParseException e) {
645 e.printStackTrace();
646 }
647 return null;
648 }
649 }