这篇文章主要写一下中文分词以及高亮显示的案例
针对lucene的 增删改查我单独写了两篇文件,供参考,如下:
lucene官网 http://lucene.apache.org
关于中文分词及高亮显示还需要额外再引入两个maven依赖,
我先把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>
<!-- 中文分词器 -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-smartcn</artifactId>
<version>5.3.1</version>
</dependency>
<!-- 高亮显示 -->
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-highlighter</artifactId>
<version>5.3.1</version>
</dependency>
一、中文分词代码段
//创建中文分词器
SmartChineseAnalyzer analyzer=new SmartChineseAnalyzer();
二、高亮显示代段
/*
* 创建 QueryScorer 实例
* QueryScorer主要是对命中结果进行评分操作
* 比如一篇很长的文章,通过关键次搜素后需要展示一部分片段摘要信息,
* 这时候就需要这个评分器,对文中判断进行评分,最后将评分高的片段显示
*/
QueryScorer scorer=new QueryScorer(query);
/*
* 创建 Fragmenter实例
* Fragmenter 通过评分器将原始字符串拆分成独立的片段
*/
Fragmenter fragmenter=new SimpleSpanFragmenter(scorer);
/* 创建 SimpleHTMLFormatter 实例
* 这是常用的格式化Html标签器,提供一个构造函数传入高亮颜色标签,默认使用黑色
* 第一个参数为在关键词前面加的内容,第二个则是在关键词后面加内容的参数
* 如 第一个参数为 <b><font color='red'> , 第二个参数为</font></b>
* 假设关键词为 测试 那么输出后为 <b><font color='red'>测试</font></b>
* 这样就可以自己设置需要的高亮样式
*/
SimpleHTMLFormatter simpleHTMLFormatter=new SimpleHTMLFormatter("<b><font color='red'>","</font></b>");
/*
* 创建 Highlighter实例
* Highlighter主要负责获取匹配上的高亮片段
*/
Highlighter highlighter=new Highlighter(simpleHTMLFormatter, scorer);
highlighter.setTextFragmenter(fragmenter);
/*
* 创建 TokenStream实例
* TokenStream主要提供静态方法,支持从数据源中获取TokenStream,进行token处理
*/
TokenStream tokenStream=analyzer.tokenStream("desc", new StringReader(centent));
//获取评分后的高亮片段,并重新复制给centent
centent = highlighter.getBestFragment(tokenStream, centent);
上面是我针对这两个功能单独写出来的代码段,方便比较
下面我把整个代码全部贴出来把,如下:
package luceneDemo;
import java.io.IOException;
import java.io.StringReader;
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.cn.smart.SmartChineseAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.IntField;
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.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.search.highlight.Fragmenter;
import org.apache.lucene.search.highlight.Highlighter;
import org.apache.lucene.search.highlight.QueryScorer;
import org.apache.lucene.search.highlight.SimpleHTMLFormatter;
import org.apache.lucene.search.highlight.SimpleSpanFragmenter;
import org.apache.lucene.analysis.TokenStream;
/**
* 全文检索案例
* @author mszhou
*/
public class luceneDemo {
/**
* 将数据写入索引文件中(这里使用的是中文分词器)
* 这里演示写入数据到索引中,在项目中我们会定时将数据写入索引文件中,
* 然后在索引文件中进行搜索,这样比在数据库中搜索效率高的多,
* 而且检索远比数据库的模糊匹配强大的多,这也是检索工具牛逼之处
*
* 需要注意的是,如果在项目中定时写入索引,
* 需要判断下该数据是否存在,存在则修改,不存在再进行新增
*
* @param luceneDir 该参数表示索引所存放的目录
*/
public static void writeIndex(String luceneDir){
IndexWriter writer = null;//声明创建索引写入器
try{
//创建索引目录 , 这里参数luceneDir 表示索引存放目录
Directory dir=FSDirectory.open(Paths.get(luceneDir));
//创建标准分词器(一般英文使用这个,不适合中文使用)改用下面的中文分词器
//Analyzer analyzer=new StandardAnalyzer();
//创建中文分词器(中文需要使用该分词器)
SmartChineseAnalyzer analyzer=new SmartChineseAnalyzer();
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("title", "小说标题的撒啊啊");//表示标题字段
map1.put("centent", "这是小说内容,我就随便写了 受到收到的市场 是否是啊啥就卡 ");//表示标题字段
list.add(map1);
//假数据2
Map<String,String> map2 =new HashMap<String, String>();
map2.put("title", "介绍小说");//表示标题字段
map2.put("centent", "以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。人物、情节、环境是小说的三要素。情节一般包括开端、发展、高潮、结局四部分,有的包括序幕、尾声。环境包括自然环境和社会环境。 小说按照篇幅及容量可分为长篇、中篇、短篇和微型小说(小小说)。按照表现的内容可分为神话、科幻、公案、传奇、武侠、言情、同人、官宦等。按照体制可分为章回体小说、日记体小说、书信体小说、自传体小说。按照语言形式可分为文言小说和白话小说。");//表示标题字段
list.add(map2);
//假数据1
Map<String,String> map3 =new HashMap<String, String>();
map3.put("title", "demo 12i131s ss");//表示标题字段
map3.put("centent", "hdaiads sd s g r44e r hgg f hd 4 ");//表示标题字段
list.add(map3);
//=== 这里造一些数据用作演示,也可以直接读取数据库中的数据 结束========
//遍历数据,并且将数据写入到索引中
for(int i=0 ;i<list.size();i++){
// ====== 获取数据开始 ======
Map<String,String> mapCen=list.get(i);
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 IntField("id", i, Field.Store.YES));
/*添加标题数据,最后面Field.Store.YES 表示存储该字段
*注意:如果需要检索该字段,建议使用TextField类型,并且设置为 Field.Store.YES
*/
doc.add(new TextField("title",title , Field.Store.YES));
/*
* 添加标题内容数据,最后面Field.Store.YES 表示存储该字段
* 如果为 Field.Store.NO 表示不存储
*/
doc.add(new TextField("centent", centent, Field.Store.YES));
// 写入索引
writer.addDocument(doc);
//========= 将数据写入索引结束 =================
}
}catch(Exception e){
System.out.println("发生了异常!");
e.printStackTrace();
}finally{
try {
writer.close();//关闭流,一定要记得关闭
} catch (IOException e) {
}
}
}
/**
* 检索匹配一下内容centent字段的数据,并高亮显示
* (这里使用的是中文分词器)
* @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();
//创建中文分词器(中文需要使用该分词器),这里使用中文分词器
SmartChineseAnalyzer analyzer=new SmartChineseAnalyzer();
//创建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 title = doc.get("title").toString();//获取标题
String centent = doc.get("centent").toString();//获取内容
//判断下为空的情况
if(centent==null || "".equals(centent)){
return ;
}
//==============================================
//===== 对centen字段数据搜素关键词高亮显示=====
//==============================================
/*
* 创建 QueryScorer 实例
* QueryScorer主要是对命中结果进行评分操作
* 比如一篇很长的文章,通过关键次搜素后需要展示一部分片段摘要信息,
* 这时候就需要这个评分器,对文中判断进行评分,最后将评分高的片段显示
*/
QueryScorer scorer=new QueryScorer(query);
/*
* 创建 Fragmenter实例
* Fragmenter 通过评分器将原始字符串拆分成独立的片段
*/
Fragmenter fragmenter=new SimpleSpanFragmenter(scorer);
/* 创建 SimpleHTMLFormatter 实例
* 这是常用的格式化Html标签器,提供一个构造函数传入高亮颜色标签,默认使用黑色
* 第一个参数为在关键词前面加的内容,第二个则是在关键词后面加内容的参数
* 如 第一个参数为 <b><font color='red'> , 第二个参数为</font></b>
* 假设关键词为 测试 那么输出后为 <b><font color='red'>测试</font></b>
* 这样就可以自己设置需要的高亮样式
*/
SimpleHTMLFormatter simpleHTMLFormatter=new SimpleHTMLFormatter("<b><font color='red'>","</font></b>");
/*
* 创建 Highlighter实例
* Highlighter主要负责获取匹配上的高亮片段
*/
Highlighter highlighter=new Highlighter(simpleHTMLFormatter, scorer);
highlighter.setTextFragmenter(fragmenter);
/*
* 创建 TokenStream实例
* TokenStream主要提供静态方法,支持从数据源中获取TokenStream,进行token处理
*/
TokenStream tokenStream=analyzer.tokenStream("desc", new StringReader(centent));
//获取评分后的高亮片段,并重新复制给centent
centent = highlighter.getBestFragment(tokenStream, centent);
System.out.println("title是:"+title+" ,centent是:"+centent);//输出
//==============================================
//==== 对centen字段数据搜素关键词高亮结束======
//==============================================
}
}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);
//检索并高亮显示
search(luceneDir,"小说");
}
}