Lucene是一个基于java开源的全文检索工具包,项目地址是http://lucene.apache.org/。难得可贵的是它支持中文检索。下面我们来学习下一个简单的Lucene的入门范例。
基本概念
Index
。在Lucene中index是一个集合, 这个集合中会包含多个全文关键字以待检索。本例中我们的index是一个文件夹,我们会把待检索内容进行分词后存入这个文件夹中。Document
。文档指代的是一篇待进行检索的全文。对一篇文档(或者待检索内容)进行关键字分词后就存入文档中。
使用到的类
org.apache.lucene.store.Directory
。这个类是Lucen中表示索引存储位置的类,它可以是一个org.apache.lucene.store.FSDirectory
表示将索引存储到文件系统中。也可以是org.apache.lucene.store.RAMDirectory
将索引存储到内存中。org.apache.lucene.analysis.Analyzer
是词法分析器,用来进行语言分词,在创建索引和检索的时候需要使用同样的分析器来进行语句分析。为了支持中文检索,我们将会使用到org.apache.lucene.analysis.cjk.CJKAnalyzer
,这个分析器同样支持日文的检索。org.apache.lucene.index.IndexReader
。顾名思义这个类是用来读取Index的类,我们在进行检索的时候需要让检索器知道如何去读取Index,那么就需要构建一个IndexReader。我们将会使用的Reader将是普通的org.apache.lucene.index.DirectoryReader
。org.apache.lucene.search.IndexSearcher
是用来进行Index检索的主类。org.apache.lucene.index.IndexWriter
是构建index的时候使用到的类,用来将index输入到指定的位置(文件系统或者内存)。构建writer的时候还需要构建org.apache.lucene.index.IndexWriterConfig
来对writer进行配置。org.apache.lucene.document.Document
。如前段所说,Document是一篇待检索内容。Document中可以存储多个内容用来表示一篇完整的待检索内容(文本)。Document必须要存储在Index中,可以在存储的时候选择是否要存储原内容或者只存储用于检索的关键字。org.apache.lucene.document.StoredField
。用来存储一段需要保存到Index中的内容,这个内容在后续检索的时候可以直接获取原文(不会进行分词或者index转换)。一般存储一些很小的数据内容,并且需要在检索过程中使用到的内容,比如排序之类的关键字。org.apache.lucene.document.TextField
。用来存储一大段文本的分词结果,通常用于不需要存储原文的大段文本内容。org.apache.lucene.document.StringField
。这个用来表示会存进index中但不会进行分词的内容,通常用来存储关键字,或者一些不会变化的文本,可以用来作为Document的id来进行Document运行时的更新。org.apache.lucene.search.ScoreDoc
。用来表示检索过程中hit的Document,其中会有Document的顺序标识(用来取出Document)和检索的时候匹配度(个人理解,仅供参考)。
下面我们开始学习代码
需要使用到的包
下载Lucene后会发现了有好多包,那么基础的包在以下几个目录中,这些包是一定要引入的。
analysis\common\这个包里面包含了我们需要的分析器,如果需要其他类型的分析器,可以尝试去analysis目录下寻找。
core\这个目录下的包是Lucene的运行核心代码
queries\和queryparser\目录下的包是用来执行检索查询功能的核心包
文本分析并且存入Index中
首先我们需要指定Index的存储位置,本例中我们使用文件系统来存储Index,那么需要构建一个FSDirectory:
Path indexPath = Paths.get(indexPathString);
Directory indexDir = FSDirectory.open(indexPath);
其次我们需要构建一个IndexWriter进行Index的存储,在构建的时候我们可以指定index的存储方式CREATE_OR_APPEND,表明我们期望在index存在的情况下只进行update而不是创建新的index:
IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
IndexWriter writer = new IndexWriter(indexDir, iwc);
获得了Writer之后我们就可以开始构建Document,然后使用Writer将Document写入文件中。一个Document对应一个待检索内容。所以完整的构建index的代码如下:
索引查询
要根据关键字进行前段构建的索引的查询,我们需要构建IndexSearcher。并且我们需要明白Lucene中查询是返回TopN的形式,并且需要指定是通过哪一个字段进行检索(比如前段中的contex还是title)。下面的是范例代码:
查询排序
如果要对查询结果进行排序,那么我们需要在进行查询的时候传入一个org.apache.lucene.search.Sort对象,比如需要使用"created"进行排序,那么在进行Searcher之前需要构建一个Sort对象:
Sort sort = new Sort(new SortField("create", SortField.Type.LONG));
//查询Top100个记录
ScoreDoc[] docs = searcher.search(query, 100, sort).scoreDocs;
分页查询
计数
既然要分页,那么我们需要知道关键字hit到的记录总数:
查询指定页数的记录
Lucene中并没有提供一个直观的分页功能,但是它有提供了searchAfter功能,我们可以使用这个功能来进行分页查询。为了实现searchAfter,我们需要知道上一次(上一页)查询的最后一个ScoreDoc。我们可以在每次查询的时候都根据页数和每页显示的数量来找到最后一个ScoreDoce。当然这个方法有缺点就是如果只是查询后面几页的记录的话,我们还是需要查询出前面所有的ScoreDoc。这会导致内存占用的浪费。
当获得了前一页的最后一个ScoreDoc之后我们就可以使用searchAfer的方法查询当前页面的ScoreDoc了,这里我们需要注意的是如果使用了排序,那么在获取上一页最后一个ScoreDoc和获取当前页面的SocreDoc的时候都需要使用一样的Sort。
Lucene的应用领域多在新闻、资料分析,在大数据分析上的用处比较大。
如果你要写爬虫、数据分析的应用,不妨考虑下这个框架。本文简单的介绍了一下Lucene的使用方法,并未涉及原理和进阶的使用。