最近在学习lucene,目前apache已经更新到6.1.0的版本,网上的大多数教程配置有些问题,故自己重配了下.
参考 作者:永恒の_☆ 地址:http://blog.csdn.net/chenghui0317/article/details/10052103
一、Lucene的介绍
Lucene是一个全文检索的框架,apache组织提供了一个用java实现的全文搜索引擎的开源项目,其功能非常的强大,api非常简单,并且有了全文检索的功能支持可以非常方便的实现根据关键字来搜索整个应用系统的内容,大大提高了用户的体验效果。 使用Lucene来建立、搜索功能和操作数据库有一点像,这样就可想而知,Lucene使用起来还是蛮方便的。
那么为什么要使用Lucene 呢? 因为如果没有使用Lucene ,那么就要根据某个关键字来搜索数据库表记录, 就要使用like 一个字符一个字符去匹配,这样子查询的方式的要累坏程序员不说,并且查询数据库的性能开销可想而知。
二、Lucene的执行流程
前面说了Lucene的操作方式和操作数据库有点相似,所以如果要使用Lucene 就要先创建“数据库”,然后往这个“数据表”中一行一行的插入数据,数据插入成功之后,就可以操作这张“数据表”,实现增删改查操作了。
总的来说,可以这样理解:
1、创建一个索引文件目录,然后把需要检索的信息 用Field 对应匹配的 封装成一个Document文档对象,将这个对象放入索引文件目录中,这里既可以将索引存放到磁盘中,也可以放入内存中,如果放入内存,那么程序关闭索引就没有了,所以一般都是将索引放入磁盘中;
2、如果发现信息有问题需要删除,那么索引文件也要删除,否则检索的时候还是会查询得到,这个时候需要根据索引id去删除对应的索引;
3、如果发现信息被更新了,那么索引文件也要更新,这个时候需要先将旧的索引删除然后添加新的索引;
4、最后重头戏是全文搜索了,这和查询数据库一样,先需要创建索引读取对象,然后封装Query查询对象,调用search()方法 得到检索结果。
三、使用Lucene的准备条件
maven pom.xml配置
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>6.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-highlighter -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-highlighter</artifactId>
<version>6.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.lucene/lucene-memory -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-memory</artifactId>
<version>6.1.0</version>
</dependency>
四、使用Lucene实战
1、使用Lucene将索引 写入内存
实现的思路如下:
<1>创建了内存目录对象RAMDirectory 和 索引写入器IndexWriter ;
<2>利用索引写入器将指定的数据存入内存目录对象中;
<3>创建IndexSearch 索引查询对象,然后根据关键字封装Query查询对象;
<4>调用search()方法,将查询的结果返回给TopDocs ,迭代里面所有的Document对象,显示查询结果;
<5>关闭IndexWriter 写入器,关闭RAMDirectory目录对象。
具体代码如下:
import java.io.IOException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.RAMDirectory;
public class RAMDirectoryDemo {
public static void main(String[] args) throws IOException {
long startTime = System.currentTimeMillis();
System.out.println("*****************检索开始**********************");
// 创建一个内存目录对象,所以这里生成的索引不会放在磁盘中,而是在内存中。
RAMDirectory directory = new RAMDirectory();
/*
* public IndexWriterConfig(Analyzer analyzer)
* analyzer:分词器对象
*/
IndexWriterConfig writerConfig = new IndexWriterConfig(new StandardAnalyzer());
/*
* 创建索引写入对象,该对象既可以把索引写入到磁盘中也可以写入到内存中。 参数说明:
* public IndexWriter(Directory directory, IndexWriterConfig conf)
* directory:目录对象,也可以是FSDirectory 磁盘目录对象
* conf:写入对象的控制
*/
IndexWriter writer = new IndexWriter(directory, writerConfig);
// 创建Document 文档对象,在lucene中创建的索引可以看成数据库中的一张表,表中也可以有字段,往里面添加内容之后可以根据字段去匹配查询
// 下面创建的doc对象中添加了三个字段,分别为name,sex,dosomething,
Document doc = new Document();
/*
* 参数说明 public Field(String name, String value, FieldType type)
* name : 字段名称
* value : 字段的值 store :
* TextField.TYPE_STORED:存储字段值
*/
doc.add(new Field("name", "lin zhengle", TextField.TYPE_STORED));
doc.add(new Field("address", "中国上海", TextField.TYPE_STORED));
doc.add(new Field("dosometing", "I am learning lucene ",TextField.TYPE_STORED));
writer.addDocument(doc);
writer.close(); // 这里可以提前关闭,因为dictory 写入内存之后 与IndexWriter 没有任何关系了
// 因为索引放在内存中,所以存放进去之后要立马测试,否则,关闭应用程序之后就检索不到了
// 创建IndexSearcher 检索索引的对象,里面要传递上面写入的内存目录对象directory
DirectoryReader ireader = DirectoryReader.open(directory);
IndexSearcher searcher = new IndexSearcher(ireader);
// 根据搜索关键字 封装一个term组合对象,然后封装成Query查询对象
// dosometing是上面定义的字段,lucene是检索的关键字
Query query = new TermQuery(new Term("dosometing", "lucene"));
// Query query = new TermQuery(new Term("address", "中国上海"));
// Query query = new TermQuery(new Term("name", "cheng"));
// 去索引目录中查询,返回的是TopDocs对象,里面存放的就是上面放的document文档对象
TopDocs rs = searcher.search(query, 100);
long endTime = System.currentTimeMillis();
System.out.println("总共花费" + (endTime - startTime) + "毫秒,检索到" + rs.totalHits + "条记录。");
for (int i = 0; i < rs.scoreDocs.length; i++) {
// rs.scoreDocs[i].doc 是获取索引中的标志位id, 从0开始记录
Document firstHit = searcher.doc(rs.scoreDocs[i].doc);
System.out.println("name:" + firstHit.getField("name").stringValue());
System.out.println("address:" + firstHit.getField("address").stringValue());
System.out.println("dosomething:" + firstHit.getField("dosometing").stringValue());
}
writer.close();
directory.close();
System.out.println("*****************检索结束**********************");
}
}
正常运行便能看到所放入的数据,但lucene原生带的分词器.不能够支持中文组词分词,只能够支持单字分词.因此我们若要用到中文分词器的话.就需要更高级的分词器来实现