首页 > 代码库 > [Java Web]Java的全文搜索类库 Lucene
[Java Web]Java的全文搜索类库 Lucene
Lucene是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。
Lucene的实现机制是倒排表。例如现在有2个文档需要建立索引,内容分别为"Lucene Learning"和"Lucene Hadoop",建立后的索引实际是这样的:
索引的优势在于:虽然建立索引会比较耗时,但是在一次建立后便可以永远支持高效的查询。
Lucene的核心类有:
Directory:索引对象,常用有RAMDirectory和FSDirectory两种,前者代表一个内存中的索引文件,后者代表一个本地的索引文件。
Filed:字段,由name和value组成,常用的字段分为三种:
- StoredFiled:仅用来存储数据的字段,该字段的数据不会建立索引。
- StringFiled、LongFiled等:将数据整体建立为索引的字段。
- TextFiled:将数据分词并建立索引的字段。
Document:索引中存储的文档结构,一个文档由多个字段组成。
Term:词元,相当于索引中的键,每个Term都指向一个由文档组成的链表。
IndexReader:索引的读取流,可以从索引中读取出需要的文档。
IndexWriter:索引的输出流,将文档写入索引。
IndexSearcher:索引的搜索功能。
Query:搜索条件。
Analyzer:分词器,可以将字段中的数据分解成多个词元。
Lucene的流程:
写入:将数据源转换为文档,然后使用IndexWriter的addDocument方法将文档添加到索引。
查询:使用IndexReader获取一个IndexSearcher对象,并创建一个Query对象指定查询类型,然后使用IndexSearcher的search方法得到文档。
代码实例:
添加索引:
public static void init() throws IOException { //索引文件 Directory dir = FSDirectory.open(new File("E:/index")); //索引配置(指定Lucene版本和分词器) IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_10_0, new StandardAnalyzer()); //得到输出流 IndexWriter writer = new IndexWriter(dir, config); //创建文档 Document doc = new Document(); //id会以一个整体被作为词元被索引 并且会被存储在文档中 doc.add(new StringField("id", "123", Field.Store.YES)); //content会被分词器分割成数个词元被索引 但不会存储在文档中 doc.add(new TextField("content", "Lucene是apache软件基金会4 jakarta" + "项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎," + "而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎," + "部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件" + "开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的" + "功能,或者是以此为基础建立起完整的全文检索引擎。", Field.Store.NO)); //address会被分词器分割成数个词元被索引 并且会存储在文档中 doc.add(new TextField("address", "北京市海淀区翠微路凯德大厦", Field.Store.YES)); //将文档添加到索引 writer.addDocument(doc); //打印当前已经被索引的文档个数 System.out.println("被索引的文档个数:" + writer.numDocs()); writer.close(); }
遍历索引中所有的文档:
public static void ergodic() throws IOException { //索引文件 Directory dir = FSDirectory.open(new File("E:/index")); //得到输入流 IndexReader reader = DirectoryReader.open(dir); IndexSearcher searcher = new IndexSearcher(reader); Document doc = null; for (int i = 0; i < reader.maxDoc(); i++) { doc = searcher.doc(i); System.out.println("Doc [" + i + "] : id: " + doc.get("id") + ", desc: " + doc.get("content")); } }
public static void search() throws IOException, ParseException { //索引文件 Directory dir = FSDirectory.open(new File("E:/index.txt")); //输入流 IndexReader reader = DirectoryReader.open(dir); IndexSearcher searcher = new IndexSearcher(reader); // 搜索条件 QueryParser parser = new QueryParser("desc", new StandardAnalyzer()); Query query = parser.parse("索引文件"); // 搜索结果 TopDocs hits = searcher.search(query, 2); System.out.println("查询出来的总数是:" + hits.totalHits); // 获取搜索结果 Document doc = null; for (ScoreDoc scoreDoc : hits.scoreDocs) { doc = searcher.doc(scoreDoc.doc); System.out.println("Doc [" + scoreDoc.doc + "] : id: " + doc.get("id") + ", desc: " + doc.get("content")); } }
一些细节:
- 对于一个索引文件,同时只能有一个输出流对它进行操作.
- 为了避免频繁的I/O操作,可以先将索引建立在RAMDirectory中,然后一次性写入本地文件。
- 中文分词库比较好用的有Ansj和IK,可以自行百度了解。
- Lucene不支持去重,DuplicateFilter会先将索引进行去重后在进行条件查询,这样会造成数据缺失。
- 索引的更新可以先根据词元删除原本的文档后再添加新的文档,在批量操作时效率很高。
[Java Web]Java的全文搜索类库 Lucene