针对lucene全文检索引擎写一个简单的增删改的案例
这里采用的是英文分词,单独写了一篇关于中文分词与高亮显示,如下:
lucene全文检索之 中文分词 以及 高亮显示,点击进入
lucene官网 http://lucene.apache.org
首先需要引入lucene的maven依赖,如下:
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
<version>5.3.1</version>
</dependency>
然后就可以开始了,代码如下:
package luceneDemo;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.Directory;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
/**
* 全文检索案例
* @author mszhou
*/
public class luceneTest {
/**
* 演示将数据写入索引文件中
* 在项目中我们会定时将数据写入索引文件中,
* 然后在索引文件中进行搜索,这样比在数据库中搜索效率高的多,
* 而且检索远比数据库的模糊匹配强大的多,这也是检索工具牛逼之处
* 需要注意的是,如果在项目中定时写入索引,
* 需要判断下该数据是否存在,存在则修改,不存在再进行新增
*
* @param luceneDir 该参数表示索引所存放的目录
*/
public static void writeIndex(String luceneDir){
IndexWriter writer = null;//声明创建索引写入器
try{
//创建索引目录 , 这里参数luceneDir 表示索引存放目录
Directory dir=FSDirectory.open(Paths.get(luceneDir));
//创建标准分词器(一般英文使用这个,不适合中文使用)
Analyzer analyzer=new StandardAnalyzer(); // 标准分词器
IndexWriterConfig iwc=new IndexWriterConfig(analyzer);
//创建索引写入器实例,通过IndexWriterConfig设置相关配置
writer=new IndexWriter(dir, iwc);
//=== 这里造一些数据用作演示,也可以直接读取数据库中的数据 开始========
List <Map<String,String>> list=new ArrayList<Map<String,String>>();
//假数据1
Map<String,String> map1 =new HashMap<String, String>();
map1.put("id", "1");//表示id字段,这里id用String类型了,大家可以用int
map1.put("title", "weejij dasa ");//表示标题字段
map1.put("centent", "hdaiads sd s g r44e r hgg f hd 4 ");//表示标题字段
list.add(map1);
//假数据2
Map<String,String> map2 =new HashMap<String, String>();
map2.put("id", "2");//表示id字段,这里id用String类型了,大家可以用int
map2.put("title", "demo is ss");//表示标题字段
map2.put("centent", "hdaiads sd s g r44e r hgg f hd 4 ");//表示标题字段
list.add(map2);
//假数据1
Map<String,String> map3 =new HashMap<String, String>();
map3.put("id", "3");//表示id字段,这里id用String类型了,大家可以用int
map3.put("title", "demo is ss");//表示标题字段
map3.put("centent", "hdaiads sd s g r44e r hgg f hd 4 ");//表示标题字段
list.add(map3);
//=== 这里造一些数据用作演示,也可以直接读取数据库中的数据 结束========
//遍历数据,并且将数据写入到索引中
for(Map<String,String> mapCen : list){
// ====== 获取数据开始 ======
String id =mapCen.get("id").toString();//获取id
String title = mapCen.get("title").toString();//获取标题
String centent = mapCen.get("centent").toString();//获取内容
// ====== 获取数据结束 ======
//========= 将数据写入索引开始 =================
//创建Document对象,Document表示lucene索引的数据结构单元
Document doc=new Document();
//添加id 数据,最后面Field.Store.YES表示存储该字段
doc.add(new StringField("id",id, Field.Store.YES));
/*添加标题数据,最后面Field.Store.YES 表示存储该字段
*注意:如果需要检索该字段,建议使用TextField类型,并且设置为 Field.Store.YES
*/
doc.add(new TextField("title",title , Field.Store.YES));
//添加标题内容数据,最后面Field.Store.NO 表示不存储该字段
doc.add(new TextField("centent", centent, Field.Store.NO));
// 写入索引
writer.addDocument(doc);
//========= 将数据写入索引结束 =================
}
}catch(Exception e){
System.out.println("发生了异常!");
e.printStackTrace();
}finally{
try {
writer.close();//关闭流,一定要记得关闭
} catch (IOException e) {
}
}
}
/**
* 演示删除索引文档数据
*
* @param luceneDir 该参数表示索引所存放的目录
*/
public static void testDelete(String luceneDir){
IndexWriter writer = null;//声明创建索引写入器
try{
//创建索引目录 , 这里参数luceneDir 表示索引存放目录
Directory dir=FSDirectory.open(Paths.get(luceneDir));
//创建标准分词器(一般英文使用这个,不适合中文使用)
Analyzer analyzer=new StandardAnalyzer(); // 标准分词器
IndexWriterConfig iwc=new IndexWriterConfig(analyzer);
//创建索引写入器 ,通过IndexWriterConfig设置相关配置
writer=new IndexWriter(dir, iwc);
//打印索引实际文档数
System.out.println("删除前:"+writer.numDocs());
/*删除属性字段id为1的文档数据,就是上面写入的第一条测试数据,如下
* map1.put("id", "1");//表示id字段,这里id用String类型了,大家可以用int
* map1.put("title", "weejij dasa ");//表示标题字段
* map1.put("centent", "hdaiads sd s g r44e r hgg f hd 4 ");//表示标题字
*/
writer.deleteDocuments(new Term("id","1"));
/*
* 调用该方法强制已删除文档中的所有段合并,
* 需要注意的是如果不调用该方法,则删除后实际文件数还是跟删除之前的一样
* 因为还没有合并,在项目中如果数据量比较大,
* 我们可以定时调用该方法来强制合并删除的数据
*/
writer.forceMergeDeletes(); // 强制删除
writer.commit();//提交
//打印索引实际文档数
System.out.println("删除后:"+writer.numDocs());
}catch(Exception e){
System.out.println("发生了异常!");
e.printStackTrace();
}finally{
try {
writer.close();//关闭流,一定要记得关闭
} catch (IOException e) {
}
}
}
/**
* 演示更新索引文档数据
*
* @param luceneDir 该参数表示索引所存放的目录
*/
public static void testUpdate(String luceneDir){
IndexWriter writer = null;//声明创建索引写入器
try{
//创建索引目录 , 这里参数luceneDir 表示索引存放目录
Directory dir=FSDirectory.open(Paths.get(luceneDir));
//创建标准分词器(一般英文使用这个,不适合中文使用)
Analyzer analyzer=new StandardAnalyzer(); // 标准分词器
IndexWriterConfig iwc=new IndexWriterConfig(analyzer);
//创建索引写入器 ,通过IndexWriterConfig设置相关配置
writer=new IndexWriter(dir, iwc);
//========= 这里造一条需要更新的假数据开始============
Document doc=new Document();
//设置数据id 数据,最后面Field.Store.YES表示存储该字段
doc.add(new StringField("id", "2", Field.Store.YES));
//设置标题数据,最后面Field.Store.YES 表示存储该字段
doc.add(new StringField("title","dewef sdasa",Field.Store.YES));
//设置标题内容数据,最后面Field.Store.NO 表示不存储该字段
doc.add(new TextField("centent", "fdfds fdddf fs sa", Field.Store.NO));
//========= 这里造一条需要更新的假数据结束 ============
//更新属性字段id为2的文档数据,
writer.updateDocument(new Term("id","2"), doc);
}catch(Exception e){
System.out.println("发生了异常!");
e.printStackTrace();
}finally{
try {
writer.close();//关闭流,一定要记得关闭
} catch (IOException e) {
}
}
}
/**
* 演示获取索引文档的数量
* @param luceneDir 该参数表示索引所存放的目录
* @return 返回索引文档数量
*/
public static int getIndexCount(String luceneDir){
IndexWriter writer = null;//声明创建索引写入器
int count =0;//用看来保存索引文件的数量
try{
//创建索引目录 , 这里参数luceneDir 表示索引存放目录
Directory dir=FSDirectory.open(Paths.get(luceneDir));
//创建标准分词器(一般英文使用这个,不适合中文使用)
Analyzer analyzer=new StandardAnalyzer(); // 标准分词器
IndexWriterConfig iwc=new IndexWriterConfig(analyzer);
//创建索引写入器 ,通过IndexWriterConfig设置相关配置
writer=new IndexWriter(dir, iwc);
count = writer.numDocs();//获取索引文件的个数
System.out.println("有"+count+"个文档");
}catch(Exception e){
System.out.println("发生了异常!");
e.printStackTrace();
}finally{
try {
writer.close();//关闭流,一定要记得关闭
} catch (IOException e) {
}
}
return count;
}
/**
* 演示读取文档
* @param luceneDir 该参数表示索引所存放的目录
*/
public static void readerIndexCount(String luceneDir){
IndexReader reader = null;//声明索引读取器
try{
//创建索引目录 , 这里参数luceneDir 表示索引存放目录
Directory dir=FSDirectory.open(Paths.get(luceneDir));
//创建索引读取器
reader=DirectoryReader.open(dir);
//打印信息
System.out.println("最大文档数:"+reader.maxDoc());
System.out.println("实际文档数:"+reader.numDocs());
}catch(Exception e){
System.out.println("发生了异常!");
e.printStackTrace();
}finally{
try {
reader.close();//关闭流,一定要记得关闭
} catch (IOException e) {
}
}
}
/**
* 演示简单检索匹配一下标题title字段的数据
* @param luceneDir 该参数表示索引所存放的目录
* @param titleStr 需要检索的关键词
*/
public static void search(String luceneDir,String titleStr){
IndexReader reader = null;//声明索引读取器
try{
//创建索引目录 , 这里参数luceneDir 表示索引存放目录
Directory dir=FSDirectory.open(Paths.get(luceneDir));
//创建索引读取器
reader=DirectoryReader.open(dir);
//创建索引搜索器
IndexSearcher is=new IndexSearcher(reader);
//创建标准分词器(一般英文使用这个,不适合中文使用)
Analyzer analyzer=new StandardAnalyzer(); // 标准分词器
//创建QueryParser查询器,查询title属性字段
QueryParser parser=new QueryParser("title", analyzer);
//设置查询关键词
Query query=parser.parse(titleStr);
//这里查询前10条匹配的数据,第二个参数为10表示查前十条
TopDocs hits=is.search(query, 10);
//打印信息
System.out.println("匹配 "+titleStr+" , 查询到"+hits.totalHits+"个记录");
//遍历查询到的数据
for(ScoreDoc scoreDoc:hits.scoreDocs){
Document doc=is.doc(scoreDoc.doc);
String id = doc.get("id").toString();//获取id
String title = doc.get("title").toString();//获取标题
//由于写入的时候 ,设置了Field.Store.NO 表示不存储该字段,所以这里读取不到
//String centent = doc.get("centent").toString();//获取内容
//打印数据
System.out.println("id是:"+id+" ,标题是:"+title);
}
}catch(Exception e){
System.out.println("发生了异常!");
e.printStackTrace();
}finally{
try {
reader.close();//关闭流,一定要记得关闭
} catch (IOException e) {
}
}
}
/**
* 测试上面的方法
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//表示索引目录
String luceneDir = "D://lucene";
//测试该方法写入数据到索引文件中
//writeIndex(luceneDir);
//测试该方法获取索引文件数量
//int count = getIndexCount(luceneDir);
//测试该方法打印索引最大文档与实际文档数
//readerIndexCount(luceneDir);
//测试该方法删除索引文档数据
//testDelete(luceneDir);
//测试该方法更新索引文档数据
//testUpdate(luceneDir);
//测试该方法检索询
search(luceneDir,"demo");
}
}