首页 > 代码库 > Lucene初试
Lucene初试
从知道Hadoop起就听过Lucene的大名,但是一直没有抽出时间好好学习下,最近有了段空闲时间,决定把这些东西补一下,不求知根知底,但求大致了解。
Lucene的概要描述就不多复制了,总之使用它可以快速创建索引,并进行检索,是一个设计良好的框架。
Lucene的使用十分简单,网上下载Lucene包,导入工程基本上就可以使用了,我用的是Lucene4.2的包,下载下来解压后有以下这些目录:
简单的Lucene程序,只用引入core下面的lucene-core.jar以及analysis下面common里面的lucene-analyzers-common.jar就可以了。
Lucene设计的比较好,高级用户可以进行细致化的定制,但是如果初级用户(譬如我)使用的话,也可以很方面的使用,这里就把我的例子贴出来吧。
1 /** 2 * 针对某个文件夹下(不包括子文件夹)所有的txt文件建立索引,存放在该文件夹下的index文件夹中。 3 * 4 * @param rootPath 5 */ 6 public static void buildIndex(String rootPath) throws IOException { 7 //指定索引文件目录 8 Directory indexDir = FSDirectory.open(new File(rootPath + "/index")); 9 File dataDir = new File(rootPath);10 File[] dataFiles = dataDir.listFiles();11 //构造分析器12 Analyzer luceneAnalyzer = new StandardAnalyzer(Version.LUCENE_42);13 //使用分析器构造索引生成器14 IndexWriter indexWriter = new IndexWriter(indexDir, new IndexWriterConfig(Version.LUCENE_42, luceneAnalyzer));15 indexWriter.deleteAll();16 //开始生成索引17 for (int i = 0; i < dataFiles.length; i++) {18 if (dataFiles[i].isFile() && dataFiles[i].getName().endsWith(".txt")) {19 Document document = new Document();20 //以文件名作为path域的内容,Field.Store.YES表示会将其存储到索引中,从而可以直接通过索引查询到内容21 document.add(new StringField("path", dataFiles[i].getCanonicalPath(), Field.Store.YES));22 //以文件内容作为contents域的内容,Field.Store.NO表示不将其存储到索引中,这样的话,可以根据其关键字查询到索引,但是查询不到具体内容。23 document.add(new TextField("contents", FileUtils.readFileToString(dataFiles[i], "GBK"), Field.Store.NO));24 indexWriter.addDocument(document);25 }26 }27 //commit和close合二为一。28 indexWriter.close();29 }30 /**31 * 根据索引进行检索32 *33 * @param indexDir 索引文件存放位置34 * @param keyword 索引关键字35 * @param numberOfRecords 需要查询出几条记录36 */37 public static List<String> search(String indexDir, String keyword, int numberOfRecords) throws IOException {38 //打开索引文件39 Directory indexDirectory = FSDirectory.open(new File(indexDir));40 DirectoryReader ireader = DirectoryReader.open(indexDirectory);41 //构造索引查询器42 IndexSearcher isearcher = new IndexSearcher(ireader);43 //构造查询语句44 Query query = new TermQuery(new Term("contents", keyword));45 //进行查询46 ScoreDoc[] hits = isearcher.search(query, null, numberOfRecords).scoreDocs;47 List<String> result = new ArrayList<String>();48 //遍历查询结果49 for (ScoreDoc scoreDoc : hits)50 result.add(isearcher.doc(scoreDoc.doc).get("path"));51 return result;52 }
完成上面的代码后,就可以对对某个文件夹下的所有文件构建索引并进行查询了,经测试,对英文文件的索引是相当给力的。
这里啰嗦一下自己对Lucene原理的理解,Lucene建立索引的过程为:
1 对需要建立索引的内容进行分词,得到关键字。
2 对关键字进行加工,加工过程包括:过滤,过滤掉语气助词,如and、or、to等;大小写转化,因为人们可能希望查询"Computer"的时候,可以查询到"computer"、"COMPUTER"等相关词;词态转化,如希望在查询"want"的时候,可以查询到"wants","wanted"等等。
3 根据关键字建立索引,即记录某个关键字在哪些文档中出现过。
大致过程就是这样,更细节的优化还没有看,想着等将来需要深层次使用的时候再去看吧。
上面这些步骤完成后,就可以方面的进行查询了。
如果大家比较细心的话,就会发现我上面专门强调“对英文文件的索引是相当给力的”,也就说明对中文文件的索引相当不给力,这是因为英文分词相对比较容易,根据空白字符和标点符号基本上就可以分词了,但是中文分词比较有难度(可以百度“清明时节雨纷纷 断词”,然后自己体会),因此如果需要对中文文件建立索引时,需要使用其他的分词包,做的比较出色的有Lucene自带的SmartCN和IKAnalyzer。这两个分词包的使用也比较简单:
需要使用SmartCN时,引入SmartCN的包(在analysis下面的smartcn下),然后将上面代码的第12行改为:
1 Analyzer luceneAnalyzer = new SmartChineseAnalyzer(Version.LUCENE_42);
即可。
需要使用IKAnalyzer时,引入IKAnalyzer的包(网上自行搜索),然后将上面代码的第12行改为:
1 Analyzer luceneAnalyzer = new IKAnalyzer();
即可。
再次感谢面向对象这个伟大的发明!
以上就是我对Lucene当前的理解了,如果项目中真正用到Lucene时,再深入学习吧。
本文涉及代码已在Oschina的Git上共享了,链接为:http://git.oschina.net/xdxn/Test
参考文献:
开源中文分词框架分词效果对比smartcn与IKanalyzer
Lucene 工作原理
Lucene初试