Lucene入门学习二
一)索引库优化
1.1 什么是索引库
索引库是Lucene的重要的存储结构,它包括二部份:原始记录表,词汇表
原始记录表:存放的是原始记录信息,Lucene为存入的内容分配一个唯一的编号(编号是由Lucene分配的,并非document对象id)
词汇表:存放的是经过分词器拆分出来的词汇和该词汇在原始记录表中的编号
1.2 为什么要将索引库进行优化
在默认情况下,向索引库中增加一个Document对象时,索引库自动会添加一个扩展名叫*.cfs的二进制压缩文件,如果向索引库中存Document对象过多,那么*.cfs也会不断增加,同时索引库的容量也会不断增加,影响索引库的大小。lucene默认是10个自动合并。
1.3索引优化方案
1.3.1 合并cfs文件
indexWriter.addDocument(document);
indexWriter.optimize(); //每2个合并
indexWriter.setMergeFactor(3);//设置每3个合并
indexWriter.close();
1.3.2 使用RAMDirectory,类似于内存索引库,能解决是的读取索引库文件的速度问题,它能以空换时,提高速度快,但不能持久保存,因此启动时加载硬盘中的索引库到内存中的索引库,退出时将内存中的索引库保存到硬盘中的索引库,且内容不能重复.
public void ramDB() throws Exception{
Article article = new Article(1,"java","面向对象的编程语言");
Document document = LuceneUtil.java2Document(article);
//硬盘索引库
Directory fsDirectory = FSDirectory.open(new File("E:/DBDB"));
//内存索引库,因为硬盘索引库的内容要同步到内存索引库中
Directory ramDirectory = new RAMDirectory(fsDirectory);
//指向硬盘索引库的字符流,true表示如果内存索引库中和硬盘索引库中的相同的document对象时,先删除硬盘索引库中的document对象,
//再将内存索引库的document对象写入硬盘索引库中
//反之是false,默认为false,这个boolean值写在硬盘字符流的构造器
IndexWriter fsIndexWriter = new IndexWriter(fsDirectory,LuceneUtil.getAnalayzer(),true,LuceneUtil.getMaxFieldLength());
//指向内存索引库的字符流
IndexWriter ramIndexWriter = new IndexWriter(ramDirectory,LuceneUtil.getAnalayzer(),LuceneUtil.getMaxFieldLength());
//将document对象写入内存索引库
ramIndexWriter.addDocument(document);
ramIndexWriter.close();
//将内存索引库的所有document对象同步到硬盘索引库中
fsIndexWriter.addIndexesNoOptimize(ramDirectory);
fsIndexWriter.close();
}
二)分词器
2.1 什么是分词器
采用一种算法,将中英文本中的字符拆分开来,形成词汇,以待用户输入关健字后搜索
2.2 为什么要分词器
因为用户输入的搜索的内容是一段文本中的一个关健字,和原始表中的内容有差别,但作为搜索引擎来讲,又得将相关的内容搜索出来,此时就得采用分词器来最大限度匹配原始表中的内容
2.3 分词器工作流程
步一:按分词器拆分出词汇
步二:去除停用词和禁用词
步三:如果有英文,把英文字母转为小写,即搜索不分大小
2.4 查看分词器的分词结果,可以用以下代码测试
public static void testAnalyzer(Analyzer analyzer, String text) throws Exception {
System.out.println("当前使用的分词器:" + analyzer.getClass());
TokenStream tokenStream = analyzer.tokenStream("content",new StringReader(text));
tokenStream.addAttribute(TermAttribute.class);
while (tokenStream.incrementToken()) {
TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);
System.out.println(termAttribute.term());
}
}
public static void main(String[] args) throws Exception {
testAnalyzer(new StandardAnalyzer(Version.LUCENE_30), "java是一门面向对象的编程语言");
}
Analyzer的实现类有二十多种,CTRL+T查看,有兴趣可以尝试去测试,其中StandardAnalyzer中文对每个字分词,FrenchAnalyzer支持中英文分词的检索,CJKAnalyzer中文每二个字分词。
2.5 使用第三方IKAnalyzer分词器——–中文首选
步一:导入IKAnalyzer分词器核心jar包,IKAnalyzer3.2.0Stable.jar
步二:将IKAnalyzer.cfg.xml和ext_stopword.dic(敏感词)和xxx.dic文件复制到Eclipse的src目录下,
IKAnalyzer.cfg.xml配置示例如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>IK Analyzer 扩展配置</comment>
<!-- 用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">/mydict.dic</entry>
<!--用户可以在这里配置自己的扩展停止词字典
<entry key="ext_stopwords">/ext_stopword.dic</entry>
-->
</properties>
当有多个dic文件时,用;隔开即可,mydict.dic配置示例如下:
java
是一门
面向对象
的
编程语言
可以根据自己的需求随意配置,利用以下代码测试:
public static void main(String[] args) throws Exception {
testAnalyzer(new IKAnalyzer(), "java是一门面向对象的编程语言");
}
分词结果显示:
当前使用的分词器:class org.wltea.analyzer.lucene.IKAnalyzer
java
是一门
一门
一
门面
门
面向对象
面向
对象
的
编程语言
编程
语言
三)搜索结果高亮
像google、baidu一样,在搜索结果中,将与关键字相同的字符用红色显示
public void highLight() throws Exception {
String keywords = "培训";
List<Article> articleList = new ArrayList<Article>();
QueryParser queryParser = new QueryParser(LuceneUtil.getVersion(),"content" , LuceneUtil.getAnalayzer());
Query query = queryParser.parse(keywords);
IndexSearcher indexSearcher = new IndexSearcher(LuceneUtil.getDirectory());
TopDocs topDocs = indexSearcher.search(query, 100); //显示前100条数据
//以下代码对内容中含有关键字的字符串高亮显示
//格式对象
Formatter formatter = new SimpleHTMLFormatter("<font color='red'","</font>");
//关键字对象
Scorer scorer = new QueryScorer(query);
//高亮对象
Highlighter highlighter = new Highlighter(formatter,scorer);
for(int i=0;i<topDocs.scoreDocs.length;i++){
ScoreDoc scoreDoc = topDocs.scoreDocs[i];
int doc = scoreDoc.doc;
float score = scoreDoc.score;
Document document = indexSearcher.doc(doc);
//将title属性和content属性中的关键字高亮
String titleHighlighter = highlighter.getBestFragment(LuceneUtil.getAnalayzer(),"title",document.get("title"));
String contentHighlighter = highlighter.getBestFragment(LuceneUtil.getAnalayzer(),"content",document.get("content"));
//将高亮后的结果再次封装到document对象中
document.getField("title").setValue(titleHighlighter);
document.getField("content").setValue(contentHighlighter);
Article article = (Article) LuceneUtil.document2Java(document, Article.class);
articleList.add(article);
}
for(Article a : articleList){
System.out.println(a);
}
}
将打印出的结果复制进html文件,用浏览器打开即可看到效果。
搜索结果摘要:如果搜索结果内容太多,我们只想显示前几个字符
Fragmenter fragmenter = new SimpleFragmenter(4);//设置显示的字符数
highlighter.setTextFragmenter(fragmenter);
四)搜索结果排序
4.1 什么是搜索结果排序
搜索结果是按某个或某些字段高低排序来显示的结果
4.2 影响网站排名的先后的有多种
head/meta/
网页的标签整洁
网页执行速度
采用div+css
...............
4.3 Lucene中的显示结果次序与相关度得分有关
ScoreDoc.score
默认情况下,Lucene是按相关度得分排序的,得分高排在前,得分低排在后
如果相关度得分相同,按插入索引库的先后次序排序
document.setBoost(20F); //人工设置document得分
单字段或多字段排序
//创建排序对象
//参数一:id表示依据document对象中的哪个字段排序,例如:id
//参数二:SortField.INT表示document对象中该字段的类型,以常量方式书写
//参数三:true表示降序,类似于order by id desc
//参数三:false表示升序,类似于order by id asc
//单字段排序
Sort sort = new Sort(new SortField("id",SortField.INT,false));
//按count字段的降序排列,如果count字段相同的话,再按id的升序排序
Sort sort = new Sort(
new SortField("count",SortField.INT,true),
new SortField("id",SortField.INT,false));
//sort表示排序的条件
TopDocs topDocs = indexSearcher.search(query,null,100,sort);
五) 条件搜索
5.1 什么是条件搜索
用关健字与指定的单列或多例进行匹配的搜索
5.2 单字段条件搜索
QueryParser queryParser = new QueryParser(LuceneUtil.getVersion(),"content",LuceneUtil.getAnalayzer());
5.3 多字段条件搜索,项目中提倡多字段搜索
QueryParser queryParser = new MultiFieldQueryParser(LuceneUtil.getVersion(),new String[]{"content","title"},LuceneUtil.getAnalayzer());
下一篇: 解析XML文件时的乱码问题