19高级进阶版lucene全文检索老师什么是_第1页
19高级进阶版lucene全文检索老师什么是_第2页
19高级进阶版lucene全文检索老师什么是_第3页
19高级进阶版lucene全文检索老师什么是_第4页
19高级进阶版lucene全文检索老师什么是_第5页
已阅读5页,还剩173页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Lucene 的概述:1.1 什么是 lucene这是一篇很好的文章。下面便是取自这里。Lucene 是一个全文搜索框架,而不是应用。因此它并不像 或者Desktop 那么拿来就能用,它只是提供了一种工具让你能实现这些。1.2 lucene 能做什么要回答这个问题,先要了解 lucene 的本质。实际上 lucene 的功能很单一,说到底,就是你给它若干个字符串,然后它为你提供一个全文搜索服务,告诉你你要搜索的出现在哪里。知道了这个本质,你就可以发挥想象做任何符合这个条件的事情了。你可以把站内都索引了,做个资料库;你可以把一个数据库表的若干个字段索引起来,那就不用再担心因为“%like%”而锁

2、表了;你也可以写个的搜索引擎1.3 你该不该选择 lucene下面给出一些测试数据,如果你觉得可以接受,那么可以选择。测试一:250 万,300M 左右文本,生成索引 380M 左右,800 线程下平均处理时间 300ms。测试二:37000,索引数据库中的两个 varchar 字段,索引文件 2.6M,800 线程下平均处理时间 1.5ms。2 lucene 的工作方式lucene 提供的服务实际包含两部分:一入一出。所谓入是写入,即将你提供的源(本质是字符串)写入索引或者将其从索引中删除;所谓出是读出,即向用户提供全文搜索服务,让用户可以通过源。2.1 写入流程源字符串首先经过 analy

3、zer 处理,包括:分词,分成一个个单词;去除 stopword(可选)。将源中需要的信息加入 Document 的各个 Field 中,并把需要索引的 Field 索引起来,把需要的 Field起来。将索引写入器,器可以是内存或磁盘。2.2 读出流程用户提供搜索,经过 analyzer 处理。对处理后的搜索索引找出对应的 Document。用户根据需要从找到的 Document 中提取需要的 Field。3 一些需要知道的概念lucene 用到一些概念,了解它们的含义,有利于下面的讲解。3.1 analyzerAnalyzer 是分析器,它的作用是把一个字符串按某种规则划分成一个个词语,并去

4、除其中的无效词语,这里说的无效词语是指英文中的“ of”、 “the”,中文中的 “的”、“地”等词语,这些词语在文章中大量出现,但是本身不包含什么关键信息,去掉有利于缩小索引文件、提高效率、提高。分词的规则千变万化,但目的只有一个:按语义划分。这点在英文中比较容易实现,因为英文本身就是以单词为的,已经用空格;而中文则必须以某种方法将连成一片的句子划分成一个个词语。具体划分方法下面再详细介绍,这里只需了解分析器的概念即可。3.2 document用户提供的源是一条条,它们可以是文本文件、字符串或者数据库表的一条等等。一条经过索引之后,就是以一个 Document 的形式在索引文件中的。用户进行

5、搜索,也是以 Document 列表的形式返回。3.3 field一个 Document 可以包含多个信息域,例如一篇文章可以包含“标题”、“正文”、“最后修改时间”等信息域,这些信息域就是通过 Field 在 Document 中的。Field 有两个属性可选:和索引。通过属性你可以是否对这个Field 进行;通过索引属性你可以是否对该 Field 进行索引。这看起来似乎有些废话,事实上对这两个属性的正确组合很重要,下面举例说明:还是以刚才的文章为例子,我们需要对标题和正文进行全文搜索,所以我们要把索引属性设置为真,同时我们希望能直接从搜索结果中提取文章标题,所以我们把标题域的属性设置为真,

6、但是由于正文域太大了,我们为了缩小索引文件大小,将正文域的属性设置为假,当需要时再直接文件;我们只是希望能从搜索解果中提取最后修改时间,不需要对它进行搜索,所以我们把最后修改时间域的属性设置为真,索引属性设置为假。上面的三个域涵盖了两个属性的三种组合,还有一种全为没有用到,事实上 Field 不你那么设置,因为既不又不索引的域是没有意义的。3.4 termterm 是搜索的最小,它表示文档的一个词语, term 由两部分组成:它表示的词语和这个词语所出现的 field。3.5 tockentocken 是 term 的一次出现,它包含 trem 文本和相应的起止偏移,以及一个类型字符串。一句话

7、中可以出现多次相同的词语,它们都用同一个 term 表示,但是用不同的 tocken,每个 tocken 标记该词语出现的地方。3.6 segment添加索引时并不是每个 document 都马上添加到同一个索引文件,它们首先被写入到不同的小文件,然后再合并成一个大索引文件,这里每个小文件都是一个 segment。4 lucene 的结构lucene 包括 core 和 sandbox 两部分,其中 core 是 lucene 稳定的部分,sandbox 包含了一些附加功能,例如 highlighter、各种分析器。 Lucene core 有七个包:analysis,document,ind

8、ex,queryParser,search,store,util。对于 4.5 版本不是这 7 个包,而是如下:关于这些的详细介绍,后面再说。环境的准备:1.先开发的 jar 包: 我们把 zip 和 src下来就可以了。2. 对于开源的框架,一般使用都有 2 个步骤a) 添加 jar 包为了项目的可移植性,我们应该建立一个 lib 文件夹,专门放外部的 jar 包,然后把需要的 jar 包放入到这个目录,最后在进项目里面b) 配置文件3. 根据开档搭建环境a)先读 readme 文件,他会告诉你怎么用,告诉你这项目是什么b)再根据 a)的指导,相应的文件,也就是 docs/index.htm

9、lc)Index 只指导我们看 demon,于是只能网上搜索 demo 怎么用下面是 demon 的使用方法:我们按照这个做法做就是了(预告:最后没有找到怎么搭建工程的方法)i) 定义环境变量:CLASSPATH 的值如下:D:soft_framework_utileslucene-4.5.0lucene-4.5.0corelucene-core-4.5.0.jar;D:soft_framework_utileslucene-4.5.0lucene-4.5.0demolucene-demo-4.5.0.jar;D:soft_framework_utileslucene-4.5.0lucene-

10、4.5.0queryparserlucene-queryparser-4.5.0.jar;D:soft_framework_utileslucene-4.5.0lucene-4.5.0analysiscommonlucene-analyzers-common-4.5.0.jar;把这个 4 个 jar 放进去就是了。j) 开始测试 demonà建立索引java org.apache.lucene.demo.IndexFiles -indexindexfolder-docsdocs folder设置要生成的索引的文件夹和要的 docs我们的 doc 目录用:demolf_test_do

11、cs_dir生成的 index 目录用:demolf_test_index_dir下面就是执行过程:我们可以去看 index 目录的生成的文件:k) 开始测试 demonà执行java org.apache.lucene.demo.SearchFiles将会出现“Query:”提示符,在其后输入关键字,回车,即可得到结果由于 SearchFiles 是查找当前目录下面的 index 目录作为索引文件目录,所以这里报错了,我们可以用-index 参数指定我们的 index 目录:可以看到mozilla 得到 3 个文档有这个关键字。4. 到教学的东西,那么我们就查资料吧,下面是做法需要

12、的 jar 包是:Ølucene-core-4.5.0.jar包Ølucene-analyzers-common-4.5.0.jar分词器Ølucene-highlighter-4.5.0.jar高亮器添加到项目 buildpath:如下显示就对了:5. 写我们的代码了先生成索引:(代码插件挺好用啊)Document document=LuceneUtiles.getDocument(filePath);/存放索引的目录Directory indexDirectory=FSDirectory.open( new File(indexPath);/这里默认使用的模式

13、是:openMode = OpenMode.CREATE_OR_APPEND;/IndexWriterConfig 的父类构造是初始化的IndexWriterConfig indexWriterConfig=newIndexWriterConfig(Version.LUCENE_45, analyzer);/索引的维护是用 IndexWriter 来做的,把 doc 添加进去,更新,删除就行了IndexWriter indexWriter=newIndexWriter(indexDirectory,indexWriterConfig);indexWriter.addDocument(docum

14、ent);/所有 io 操作的,最后都应该关闭,比如file,network,database 等indexWriter.close();:publicvoidsearchFromIndex()throwsIOException /只能全小写才可以!因为我们 term 没有经过分词器处理!/所以只能用直接跟索引库的关键字一一对应的值/以后讲解把索引字符串也处理的方法String queryString="binary"/1.收索字符串->Query 对象Query query=null; /注意:/因为文件在建立索引的时候(分词器那里),就已经做了一次大小写转换了,/

15、存的索引全是小写的/而我们这里搜索的时候没有通过分词器,所以我们的数据没有转化,/那么如果这里是大写类型就搜不到任何东西!Term term=newTerm("fileContent",queryString);/至于这里用什么 Query,以后再说query=newTermQuery(term); /2.进行TopDocs topDocs=null; IndexSearcher searcher=null; IndexReader indexReader=null; /指定索引的文件位置indexReader=DirectoryReader.open(FSDirector

16、y.open(newFile(indexPath); searcher=newIndexSearcher(indexReader); Filter filter=null;/搜索/过滤器,可以过滤一些文件,null 就是不用过滤器/数字代表每次多少条,也就是一次数据的读多少条,/1000,10000 等比较合适,默认是 50/topDocs=searcher.search(query, filter,1000); /3.打印结果 System.out.println("总共有【"+topDocs.totalHits+"】条匹配结果");/这是返回的数据f

17、or(inti=0; i<topDocs.scoreDocs.length; i+6. 讲解点击类名,使用 ctrl+T 实现该类的子类,即继承关系!下面是 Lucene 的大体结构图:原理是先把文章根据需求用分词器拆分,然后建立好每一个到文章的关系,这就是索引表,索引表存放的就是关键字到文章的,注意这里的不是直接就持有了对应的文章,而是持有的内部对文章编号的一个 id。所以索引是关键字到文章 Id 的一个。当用户时,也用之前的分词器,把分词,然后每一个词都挨着找索引,把匹配的返回出来就完毕了。) intdocId=topDocs.scoreDocsi.doc; Document hit

18、tedDocument=searcher.doc(docId); LuceneUtiles.print(hittedDocument); indexReader.close(); (别人的图片)a) Analysis:分词器Analysis 包含一些内建的分析器,例如按空白字符分词的 WhitespaceAnalyzer,添加了 stopwrod 过滤的 StopAnalyzer,最常用的 StandardAnalyzer。b) Documet:文档就是我们的源数据的封装结构,我们需要把源数据分成不同的域,放入到 documet 里面,到时搜索时也可以指定搜索哪些域( Field)了。c) D

19、irectory : 目录,这是对目录的一个抽象,这个目录可以是文件系统上面的一个 dir(FSDirectory),也可以是内存的一块(RAMDirectory),MmapDirectory 为使用内存的索引。放在内存的话就会避免 IO 的操作耗时了,根据需要选择就是了。d) IndexWriter : 索引书写器,也就是维护器,对索引进行和删除操作的类e) IndexReader : 索引器,用于指定目录的索引。f) IndexSearcher : 索引的搜索器,就是把用户输入拿到索引列表中搜索的一个类需要注意的是,这个搜索出来的就是( TopDocs)索引号,还不是真正的文章。g) Qu

20、ery :语句,我们需要把我们的String 封装成 Query 才可以交给 Searcher 来搜索 ,的最小单元是 Term,Lucene 的 Query有很多种,根据不同的需求选用不同的 Query 就是了.i. TermQuery:如果你想执行一个这样的:“在 content 域中包含lucene的 document”,那么你可以用 TermQuery:Term t=ii. BooleanQuery:多个 query 的【与或】关系的如果你想这么:“在 content 域中包含 java 或 perl 的 document”,那么你可以建立两个 TermQuery 并把它们用 Bool

21、eanQuery 连接起来:TermQuery termQuery1=new Term("content","lucene"); Query query=new TermQuery(t);newTermQuery(newTerm("content","java"); TermQuery termQuery2=newTermQuery(newTerm("content","perl"); BooleanQuery booleanQuery=iii. WildcardQuery

22、: 通配符的如果你想对某单词进行通配符,你可以用 WildcardQuery,通配符包括?匹配一个任意字符和*匹配零个或多个任意字符,例如你搜索use*,你可能找到useful或者useless:Query query = new WildcardQuery(new Term("content", "use*");iv. PhraseQuery : 在指定的文字距离内出现的词的你可能对关系比较感,想查找中和日挨得比较近( 5 个字的距离内)的文章,超过这个距离的不予考虑,你可以:PhraseQuery query = new PhraseQuery();

23、query.setSlop(5);query.add(new Term("content ", “中”);query.add(new Term(“content”, “日”);newBooleanQuery(); booleanQuery.add(termQuery1, BooleanClause.Occur.SHOULD); booleanQuery.add(termQuery2, BooleanClause.Occur.SHOULD);那么它可能搜到“合作”、“中方和日方”,但是搜不到“中国某说欠扁”。v. PrefixQuery :词语是以某字符开头的如果你想搜以中开

24、头的词语,你可以用 PrefixQuery:PrefixQuery query = new PrefixQuery(new Term("content ", " 中");vi. FuzzyQuery : 相似的搜索FuzzyQuery 用来搜索相似的 term,使用 Levenshtein 算法。假设你想搜索跟wuzza相似的词语,你可以:Query query = new FuzzyQuery(new Term("content", "wuzza");你可能得到fuzzy和wuzzy。vii. TermRange

25、Query : 范围内搜索你也许想搜索时间域从 20060101 到 20060130 之间的 document,你可以用 TermRangeQuery:TermRangeQuery query2 = TermRangeQuery.newStringRange("time", "20060101", "20060130", true, true);最后的 true 表示用闭合区间。viii.h) TopDocs :结果集,就是 searcher 搜索的结果,里面就是一些 ScoreDoc,这个对象的 doc 成员就是这个 Id 了!要

26、想得到文章,那么就得需要用这个 Id 去取文章了,searcher 提供了用 id 得到 document 的方法,于是就取到了数据了i)7.使用多个 Directory因为我们知道了 FSDirectory 是从文件系统的目录中数据,我们总不可能每次都从文件中一次索引吧,所以我们的做法应该是程序启动时就把所以载入到内存,时再回写,如下面的示意图:(也是别人的图片)使用内存的目录:RAMDirectory这样可以加快速度/* 测试使用RAMDirectroy,也就是把生成的索引写到内存而不是磁盘. * 运行这个方法, 不报错就代表了。 *我们是把索引文件写道文件系统的,这里就是写道 RAM 中

27、,以后也 * 可以在这个目录,快速! *throws IOException*/Test publicvoid testWriteInToRam() throwsIOException Directory directory=从文件系统的目录载入到 ram 中,然后进行操作,最后保存回去下面是实例代码:/*newRAMDirectory(); IndexWriterConfig config=newIndexWriterConfig(Version.LUCENE_45, analyzer); IndexWriter indexWriter=newIndexWriter(directory, c

28、onfig); indexWriter.addDocument(LuceneUtiles.getDocument(filePath); indexWriter.close(); * 从磁盘的索引文件中放入到 RAM 目录,* 然后进行一系列的其他操作。* 退出时再把 RAM 的写回文件系统。*throwsIOException*/TestpublicvoidtestLoadIntoRamAndWriteBacktoFS()throwsIOException /1.启动时载入Directory fsDir=FSDirectory.open(newFile(indexPath); RAMDirec

29、tory ramDir=newRAMDirectory(fsDir,newIOContext();/中途操作内存中的数据IndexWriterConfig ramIndexWriterConfig=newIndexWriterConfig(Version.LUCENE_45, analyzer); IndexWriter ramIndexWriter=newIndexWriter(ramDir, ramIndexWriterConfig);/添加一个文件,这好像没有写进去!/不是没写进去,而是这个方法没有执行!因为 test 方法一定要加Test 注解!ramIndexWriter.addDo

30、cument( LuceneUtiles.getDocument(filePath);ramIndexWriter.close();/要先关闭,因为还有缓存。/2.时保存写回,因为默认是 CREATE_OR_APPEND/所以这里就会把AABBCC 读出来之后,加上 DD/那么写回去的数据时 AABBCCDD,但是已经本地有了,/所以是 append 的方式,于是最后的结果是/AABBCCAABBCCDD,就是重复的了。可以 search 同一个关键字,/看结果数量就知道了/会 1 条变 3 条,3 条变 7 条,这种*2+1 的形式/我们可以每次都重写,就能解决了合并索引因为每添加一个文档的

31、索引,都会建立多个小的文件存放索引,所以文档多了之后,IO 操作就很费时间了,于是我们需要合并小文件,每一个小文件就是 segment。合并代码如下,需要注意的是:IndexWriterConfig fsIndexWriterConfig=newIndexWriterConfig(Version.LUCENE_45, analyzer);/设置每次重写fsIndexWriterConfig.setOpenMode(OpenMode.CREATE); IndexWriter fsIndexWriter=newIndexWriter(fsDir, fsIndexWriterConfig); fsI

32、ndexWriter.addIndexes(ramDir); fsIndexWriter.close(); a) 我们不能直接把索引库打开,用 Creat_OR_Append 的方式强制写回他会出现叠加的问题b) 要每次都用 Create 的方式写回但是不能再写回的目录,因为同一个目录不支持又读又写,必须指定其他的目录c) 指定其他目录存放 Merge 的索引,在写回之前,应该把之前的索引添加到 IndexWriter 中,这样才把会有数据/* 索引库文件优化,貌似没有提供保存优化的接口 * 多半内部封装好的,外界不用管。只有一个强制合并的接口。 * 这就是用于合并。 *throws IOEx

33、ception*/Test publicvoidtestYouHua()throwsIOException Directory fsDirectory_Merged=FSDirectory.open(newFile(indexPathMerged); Directory fsDirectory=FSDirectory.open(newFile(indexPath); IndexWriterConfig indexWriterConfig=newIndexWriterConfig(Version.LUCENE_45, analyzer);indexWriterConfig.setOpenMode

34、(OpenMode.CREATE); IndexWriter indexWriter=newIndexWriter(fsDirectory_Merged, indexWriterConfig);/forceMerge(1)可以把所以的段合并成 1 个,但是每次都会增加一份,/就是像拷贝了一份加入一样/难道是该指定 OpenMode.CREATE,如果指定了 CREATE,/但是呢 IndexWriter 里面没有添加 doc 索引(即 addDoc 等方法),/所以写进去就编程空索引库了,于是需要先读出来再写回/于是还应该把索引加到 writer 里面/把加入进去,然后再用每次都 create

35、 的办法保持新增/注意不能添加到,所以还得新建一个库才可以,这样就叠加了indexWriter.addIndexes(fsDirectory); indexWmit();indexWriter.forceMerge(1); indexWriter.close(); 分词器(Analyzer)在前面的概念介绍中我们已经知道了分析器的作用,就是把句子按照语义切分成一个个词语。英文切分已经有了很成分析器: StandardAnalyzer,很多情况下 StandardAnalyzer 是个不错的选择。甚至你会发现 StandardAnalyzer 也能对中文进行分词。但是我们的焦点是中文分词,Sta

36、ndardAnalyzer 能支持中文分词吗?实践证明是可以的,但是效果并不好,搜索“如果” 会把“牛奶不如果汁好喝”也搜索出来,而且索引文件很大。那么我们手头上还有什么分析器可以使用呢?core 里面没有,我们可以在 sandbox 里面找到两个:Analyzer 和 CJKAnalyzer。但是它们同样都有分词的问题。相比之下用 StandardAnalyzer 和Analyzer 建立索引时间差不多,索引文件大小也差不多,CJKAnalyzer 表现会差些,索引文件大且耗时比较长。要解决问题,首先分析一下这三个分析器的分词方式。StandardAnalyzer和Analyzer 都是把句

37、子按单个字切分,也就是说 “牛奶不如果汁好喝”会被它们切分成“牛 奶 不 如 果 汁 好 喝”;而 CJKAnalyzer则会切分成“牛奶 奶不 不如 如果 果汁 汁好好喝”。这也就解释了为什么搜索“果汁”都能匹配这个句子。以上分词的缺点至少有两个:匹配确和索引文件大。我们的目标是将上面的句子分解成 “牛奶 不如 果汁好喝”。这里的关键就是语义识别,我们如何识别“牛奶”是一个词而“奶不”不是词语?我们很自然会想到基于词库的分词法,也就是我们先得到一个词库,里面列举了大部分词语,我们把句子按某种方式切分,当得到的词语与词库中的项匹配时,我们就认为这种切分是正确的。这样切词的过程就转变成匹配的过程

38、,而匹配的方式最简单的有正向最大匹配和逆向最大匹配两种,说白了就是一个从句子开头向后进行匹配,一个从句子末尾向前进行匹配。基于词库的分词词库非常重要,词库的容量直接影响搜索结果,在相同词库的前提下,据说逆向最大匹配优于正向最大匹配。当然还有别的分词方法,这本身就是一个学科,我这里也没有深入研究。回到具体应用,我们的目标是能找到成、现成的分词工具,避免重新发明车轮。经过网上搜索,用的比较多的是的 ICTCLAS 和一个不开放源码但是的 JE-Analysis。ICTCLAS 有个问题是它是一个动态库, java 调用需要本地方法调用,不方便也有安全隐患,而且口碑也确实不大好。JE-Analysi

39、s 效果还不错,当然也会有分词的地方,相比比较方便放心。下面就是分词器的例子:/* <pre> * 测试分词器的,分词器分出来的关键字我们叫做 Token * 分词器一般需要完成的工作是: * 1.词组拆分 * 2.去掉停用词 * 3.大小写转换 * 4.词根还原 * * 对于中文分词,通常有 3 种:单词分词,二分法,词典分词。 * 单词分词:就分成一个一个的单个字,比如linkStandardAnalyzer, * 如分成 我-们-是-* 二分法分词:按 2 个字分词,即我们-们是-是中-中国-国人,实现是是 * linkCJKAnalyzer * 词典分词:按照某种算法构造词

40、,然后把词拿到词典里面找,如果是词,就算对了。 * 这是目前的好用的,可以分词成 我们-, * 好用的有【极易分词:MMAnalyzer】,还有就是【庖丁分词】目前没有找到适用于 4.5 的。 * 还有一个牛的,是院的。能分出帽子和服装。这些需要外界提供,需要jar 包 * </pre> * *authorLiFeng */publicclassAnalyzerTest String enString="it must be made available under this Agreement,”+”formore information : infor.doc&quo

41、t;String zhString="你好,我是,名字是李锋。"/这个分词器用于英文的,没有形态还原/如果拿去分中文的话,每一个字都被拆开了,测试下就晓得了Analyzer enAnalyzer=newStandardAnalyzer(Version.LUCENE_45);/可以按点,没有形态还原/对于中文的话,他也只按标点分:你好 我是名字是李锋这 3 个 tokenAnalyzer simpleAnalyzer=newSimpleAnalyzer(Version.LUCENE_45);/分中文就是二分法/分英文就是:单词就完了Analyzer cjkAnalyzer=n

42、ewCJKAnalyzer(Version.LUCENE_45);/lucene4.5 使用je-analysis-1.5.3.jar 会,因为好多都改了Analyzer jeAnalyzer=newMMAnalyzer();/词库分词,比如极易String testString=enString; Analyzer testAnalyzer=jeAnalyzer;/* 得到分词器拆分出来的关键字(Token) * *throwsIOException*/TestpublicvoidtestGetTokens()throwsIOException /得到分出来的词流/fileName 就是我们

43、当时创建 document 时一样的意思/我们这里是要得到分出的词,跟他要归属哪个 filed 无关,所以不用管/查看 enAnalyzer 的 tokenStream 的帮助,他叫们参考:/See the Analysis package documentation for some examples/demonstrating this./于是打开对于的文档如下:/docs/core/org/apache/lucene/analysis/package-summary.html#package_description/这里面会有例子的!/下面是文档的例子/分词器把文本分词 token 流T

44、okenStream tokenStream=testAnalyzer.tokenStream("myfield",newStringReader(testString); OffsetAttribute offsetAtt=tokenStream.addAttribute(OffsetAttribute.class);try/Resets this stream to the beginning. (Required)tokenStream.reset();while(tokenStream.incrementToken() /这里传入 true 就可以看到更详细的信息,

45、调试用很好/打印 token 的信息System.out.println("token:"+tokenStream.refleString(false);/可以去除 token 存放的开始和结束/System.out.println("token start offset: "/+ offsetAtt.startOffset();/System.out.println(" token end offset: "/+ offsetAtt.endOffset(); tokenStream.end(); finally/Release re

46、sources associated with this stream.tokenStream.close(); 高亮器 highlighter高亮器帮我们做两件事,第一件就是搜索结果的摘要,第二件事就是整体内容的关键字高亮。高亮的原理就是在关键字周围加上 html就是了。String indexPath="D:WorkspacesForAllLuceneLucene-00010-HelloWorldlf_index " Analyzer analyzer=newStandardAnalyzer(Version.LUCENE_45); Test publicvoidtest

47、Hightlight()throwsIOException, InvalidTokenOffsetsException /fileContent 字段的reproduce 关键字/这里的 filed 指定就是用于找到符合的document/在高亮器初始化的时候 Scorer 类也用到了这个 query/其实过程就是:/1.先把某个域出现关键字的 doc 全部找出来/2.再用高亮器,在找到的文章中,/把指定域的内容提取一部分有关键字的文本,加上高亮就完毕了Query query=newTermQuery(newTerm("fileContent","reproduc

48、e");/高亮器的初始化准备Highlighter highlighter=null; Formatter formatter=newSimpleHTMLFormatter("<font color='red'>","</font>"); Scorer fragmentScorer=newQueryScorer(query); highlighter=newHighlighter(formatter, fragmentScorer);/摘要只取 50 个字符Fragmenter fragmenter=ne

49、wSimpleFragmenter(50); highlighter.setTextFragmenter(fragmenter); IndexReader indexReader=DirectoryReader.open( FSDirectory.open(newFile(indexPath); IndexSearcher searcher=newIndexSearcher(indexReader); TopDocs topDocs=searcher.search(query,null,1000); System.out.println("找到【"+topDocs.tota

50、lHits+"】个:");for(inti=0; i<topDocs.scoreDocs.length; i+) intdocId=topDocs.scoreDocsi.doc; Document document=searcher.doc(docId);/用高亮器返回摘要/参数 1 就是用指定的分词器,/参数 2 目前不知道咋用/参数 3 就是我们需要处理哪一段文本的数据,把这段文件实现高亮并返回摘要/返回的就是高亮之后的摘要了,没有就是 nullString ret=highlighter.getBestFragment( analyzer,"anySt

51、ring",document.get("fileContent") );/String ret = highlighter.getBestFragment(/analyzer, "anyString",document.get("noThisFiled") );if(ret!=null) System.out.println(ret); else String defaultString=document.get("fileContent有两种大类:第一种是使用字符串,有语法的。就像直接输入 sql 语句一样。第二

52、种就是对象,即用 query 类来组复杂。这个在概述的时候已经讲过了。对象:常用的有:TermQuery,BooleanQuery,WildcardQuery,PhraseQuery,PrefixQuery,TermRangeQuery 等。对象对应的语法可以直接打印出来 system.out.println(query);TermQuery:"); System.out.println( "不高亮:"+defaultString); 如果你想执行一个这样的:“在 content 域中包含lucene的 document”,那么你可以用 TermQuery:Term t = new Term("content", " lucene");Query query = new TermQuery(t);BooleanQuery多个 query 的【与或】关系的如果你想这么:“在 content 域中包含 java 或 pe

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论