【Lucene3.6.2入门系列】第09节_高级搜索之自定义QueryParser

[java]  view plain copy print ?
  1. package com.jadyer.lucene;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.text.SimpleDateFormat;  
  6. import java.util.Date;  
  7.   
  8. import org.apache.lucene.analysis.standard.StandardAnalyzer;  
  9. import org.apache.lucene.document.Document;  
  10. import org.apache.lucene.document.Field;  
  11. import org.apache.lucene.document.NumericField;  
  12. import org.apache.lucene.index.IndexReader;  
  13. import org.apache.lucene.index.IndexWriter;  
  14. import org.apache.lucene.index.IndexWriterConfig;  
  15. import org.apache.lucene.queryParser.ParseException;  
  16. import org.apache.lucene.queryParser.QueryParser;  
  17. import org.apache.lucene.search.IndexSearcher;  
  18. import org.apache.lucene.search.Query;  
  19. import org.apache.lucene.search.ScoreDoc;  
  20. import org.apache.lucene.search.TopDocs;  
  21. import org.apache.lucene.store.Directory;  
  22. import org.apache.lucene.store.FSDirectory;  
  23. import org.apache.lucene.util.Version;  
  24.   
  25. import com.jadyer.custom.MyQueryParser;  
  26.   
  27. /** 
  28.  * 【Lucene3.6.2入门系列】第09节_高级搜索之自定义QueryParser 
  29.  * @create Aug 19, 2013 2:07:32 PM 
  30.  * @author 玄玉<http://blog.csdn.net/jadyer> 
  31.  */  
  32. public class AdvancedSearch {  
  33.     private Directory directory;  
  34.     private IndexReader reader;  
  35.       
  36.     public AdvancedSearch(){  
  37.         /**文件大小*/  
  38.         int[] sizes = {901020106050};  
  39.         /**文件名*/  
  40.         String[] names = {"Michael.java""Scofield.ini""Tbag.txt""Jack""Jade""Jadyer"};  
  41.         /**文件内容*/  
  42.         String[] contents = {"my java blog is http://blog.csdn.net/jadyer",  
  43.                              "my Java Website is http://www.jadyer.cn",  
  44.                              "my name is jadyer",  
  45.                              "I am a Java Developer",  
  46.                              "I am from Haerbin",  
  47.                              "I like java of Lucene"};  
  48.         /**文件日期*/  
  49.         Date[] dates = new Date[sizes.length];  
  50.         SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd HH:mm:ss");  
  51.         IndexWriter writer = null;  
  52.         Document doc = null;  
  53.         try {  
  54.             dates[0] = sdf.parse("20130407 15:25:30");  
  55.             dates[1] = sdf.parse("20130407 16:30:45");  
  56.             dates[2] = sdf.parse("20130213 11:15:25");  
  57.             dates[3] = sdf.parse("20130808 09:30:55");  
  58.             dates[4] = sdf.parse("20130526 13:54:22");  
  59.             dates[5] = sdf.parse("20130701 17:35:34");  
  60.             directory = FSDirectory.open(new File("myExample/01_index/"));  
  61.             writer = new IndexWriter(directory, new IndexWriterConfig(Version.LUCENE_36, new StandardAnalyzer(Version.LUCENE_36)));  
  62.             writer.deleteAll();  
  63.             for(int i=0; i<sizes.length; i++){  
  64.                 doc = new Document();  
  65.                 doc.add(new NumericField("size",Field.Store.YES, true).setIntValue(sizes[i]));  
  66.                 doc.add(new Field("name", names[i], Field.Store.YES, Field.Index.ANALYZED_NO_NORMS));  
  67.                 doc.add(new Field("content", contents[i], Field.Store.NO, Field.Index.ANALYZED));  
  68.                 doc.add(new NumericField("date", Field.Store.YES, true).setLongValue(dates[i].getTime()));  
  69.                 writer.addDocument(doc);  
  70.             }  
  71.         } catch (Exception e) {  
  72.             e.printStackTrace();  
  73.         } finally {  
  74.             if(null != writer){  
  75.                 try {  
  76.                     writer.close();  
  77.                 } catch (IOException ce) {  
  78.                     ce.printStackTrace();  
  79.                 }  
  80.             }  
  81.         }  
  82.     }  
  83.       
  84.       
  85.     /** 
  86.      * 获取IndexReader实例 
  87.      */  
  88.     private IndexReader getIndexReader(){  
  89.         try {  
  90.             if(reader == null){  
  91.                 reader = IndexReader.open(directory);  
  92.             }else{  
  93.                 //if the index was changed since the provided reader was opened, open and return a new reader; else,return null  
  94.                 //如果当前reader在打开期间index发生改变,则打开并返回一个新的IndexReader,否则返回null  
  95.                 IndexReader ir = IndexReader.openIfChanged(reader);  
  96.                 if(ir != null){  
  97.                     reader.close(); //关闭原reader  
  98.                     reader = ir;    //赋予新reader  
  99.                 }  
  100.             }  
  101.             return reader;  
  102.         }catch(Exception e) {  
  103.             e.printStackTrace();  
  104.         }  
  105.         return null//发生异常则返回null  
  106.     }  
  107.   
  108.       
  109.     /** 
  110.      * 自定义QueryParser的搜索 
  111.      * @param expr 搜索的表达式 
  112.      */  
  113.     public void searchByCustomQueryParser(String expr){  
  114.         IndexSearcher searcher = new IndexSearcher(this.getIndexReader());  
  115.         QueryParser parser = new MyQueryParser(Version.LUCENE_36, "content"new StandardAnalyzer(Version.LUCENE_36));  
  116.         try {  
  117.             Query query = parser.parse(expr);  
  118.             TopDocs tds = searcher.search(query, 10);  
  119.             for(ScoreDoc sd : tds.scoreDocs){  
  120.                 Document doc = searcher.doc(sd.doc);  
  121.                 System.out.print("文档编号=" + sd.doc + "  文档权值=" + doc.getBoost() + "  文档评分=" + sd.score + "    ");  
  122.                 System.out.println("size=" + doc.get("size") + "  date=" + new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date(Long.parseLong(doc.get("date")))) + "  name=" + doc.get("name"));  
  123.             }  
  124.         } catch (ParseException e) {  
  125.             System.err.println(e.getMessage());  
  126.         } catch (Exception e) {  
  127.             e.printStackTrace();  
  128.         } finally {  
  129.             if(null != searcher){  
  130.                 try {  
  131.                     searcher.close(); //记得关闭IndexSearcher  
  132.                 } catch (IOException e) {  
  133.                     e.printStackTrace();  
  134.                 }  
  135.             }  
  136.         }  
  137.     }  
  138.       
  139.       
  140.     /** 
  141.      * 测试一下搜索效果 
  142.      */  
  143.     public static void main(String[] args) {  
  144.         AdvancedSearch advancedSearch = new AdvancedSearch();  
  145.         advancedSearch.searchByCustomQueryParser("name:Jadk~");  
  146.         advancedSearch.searchByCustomQueryParser("name:Ja??er");  
  147.         System.out.println("------------------------------------------------------------------------");  
  148.         advancedSearch.searchByCustomQueryParser("name:Jade");  
  149.         System.out.println("------------------------------------------------------------------------");  
  150.         advancedSearch.searchByCustomQueryParser("name:[h TO n]");  
  151.         System.out.println("------------------------------------------------------------------------");  
  152.         advancedSearch.searchByCustomQueryParser("size:[20 TO 80]");  
  153.         System.out.println("------------------------------------------------------------------------");  
  154.         advancedSearch.searchByCustomQueryParser("date:[20130407 TO 20130701]");  
  155.     }  
  156. }  


下面是自定义的MyQueryParser.java(这里主要实现了以下两个功能)

1)禁用模糊搜索和通配符搜索,以提高搜索性能

2)扩展基于数字和日期的搜索,使之支持数字和日期的搜索

[java]  view plain copy print ?
  1. package com.jadyer.custom;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.regex.Pattern;  
  5.   
  6. import org.apache.lucene.analysis.Analyzer;  
  7. import org.apache.lucene.queryParser.ParseException;  
  8. import org.apache.lucene.queryParser.QueryParser;  
  9. import org.apache.lucene.search.NumericRangeQuery;  
  10. import org.apache.lucene.search.Query;  
  11. import org.apache.lucene.util.Version;  
  12.   
  13. /** 
  14.  * 自定义QueryParser 
  15.  * @see -------------------------------------------------------------------------------------------------- 
  16.  * @see 实际使用QueryParser的过程中,通常会考虑两个问题 
  17.  * @see 1)限制性能低的QueryParser--对于某些QueryParser在搜索时会使得性能降低,故考虑禁用这些搜索以提升性能 
  18.  * @see 2)扩展基于数字和日期的搜索---有时需要进行一个数字的范围搜索,故需扩展原有的QueryParser才能实现此搜索 
  19.  * @see -------------------------------------------------------------------------------------------------- 
  20.  * @see 限制性能低的QueryParser 
  21.  * @see 继承QueryParser类并重载相应方法,比如getFuzzyQuery和getWildcardQuery 
  22.  * @see 这样造成的结果就是,当输入普通的搜索表达式时,如'I AND Haerbin'可以正常搜索 
  23.  * @see 但输入'name:Jadk~'或者'name:Ja??er'时,就会执行到重载方法中,这时就可以自行处理了,比如本例中禁止该功能 
  24.  * @see -------------------------------------------------------------------------------------------------- 
  25.  * @see 扩展基于数字和日期的查询 
  26.  * @see 思路就是继承QueryParser类后重载getRangeQuery()方法 
  27.  * @see 再针对数字和日期的'域',做特殊处理(使用NumericRangeQuery.newIntRange()方法来搜索) 
  28.  * @see -------------------------------------------------------------------------------------------------- 
  29.  * @create Aug 6, 2013 4:13:42 PM 
  30.  * @author 玄玉<http://blog.csdn.net/jadyer> 
  31.  */  
  32. public class MyQueryParser extends QueryParser {  
  33.     public MyQueryParser(Version matchVersion, String f, Analyzer a) {  
  34.         super(matchVersion, f, a);  
  35.     }  
  36.       
  37.     @Override  
  38.     protected Query getWildcardQuery(String field, String termStr) throws ParseException {  
  39.         throw new ParseException("由于性能原因,已禁用通配符搜索,请输入更精确的信息进行搜索 ^_^ ^_^");  
  40.     }  
  41.       
  42.     @Override  
  43.     protected Query getFuzzyQuery(String field, String termStr, float minSimilarity) throws ParseException {  
  44.         throw new ParseException("由于性能原因,已禁用模糊搜索,请输入更精确的信息进行搜索 ^_^ ^_^");  
  45.     }  
  46.       
  47.     @Override  
  48.     protected Query getRangeQuery(String field, String part1, String part2, boolean inclusive) throws ParseException {  
  49.         if(field.equals("size")){  
  50.             //默认的QueryParser.parse(String query)表达式中并不支持'size:[20 TO 80]'数字的域值  
  51.             //这样一来,针对数字的域值进行特殊处理,那么QueryParser表达式就支持数字了  
  52.             return NumericRangeQuery.newIntRange(field, Integer.parseInt(part1), Integer.parseInt(part2), inclusive, inclusive);  
  53.         }else if(field.equals("date")){  
  54.             String regex = "\\d{8}";  
  55.             String dateType = "yyyyMMdd";  
  56.             if(Pattern.matches(regex, part1) && Pattern.matches(regex, part2)){  
  57.                 SimpleDateFormat sdf = new SimpleDateFormat(dateType);  
  58.                 try {  
  59.                     long min = sdf.parse(part1).getTime();  
  60.                     long max = sdf.parse(part2).getTime();  
  61.                     //使之支持日期的检索,应用时直接QueryParser.parse("date:[20130407 TO 20130701]")  
  62.                     return NumericRangeQuery.newLongRange(field, min, max, inclusive, inclusive);  
  63.                 } catch (java.text.ParseException e) {  
  64.                     e.printStackTrace();  
  65.                 }  
  66.             }else{  
  67.                 throw new ParseException("Unknown date format, please use '" + dateType + "'");  
  68.             }  
  69.         }  
  70.         //如没找到匹配的Field域,那么返回默认的TermRangeQuery  
  71.         return super.getRangeQuery(field, part1, part2, inclusive);  
  72.     }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值