Lucene全文检索学习笔记
全文索引 介绍Lucene的作者:Lucene的贡献者Doug Cutting是 一位资深全文索引/检索专家,曾经是V-Twin搜索引擎(Apple的Copland操作系统的成就之一)的主要开发者,后在Excite担任高级系统架构设计师,目前从事于一些INTERNET底层架构的研究。他贡献出的Lucene的目标是为各种中小型应用程序加入全文检索功能。原理lucene的检索算法属于索引检索,即用空间来换取时间,对需要检索的文件、字符流进行全文索引,在检索的时候对索引进行快速的检索,得到检索位置,这个位置记录检索词出现的文件路径或者某个关键词。
在使用数据库的项目中,不使用数据库进行检索的原因主要是:数据库在非精确查询的时候使用查询语言“like %keyword%”,对数据库进行查询是对所有记录遍历,并对字段进行“%keyword%”匹配,在数据库的数据庞大以及某个字段存储的数据量庞大的时候,这种遍历是致命的,它需要对所有的记录进行匹配查询。因此,lucene主要适用于文档集的全文检索,以及海量数据库的模糊检索,特别是对数据库的xml或者大数据的字符类型。
一、 搭建环境
a) 导包:
- IKAnalyzer3.2.0Stable.jar //中文分词器
- lucene-analyzers-3.0.1.jar //英文分词器
- lucene-core-3.0.1.jar //核心包
- lucene-highlighter-3.0.1.jar //关键字高亮显示
- lucene-memory-3.0.1.jar //缓存机制
二、 建立索引
a) 步骤:
- 创建索引的javaBean类文件,如Article.java
- 创建全文检索库,Directory directory = FSDirectory.open(new File("./indexDir"));
- 创建分词器,Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);//在这里使用的是Lucene自带的分词器,也可以使用上面的IKAnalyzer中文分词
- 创建IndexWriter对象,IndexWriter indexWriter = new IndexWriter(directory, analyzer, MaxFieldLength.UNLIMITED);
- 创建Document对象,Document document = new Document();
- 将Article对象转换为Document对象,Field idField = new Field("id", article.getId().toString(), Store.YES, Index.NOT_ANALYZED);
- 将Field添加到Document中,document.add(idField);
- 将Document对象写入到索引库中,indexWriter.addDocument(document);
- 最后,切记关闭IndexWriter对象,否则会产生一个锁文件,导致下面无法执行。indexWriter.close();
三、 如何删除索引
a) 步骤:
- lucene提供了两种从索引中删除document的方法,一种是void deleteDocument(int docNum)这种方法是根据document在索引中的编号来删除,每个document加进索引后都会有个唯一编号,所以根据编号删除是一种精确删除,但是这个编号是索引的内部结构,一般我们不会知道某个文件的编号到底是几,所以用处不大。另一种是void deleteDocuments(Term term)这种方法实际上是首先根据参数term执行一个搜索操作,然后把搜索到的结果批量删除了。我们可以通过这个方法提供一个严格的查询条件,达到删除指定document的目的。 下面给出一个例子:
Directory dir = FSDirectory.getDirectory(PATH, false);
IndexReader reader = IndexReader.open(dir);
Term term = new Term(field, key);
reader.deleteDocuments(term);
reader.close();
四、
更新索引
a) 步骤:
- lucene并没有提供专门的索引更新方法,我们需要先将相应的document删除,然后再将新的document加入索引。例如:
Directory dir = FSDirectory.getDirectory(PATH, false);
IndexReader reader = IndexReader.open(dir);
Term term = new Term(“title”, “lucene introduction”);
reader.deleteDocuments(term);
reader.close();
IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(), true);
Document doc = new Document();
doc.add(new Field("title", "lucene introduction",
Field.Store.YES, Field.Index.TOKENIZED));
doc.add(new Field("content", "lucene is funny",
Field.Store.YES, Field.Index.TOKENIZED));
writer.addDocument(doc);
writer.optimize();
writer.close();
五、 根据关键字进行搜索
a) 步骤:
- 创建全文检索库,Directory directory =
FSDirectory.open(new File("./indexDir")); - 创建IndexSearcher对象,IndexSearcher indexSearcher = new
IndexSearcher(directory); - 创建分词器,Analyzer analyzer = new
StandardAnalyzer(Version.LUCENE_30);//在这里使用的是Lucene自带的分词器,也可以使用上面的IKAnalyzer中文分词 - 创建QueryParser对象,QueryParser queryParser = new
QueryParser(Version.LUCENE_30, "title", analyzer); - 创建Query对象,Query
query = queryParser.parse("lucene");//lucene为关键词 - 获取查询对象:
- TopDocs topDocs =
indexSearcher.search(query, 10); - int count =
topDocs.totalHits;// 总的记录数 - ScoreDoc[] scoreDocs =
topDocs.scoreDocs; - For循环遍历scoreDocs数组,将查询出来的每一个Document对象转换为Article对象,并装进List集合中。
- 关闭IndexSearcher对象
- TopDocs topDocs =
六、 分页处理
a) 步骤:
- 通过两个参数来实现Lucene的分页处理,一个是:开始的记录,二是:每页显示的记录条数。
- 在Lucene中每次查询都是全部检索,所以可以通过这个方法获取总记录数,然后用每页显示的条件将其进行分开。int count = topDocs.totalHits;// 总的记录数
- 如:每页显示5条,索引从0开始,现在要查询第二页,那就是从第5开始到第9条数据。具体写法:
for (int i = startResult; i < len; i++) {}
七、 高亮显示
a) 步骤:
- 在进行了查询以后,开始配置高亮器TopDocs topDocs =
indexSearcher.search(query, 25); - 在关键字的前后加前缀和后缀,用于使关键词变色Formatter formatter = new
SimpleHTMLFormatter("<font
color='red'>","</font>"); - 封装了关键字Scorer scorer = new QueryScorer(query);
- Highlighter highlighter =
new Highlighter(formatter,scorer); //摘要 - Fragmenter fragmenter =
new SimpleFragmenter(5); - highlighter.setTextFragmenter(fragmenter);
- 在循环scoreDocs中为关键字进行高亮String text = highlighter.getBestFragment(LuceneUtils.analyzer,
"title",document.get("title")); - 如果高亮完成则会返回高亮后的字符串,如果不成功则会返回Null
八、 Lucene优化
介绍:
Lucene 会为每一次addDocument(document) 是在索引库目录下新增一个文件".cfs"后缀的文件。这意味我们的程序将便对越来越多的文件(但是默认情况下,最多也不会超过10个,当文件达到10个的时候,lucene 会将它们合并为一个大的文件)。意味着 IO 流的打开和关闭也将越来越多。这对效率的影响是比较大的。
方式是调用 IndexWriter 的 IndexWriter.optimize() 或 indexWriter.setMergeFactor(int),IndexWriter.optimize() 被调用后,lucene 会立即将索引库目录下所有 ".cfs" 后缀的文件合并为一个大的文件。但是它的数据是不会改变的。indexWriter.setMergeFactor(int) 接收一个整型参数表示当 ".cfs" 文件达到多少数量时就自动合并。
a) 具体信息:
- 调用commit方法,会生成一个.cfs文件,调用一次生成一个。
- 单独调用optimize()方法,会额外生成一个合并了多个.cfs文件的大.cfs文件,此时如果不close(),则索引文件大小翻倍。单独close()方法无效。
- 添加文档后,手动GC一次,内存释放快。
- 设置合并因子,根据.cfs文件个数合并。
- 添加一次document则消耗一定内存,然后释放,内存回升。
- 不进行提交操作,内存逐渐增长,若进行提交且内存占用多,则一次性回升大,然后降低至最低。
- 暂时未发现改变内存缓冲大小setRAMBufferSizeMB对索引性能的影响。
- 如果合并索引文件,则剩余的碎片会在commit或者是close之后自动删除。
- 合并式的索引效率没有提交式的索引效率高。
- 加载索引,首先读入段信息,然后看一下有几个段:如果只有一个,那么可能是优化过的,直接读取这一个段就可以;否则需要一次读入各个段,然后再拼成一个MultiReader。
- 增强索引的实时性,利用内存索引存放document一段时间,然后写入磁盘索引。搜索的时候提供内存跟磁盘索引多级目录。合并的时候,需要创建第三个索引,用于存放新增加的document,搜索时需要遍历这三个索引。
- 分布式的处理, 需要将相应的类,按照同样的路径打包,否则出现问题。
- 分布式的注册类,实现UnicastRemoteObject类后就不需要专门生成RMI类。
- 采用多线程,对每一个线程都有一个对应的文档集处理对象,因此可以并行的进行索引,虽然对文档的处理过程可以并行,但是将文档写入索引文件却必须串行进行。
- setMergeFactor设置lucene的合并参数,可以由setMaxMergeDocs来控制一个.cfs文件里面的document个数,如果超过了,则合并因子失效了。
- 所谓的优化就是对整个目录内未合并的segment进行的合并。同设置合并因子之后的合并。
Lucene全文检索学习笔记的更多相关文章
- Lucene基础学习笔记
在学校和老师一起做项目,在老师的推荐下深入学习了一些SqlServer的知识,看一些书下来哎也没记住多少,不过带来了新疑问. 不使用模糊查询,我应该用什么呢?如何能不影响数据库性能,还能做模糊查询呢? ...
- 全文检索学习历程目录结构(Lucene、ElasticSearch)
1.目录 (1) Apache Lucene(全文检索引擎)—创建索引:http://www.cnblogs.com/hanyinglong/p/5387816.html (2) Apache Luc ...
- Lucene学习笔记
师兄推荐我学习Lucene这门技术,用了两天时间,大概整理了一下相关知识点. 一.什么是Lucene Lucene即全文检索.全文检索是计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明 ...
- Lucene学习笔记(更新)
1.Lucene学习笔记 http://www.cnblogs.com/hanganglin/articles/3453415.html
- Lucene学习笔记1(V7.1)
Lucene是一个搜索类库,solr.nutch和elasticsearch都是基于Lucene.个人感觉学习高级搜索引擎应用程序之前 有必要了解Lucene. 开发环境:idea maven spr ...
- lucene学习笔记(四)lucene分词详解
分词器的核心类 Analyzer SimpleAnalyzer StopAnalyzer WhitespaceAnalyzer StandardAnalyzer TokenStream 分词器做好处理 ...
- Elasticsearch学习笔记一
Elasticsearch Elasticsearch(以下简称ES)是一款Java语言开发的基于Lucene的高效全文搜索引擎.它提供了一个分布式多用户能力的基于RESTful web接口的全文搜索 ...
- ElasticSearch学习笔记(超详细)
文章目录 初识ElasticSearch 什么是ElasticSearch ElasticSearch特点 ElasticSearch用途 ElasticSearch底层实现 ElasticSearc ...
- 【转载】Java学习笔记
转载:博主主页 博主的其他笔记汇总 : 学习数据结构与算法,学习笔记会持续更新: <恋上数据结构与算法> 学习Java虚拟机,学习笔记会持续更新: <Java虚拟机> 学习Ja ...
随机推荐
- thinkphp增删改查
添加数据: (添加单行数据) // 添加成功返回1,失败返回0 (添加多行数据) // 返回添加数据的条数 删除数据: 修改数据: (修改单个字段) (修改多个字段) // 修改成功返回1,失败返回0 ...
- Yii 2.0 数据库操作总结
1. 概述 操作数据库有2种方式: DAO(data access object),不安全 ORM(onject relational mapping) 2. DAO Yii::app()->d ...
- 设置Intel网卡以抓取报文的vlan tag
一.实验环境 1.ThinkPad T450 Notebook 2.Notebook网卡Intel I218-V 二.设置步骤 1."设备管理器" -> "Inte ...
- HDU1411 欧拉四面体
用向量解决: 三角形面积:S=1/2*|x1*y2-x2*y1|; (粗体表示向量) 三棱锥体积:V=1/6*(OA*OB)*OC 不知道哪里去找的代码,毕竟很线性代数矩阵什么的很头疼,晚上 ...
- 【转载】使用CSS将图片转换成黑白(灰色、置灰)
文章转载自 张鑫旭-鑫空间-鑫生活 http://www.zhangxinxu.com/ 原文链接:http://www.zhangxinxu.com/wordpress/?p=2547原文摘要: . ...
- Pycharm小技巧--使用正则进行查找和批量替换
分享一个Pycharm中使用正则的分组匹配来进行批量替换的小技巧 例如,我现在需要把HTML文件中的静态文件得到路径全部替换为django模板引用路径的格式 修改为类似这样的格式: {% static ...
- YYHS-NOIP模拟赛-gcd
题解 这道题题解里说用莫比乌斯反演做(我这个蒟蒻怎么会做呢) 但是不会,所以我们另想方法,这里我们用容斥来做 我们先把500000以内的所有质数筛出来 每次读入编号的时候,先把编号对应的这个数分解质因 ...
- Spring装配Bean之组件扫描和自动装配
Spring从两个角度来实现自动化装配: 组件扫描:Spring会自动发现应用上下文中所创建的bean. 自动装配:Spring自动满足bean之间的依赖. 案例:音响系统的组件.首先为CD创建Com ...
- “华尔街之狼”:ICO是“史上最大骗局”
勘探船进村的那个夏季,父亲从城里带回了那把手电.手电的金属外壳镀了镍,看上去和摸起来一样冰凉.父亲进城以前采了两筐枸杞子,他用它们换回了那把锃亮的东西.父亲一个人哼着<十八摸>上路,鲜红透 ...
- 【转】认识物理I/O构件- 主机I/O总线
在数据离开系统内存总线后,它通常传输到另一条总线,即主机I/O总线.在今天的产品中,最常见的主机I/O总线是PCI总线,但也存在着几种其他的总线,如S -总线,EIS A总线及VME总线.主机I/O总 ...