首页 > 代码库 > 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初试