??xml version="1.0" encoding="utf-8" standalone="yes"?>日韩精品网站,亚洲欧美日韩综合,亚洲www啪成人一区二区麻豆http://www.aygfsteel.com/masen/category/22936.html从现在开?/description>zh-cnThu, 31 May 2007 13:42:10 GMTThu, 31 May 2007 13:42:10 GMT60 Lucene 学习Q{Q?/title><link>http://www.aygfsteel.com/masen/articles/121128.html</link><dc:creator>Masen</dc:creator><author>Masen</author><pubDate>Thu, 31 May 2007 04:56:00 GMT</pubDate><guid>http://www.aygfsteel.com/masen/articles/121128.html</guid><wfw:comment>http://www.aygfsteel.com/masen/comments/121128.html</wfw:comment><comments>http://www.aygfsteel.com/masen/articles/121128.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/masen/comments/commentRss/121128.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/masen/services/trackbacks/121128.html</trackback:ping><description><![CDATA[通过q几天的看书和学习,?Lucene 有了更进一步的认识Q所以ȝ一下这些天的学习成果把 Lucene 的学习心得也学出来?<o:p></o:p> <h1>1          Lucene 的认?<o:p></o:p></h1> <p style="FONT-SIZE: 14pt">提到 Lucene 很多人都知道q个开源的搜烦工具Q其力也是很大的。它让我们对搜烦引擎的认识不在那么神U,也不会在觉得癑ֺ?google 的技术多么的高深没测Q其实其原理都是一LQ只是他们要做的更好Q走的更qŞ了?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Lucene 可以对Q何的数据做烦引和搜烦Q说q样的话其实不过分,真的是q样Q只要你能处理好q些数据Q交l?Lucene d立烦引它都可以帮你把q些数据l检索出来,是不是很好玩了。真正好玩的地方q在后面呢?<o:p></o:p></p> <h1>2          Lucene 的学?<o:p></o:p></h1> <p style="FONT-SIZE: 14pt">前面已经?Lucene 有了一些了解,现在我们惌它怎么L索这些数据呢Q如果知道倒排索引Q你q道了Q其?lucene 索的是它自己建立的烦引,从烦引中的到数据的指针,从而得到数据。其实就q么单?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">提到索引Q现在的索引技术中有:倒排索引、后~数组和签名文件这三种Q其中后~数组q种技术虽然检索速度也很快,但是它的数据l构构造和l护都是相当ȝ的所以不可取了。我也懒得去看了。至于签名文件嘛Q那?80 q代的玩意了Q现在已l过时了。现在可是倒排索引的天下啊Q相信百度和 google 都是q种技术?<o:p></o:p></p> <h1>3          索引的徏?<o:p></o:p></h1> <p style="FONT-SIZE: 14pt"><o:p> </o:p> </p> <p style="FONT-SIZE: 14pt">我们从烦引的建立入手Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">我们建立一?lucene 的烦引时必须先徏立该索引文g存放的位|,看一下代码: <o:p></o:p></p> <p style="FONT-SIZE: 14pt">IndexWriter writer = null;<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">writer = new IndexWriter("c:\\index", new CJKAnalyzer(), true);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">q段代码时建立一个烦引前所必须的操作,先声明这?IndexWriter Q实例化它你必须传入三个参数。他们分别代表:你要建立索引文g的存放位|、你要用烦引徏立的分词Ҏ、是否重新徏立烦引。这样你告?lucene 我要?c 盘的 index 目录下徏立烦引文Ӟ我要使用<st1:personname w:st="on" productid="车东">车东</st1:personname>老师的二分词法做分析器、我要在q个目录下删除以前的索引或Q何文件创立我的烦引文件?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">索引的徏立有三种方式Q让我一一道来Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">1 ?new IndexWriter(new RAMDirectory(), new StandardAnalyzer(), true);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">在内存中建立索引Q速度最快但是耗资源,而且重启没了?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">2 ?new IndexWriter(FSDirectory.getDirectory(path, true), new StandardAnalyzer(), true);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">在文件系l中建立索引Q这里有两个参数Q分别是Q徏立烦引的路径、是否要删除当前目录下的文g重新建立索引?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">3 ?new IndexWriter("c:\\index", new CJKAnalyzer(), true);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">最常见的一U,在制定目录下建立索引Q看了源码你q道这U方法也是用的第二种方式?Lucene 的源码: <o:p></o:p></p> <p style="FONT-SIZE: 14pt">public IndexWriter(String path, Analyzer a, boolean create)<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       throws IOException {<o:p></o:p> </p> <p style="FONT-SIZE: 14pt"> this(FSDirectory.getDirectory(path, create), a, create, true);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">  }<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">我想的没错?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Indexwriter 性能调整参数Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">W一个优化的参数 Q?mergeFactor q个参数用于控制 lucene 在把索引从内存写入到盘上的文gpȝ时内存最大的 Document 对象的数量。这个数要根据你的计机讄Q默认情况下?10 ?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">    W二个优化的参数 Q?maxMergeFactor q个参数用来讄当有多少?Segment 时进行合q操作。当然我们知道当索引文g太多的话其检索的速度׃很慢Q所以我们要当文件数量一定时让它q行索引的合q。这样就可以加快索引速度Q但是这个DҎ你的情况而定。当文数量较多时我们将D大些Q当文档数量较少时我们将D些?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">W三个优化的参数 Q?minMergeDocs q个参数用于控制内存中文的数量?<o:p></o:p></p> <p style="FONT-SIZE: 14pt"><o:p> </o:p> </p> <p style="FONT-SIZE: 14pt">q样我们建立索引已经完成Q接下来我们要徏?Document 对象Q因Z必须告诉我要搜烦什么吧Q好了,看看源码Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">File file = new File("1.txt"); <o:p></o:p></p> <p style="FONT-SIZE: 14pt">Document doc = new Document();<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">doc.add(Field.UnIndexed("filename", file.getName()));<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">FileInputStream fis = new FileInputStream(file);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">byte[] b = new byte[fis.available()];<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">fis.read(b);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">String content = new String(b);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">doc.add(Field.Text("content", content));<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">fis.close();<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">以上我们完成了?1.txt 文g攑ֈ我们?Document 对象了。这里我们用?Field.Text(); q样的操作和 doc.add(); q样的方法徏立的。这也是建立索引的必R?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">E微介绍一?Field Q它是你要建立索引的字Dc它分别?<o:p></o:p></p> <table cellSpacing=0 cellPadding=0 border=1> <tbody> <tr> <td style="FONT-SIZE: 14pt" width=208> <p style="FONT-SIZE: 14pt" align=center>cd / Ҏ <o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" width=52> <p style="FONT-SIZE: 14pt" align=center>是否分词 <o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" width=48> <p style="FONT-SIZE: 14pt" align=center>是否索引 <o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" width=48> <p style="FONT-SIZE: 14pt" align=center>是否存储 <o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" width=213> <p style="FONT-SIZE: 14pt" align=center>常用实例 <o:p></o:p></p> </td> </tr> <tr> <td style="FONT-SIZE: 14pt" width=208> <p style="FONT-SIZE: 14pt" align=center>Keyword(String,String)<o:p></o:p> </p> <p style="FONT-SIZE: 14pt" align=center>Keyword(String,Date)<o:p></o:p> </p> </td> <td style="FONT-SIZE: 14pt" width=52> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" width=48> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" width=48> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" width=213> <p style="FONT-SIZE: 14pt" align=center>电话LQn份证Qh名,地名Q日?<o:p></o:p></p> </td> </tr> <tr> <td style="FONT-SIZE: 14pt" vAlign=top width=208> <p style="FONT-SIZE: 14pt" align=center>Unindexed(String,String)<o:p></o:p> </p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=52> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=48> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=48> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=213> <p style="FONT-SIZE: 14pt" align=center>文cdQ文名U?<o:p></o:p></p> </td> </tr> <tr> <td style="FONT-SIZE: 14pt" vAlign=top width=208> <p style="FONT-SIZE: 14pt" align=center>UnStored(String,String)<o:p></o:p> </p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=52> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=48> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=48> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=213> <p style="FONT-SIZE: 14pt" align=center>文的标题和内容 <o:p></o:p></p> </td> </tr> <tr> <td style="FONT-SIZE: 14pt" vAlign=top width=208> <p style="FONT-SIZE: 14pt" align=center>Text(String,String)<o:p></o:p> </p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=52> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=48> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=48> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=213> <p style="FONT-SIZE: 14pt" align=center>文档的标题和内容 <o:p></o:p></p> </td> </tr> <tr> <td style="FONT-SIZE: 14pt" vAlign=top width=208> <p style="FONT-SIZE: 14pt" align=center>Text(String,Reader)<o:p></o:p> </p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=52> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=48> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=48> <p style="FONT-SIZE: 14pt" align=center>?<o:p></o:p></p> </td> <td style="FONT-SIZE: 14pt" vAlign=top width=213> <p style="FONT-SIZE: 14pt" align=center>文的标题和内容 <o:p></o:p></p> </td> </tr> </tbody> </table> <p style="FONT-SIZE: 14pt">    q样我们要徏什么样的烦引就对号入吧,只要最后我们?doc.add(Field.Text("content", content)); 把它d?Document 中就可以了?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">    q时我们的文已l徏立好了,现在开始向索引中添加文吧Q这里我们?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">writer.addDocument(doc); 来向 Indexwriter 索引中添加构造好的文?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">q样我们是不是就可以说我们已l徏立完了烦引呢Q其实不Ӟ我们q要优化优化Q这h快嘛Q对不对Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">    writer.optimize(); q样一句话可以实现烦引优化了Q具体的优化q程我就不说了,是不是很单。但是一定不要忘了哦。调用这个方法时最好徏立一个合适的周期。定期进行优化?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">    好了Q这h们就完成了烦引的建立了?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">    下面我们看看~媄的合q吧Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">当我们在很多地方建立了很多的索引后,惌合ƈq些索引我们怎么办呢Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">    使用 IndexWriter.assIndexs(New Directory[]{path});<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">可以对 path 路径下的索引合ƈ到当前的索引中了?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">    下面再看看烦引的删除吧! <o:p></o:p></p> <p style="FONT-SIZE: 14pt">    有一些过时的索引我们需要删除,怎么办呢Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">IndexReader reader = IndexReader.open("c:\\index");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">    reader.delete(0);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">q样我们可以按照文的序删除对应的文了Q但是这样不太现实,不对吗?我们怎么会知道文的序呢? <o:p></o:p></p> <p style="FONT-SIZE: 14pt">下面我们看看W二中方法: <o:p></o:p></p> <p style="FONT-SIZE: 14pt">IndexReader reader = IndexReader.open("c:\\index");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">reader.delete(new Term("name","word1"));<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">reader.close();<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">按照字段来删除对应的文档Q这样合理多了。以后要删除时就按照词条的方式去删除?!<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">索引锁: write.lock , commit.lock.<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">write.lock 是ؓ了避免几个线E同时修改一个烦引文而设|。当实例一?indexwrite 时徏立和使用 indexReader 删除文时徏立?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Commit.lock 该锁主要?segment 在徏立,合ƈ或读取时生成?<o:p></o:p></p> <h1>4          Lucene 的搜?<o:p></o:p></h1> <p style="FONT-SIZE: 14pt"><o:p> </o:p> </p> <p style="FONT-SIZE: 14pt">以上完成了烦引的建立和一些关于烦引的知识Q但是光有烦引是不行的,我们真正要做的检索,q才是我们的关键。现在我们看?lucene 的检索吧?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">认识索从索的工具开始吧Q?IndexSearcher cL lucene 用于索的工具c,我们在检索之前要得到q个cȝ实例?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">W一步我们看以下代码Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">IndexSearcher searcher = new IndexSearcher("c:\\index");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">创徏 IndexSearcher 实例需要告?lucene 索引的位|,是?IndexWrite 的文件\径?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Query query = null;<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">Hits hits = null;<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">query = QueryParser.parse(key1, "name", new StandardAnalyzer());<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">if (hits != null) {<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">           if (hits.length() == 0) {<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">              System.out.println(" 没有扑ֈMl果 ");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">           } else {<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">              System.out.print(" 扑ֈ ");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">              for (int i = 0; i < hits.length(); i++) {<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">                  Document d = hits.doc(i);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">                  String dname = d.get("title");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">                  System.out.print(dname + "   " );<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">              }<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">           }<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       }<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">}<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">以上是一个完整的索过E,q里我们看见了个 Query ?Hits Q这两个cd是比较关键的了,我们先从索结果的 Hits c说赗?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">我们使用 Hits l常使用的几个方法有Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">length() :  q回搜烦l果的L量?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Doc(int n) : 攑֛W?n 个文?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Id(int n) : q回W?n 个文档的内部~号?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Sorce(int n) : q回W?n 个文的得分?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">看见q个 Sorce(int n) q个ҎQ是不是可以联惛_搜烦引擎的排序问题呢Q像癑ֺ的推q是怎么做出来的?, 可想而知吧,那就说明必定存在一中方法可以动态的改变某片文的得分。对了, lucene 中可以?Document ?setBoost Ҏ可以改变当前文?boost 因子?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">下面我们看看Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Document doc1 = new Document();<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">doc1.add(Field.Text("contents", "word1 word"));<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">doc1.add(Field.Keyword("path", "path\\document1.txt"));<o:p></o:p> </p> <p style="FONT-SIZE: 14pt"> doc1.setBoost(<st1:chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="1" unitname="F">1.0f</st1:chmetcnv>);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt"><o:p> </o:p> </p> <p style="FONT-SIZE: 14pt">  q样我们在改变了篇文的评分了Q当 boost 的D大它的分值就高Q其出现的位|就靠前?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">让我们再来看?lucene 为我们提供的各种 Query 吧?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">W一?nbsp;  按词条搜?Q?TermQuery <br>query = new TermQuery(new Term("name","word1"));<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">q样可以把 field ?name 的所有包?word1 的文档检索出来了?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">W二?nbsp; “与或”搜烦 Q?BooleanQuery<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">它实际是一个组?query 看看下面的代码: <o:p></o:p></p> <p style="FONT-SIZE: 14pt">query1 = new TermQuery(new Term("name","word1"));<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">query2 = new TermQuery(new Term("name","word2"));<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">query = new BooleanQuery();<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">query.add(query1, false, false);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">query.add(query2, false, false);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">看看 booleanQuery 的用法吧Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">true & true : 表明当前加入的字句是必须要满的。相当于逻辑与?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">false & true : 表明当前加入的字句是不可一被满的Q?相当于逻辑非?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">false & false : 表明当前加入的字句是可选的Q相当于逻辑或?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">true & true : 错误的情c?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Lucene 可以最多支持连l?1024 ?query 的组合?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">W三?nbsp; 在某一范围内搜?Q?RangeQuery<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">IndexSearcher searcher = new IndexSearcher("c:\\index");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">     Term beginTime = new Term("time","200001");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">     Term endTime = new Term("time","200005");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">     Hits hits = null;<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">     RangeQuery query = null;<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">     query = new RangeQuery(beginTime, endTime, false);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">     hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">RangeQuery 的构造函数的参数分别代表起始、结束、是否包括边界。这h们就可以按照要求索了?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">W四?nbsp; 使用前缀?Q?PrefixQuery<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">q个索的机制有点cM?indexOf() 从前~查找。这个常在英文中使用Q中文中很用了。代码如下: <o:p></o:p></p> <p style="FONT-SIZE: 14pt">IndexSearcher searcher = new IndexSearcher("c:\\index");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       Term pre1 = new Term("name", "Da");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       query = new PrefixQuery(pre1);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">W五?nbsp; 多关键字的搜?Q?PhraseQuery<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">可以多个关键字同时查询。用如下: <o:p></o:p></p> <p style="FONT-SIZE: 14pt">query = new PhraseQuery();<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       query.add(word1);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       query.add(word2);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       query.setSlop(0);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       printResult(hits, "'david' ?'mary' 紧紧盔R?Document");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       query.setSlop(2);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       printResult(hits, "'david' ?'mary' 中相隔两个词的短?");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">    q里我们要注?query.setSlop(); q个Ҏ的含义?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">query.setSlop(0);  紧紧相连 Q这个的条g比较苛刻Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">query.setSlop(2);  盔R <o:p></o:p></p> <p style="FONT-SIZE: 14pt">W六?nbsp; 使用短语~搜烦 Q?PharsePrefixQuery <o:p></o:p></p> <p style="FONT-SIZE: 14pt">使用 PharsePrefixQuery 可以很容易的实现相关短语的检索功能?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">实例Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">query = new PhrasePrefixQuery();<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       // 加入可能的所有不定的词 <o:p></o:p></p> <p style="FONT-SIZE: 14pt">Term word1 = new Term("content", "david");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       Term word2 = new Term("content", "mary");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       Term word3 = new Term("content", "smith");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       Term word4 = new Term("content", "robert");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       query.add(new Term[]{word1, word2});<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       // 加入定的词 <o:p></o:p></p> <p style="FONT-SIZE: 14pt">       query.add(word4);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       query.setSlop(2);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       printResult(hits, " 存在短语 'david robert' ?'mary robert' 的文?");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">W七?nbsp; 相近词语的搜?Q?fuzzyQuery<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">可以通俗的说它是一U模p查询?<o:p></o:p></p> <p style="FONT-SIZE: 14pt"><o:p> </o:p> </p> <p style="FONT-SIZE: 14pt"><o:p> </o:p> </p> <p style="FONT-SIZE: 14pt">实例Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Term word1 = new Term("content", "david");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       Hits hits = null;<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       FuzzyQuery query = null;<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       query = new FuzzyQuery(word1);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       printResult(hits," ?'david' 怼的词 ");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">W八?nbsp; 使用通配W搜?Q?WildcardQuery<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">实例Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">IndexSearcher searcher = new IndexSearcher("c:\\index");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       Term word1 = new Term("content", "*ever");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       Term word2 = new Term("content", "wh?ever");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       Term word3 = new Term("content", "h??ever");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       Term word4 = new Term("content", "ever*");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       WildcardQuery query = null;<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       Hits hits = null;<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       query = new WildcardQuery(word1);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       printResult(hits, "*ever");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       query = new WildcardQuery(word2);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       printResult(hits, "wh?ever");      <o:p></o:p></p> <p style="FONT-SIZE: 14pt">       query = new WildcardQuery(word3);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       printResult(hits, "h??ever");      <o:p></o:p></p> <p style="FONT-SIZE: 14pt">       query = new WildcardQuery(word4);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       printResult(hits, "ever*");<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">    ׃可以看出通配W?代便 1 个字W, * 代表 0 到多个字W?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Lucene 现在支持以上八中的搜索方式,我们可以Ҏ需要选择适合自己的搜索方式。当然上面提供的一些可能对英文q是比较有效Q中文就不可取了Q所以我们开始想想百度,我们只在一个输入框中搜索结果。有了这个疑问我们揭开下一章的讨论吧! <o:p></o:p></p> <p style="FONT-SIZE: 14pt">查询字符串的解析Q这个就是我们经常在一个输入框中输入我们要索的文字Q交l搜索引擎去帮我们分词?</p> <p style="FONT-SIZE: 14pt">QueryParser cd是对查询字符串的解析cR?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">看看它的用法Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt"><o:p> </o:p> </p> <p style="FONT-SIZE: 14pt">query = QueryParser.parse(key1, "name", new StandardAnalyzer());<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">它直接返回一?Query 对象。需要传入的参数分别是: <o:p></o:p></p> <p style="FONT-SIZE: 14pt">用户需要查询的字符丌Ӏ需要检索的对应字段名称、采用的分词cR?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Analyzer analyzer = new CJKAnalyzer();<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">String[] fields = {"filename", "content"};<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">Query query = MultiFieldQueryParser.parse(searchword, fields, analyzer);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">Hits hits = searcher.search(query);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">QueryParser ?#8220;?#8221; ?“?#8221;Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">QueryParser 之间默认是或Q我们想改变Z的话加入以下代码Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">QueryParser.setOperator(QueryParser.DEFAULT_OPERATOR_AND);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">可以了?<o:p></o:p></p> <h1>5          高搜烦技?<o:p></o:p></h1> <p style="FONT-SIZE: 14pt">前面我们已经介绍了一般情况下 lucene 的用技巧,现在我们探讨一下高U搜索的技巧吧Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">1?Ҏ索结果进行排序: <o:p></o:p></p> <p style="FONT-SIZE: 14pt">1Q?使用 sort cL序: <o:p></o:p></p> <p style="FONT-SIZE: 14pt">    Sort sort = new Sort();<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">        hits = searcher.search(query,sort);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">q种方式是用默认的 sort 排序方式q行排序。默认的 sort 排序是按照相兛_q行排序。即通过 luence 的评分机制进行排序?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">2) Ҏ一字段q行排序 <o:p></o:p></p> <p style="FONT-SIZE: 14pt">       Sort sort = new Sort( “ content ” );<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">      hits = searcher.search(query,sort);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">3) 对多个字D进行排?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Sort sort = new Sort(new SortField[]{new SortField("title"),new SortField("contents")});<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">hits = searcher.search(query,sort);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">2?多域搜烦和多索引搜烦Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">在?luecene Ӟ如果查询的只是某?terms Q而不兛_q些词条到时来自那个字段中时。这时可以?MultiFieldQueryParser cR这个用于用h索含有某个关键字是否存在在字D中Q他们之间的关系使用 OR q接。即不管存在在哪一个字D都会显C显C出来?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">使用 MultiSearcher 可以满同时多烦引的搜烦需求?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Searcher[] searchers = new Searcher[2]; <o:p></o:p></p> <p style="FONT-SIZE: 14pt">searchers[0] = new IndexSearcher(indexStoreB);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">searchers[1] = new IndexSearcher(indexStoreA);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">        // 创徏一个多索引索器 <o:p></o:p></p> <p style="FONT-SIZE: 14pt">Searcher mSearcher = new MultiSearcher(searchers);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">3?    Ҏ索结果进行过滤: <o:p></o:p></p> <p style="FONT-SIZE: 14pt">1)    Ҏ间进行过?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">         通常情况下我们对搜烦l果要进行过滤显C,卛_昄qo后的l果?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">doc.add(Field.Keyword("datefield", DateField.timeToString(now - 1000)));<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">DateFilter df1 = DateFilter.Before("datefield", now);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">2)        查询qo?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">通过查询qo器可以过滤一部分的信息?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">Filter filter = new Filter() <o:p></o:p></p> <p style="FONT-SIZE: 14pt">        {<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       public BitSet bits (IndexReader reader) throws IOException <o:p></o:p></p> <p style="FONT-SIZE: 14pt">          {<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">            BitSet bitset = new BitSet(5);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">            bitset.set (1);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">            bitset.set (3);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">            return bitset;<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">          }<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">        }; <o:p></o:p></p> <p style="FONT-SIZE: 14pt">        // 生成带有qo器的查询对象 <o:p></o:p></p> <p style="FONT-SIZE: 14pt">        Query filteredquery = new FilteredQuery (query, filter);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">       // q回索结?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">        Hits hits = searcher.search (filteredquery);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt"><o:p> </o:p> </p> <p style="FONT-SIZE: 14pt">q样我们可以用自己定义的qo方式去过滤信息了?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">3)    带缓存的qo器: <o:p></o:p></p> <p style="FONT-SIZE: 14pt">使用待缓存的qo器我们可以重用过滤功能,如下Q?<o:p></o:p></p> <p style="FONT-SIZE: 14pt">MockFilter filter = new MockFilter();<o:p></o:p> </p> <p style="FONT-SIZE: 14pt"> CachingWrapperFilter cacher = new CachingWrapperFilter(filter);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">        cacher.bits(reader);<o:p></o:p> </p> <p style="FONT-SIZE: 14pt">以上介绍完了现在学习 luence Q没有太详细的介l它的实玎ͼ因ؓ它对于我们来说是一个工P既然是工h们就要会用就可以了?</p> <img src ="http://www.aygfsteel.com/masen/aggbug/121128.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/masen/" target="_blank">Masen</a> 2007-05-31 12:56 <a href="http://www.aygfsteel.com/masen/articles/121128.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Lucene 索引机制 http://www.aygfsteel.com/masen/articles/121115.htmlMasenMasenThu, 31 May 2007 03:52:00 GMThttp://www.aygfsteel.com/masen/articles/121115.htmlhttp://www.aygfsteel.com/masen/comments/121115.htmlhttp://www.aygfsteel.com/masen/articles/121115.html#Feedback0http://www.aygfsteel.com/masen/comments/commentRss/121115.htmlhttp://www.aygfsteel.com/masen/services/trackbacks/121115.html深入 Lucene 索引机制

Lucene 是一个基?Java 的全文检索工具包Q你可以利用它来Z的应用程序加入烦引和索功能。Lucene 目前是著名的 Apache Jakarta 家族中的一个开源项目,下面我们卛_学习 Lucene 的烦引机制以及它的烦引文件的l构?/p>

在这文章中Q我们首先演C如何?Lucene 来烦引文,接着讨论如何提高索引的性能。最后我们来分析 Lucene 的烦引文件结构。需要记住的是,Lucene 不是一个完整的应用E序Q而是一个信息检索包Q它方便你ؓ你的应用E序d索引和搜索功能?/p>

架构概览

图一昄?Lucene 的烦引机制的架构。Lucene 使用各种解析器对各种不同cd的文档进行解析。比如对?HTML 文QHTML 解析器会做一些预处理的工作,比如qo文中的 HTML 标签{等。HTML 解析器的输出的是文本内容Q接着 Lucene 的分词器(Analyzer)从文本内容中提取出烦引项以及相关信息Q比如烦引项的出现频率。接着 Lucene 的分词器把这些信息写到烦引文件中?/p>
图一QLucene 索引机制架构
图一QLucene 索引机制架构




回页?/font>


用Lucene索引文

接下来我一步一步的来演C如何利?Lucene Z的文创建烦引。只要你能将要烦引的文g转化成文本格式,Lucene pZ的文徏立烦引。比如,如果你想?HTML 文或?PDF 文档建立索引Q那么首先你需要从q些文中提取出文本信息Q然后把文本信息交给 Lucene 建立索引。我们接下来的例子用来演C如何利?Lucene 为后~名ؓ txt 的文件徏立烦引?/p>

1Q?准备文本文g

首先把一些以 txt 为后~名的文本文g攑ֈ一个目录中Q比如在 Windows q_上,你可以放?C:\\files_to_index 下面?/p>

2Q?创徏索引

清单1是ؓ我们所准备的文创建烦引的代码?/p>
清单1Q用 Lucene 索引你的文
package lucene.index;
            import java.io.File;
            import java.io.FileReader;
            import java.io.Reader;
            import java.util.Date;
            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.index.IndexWriter;
            /**
            * This class demonstrates the process of creating an index with Lucene
            * for text files in a directory.
            */
            public class TextFileIndexer {
            public static void main(String[] args) throws Exception{
            //fileDir is the directory that contains the text files to be indexed
            File   fileDir  = new File("C:\\files_to_index ");
            //indexDir is the directory that hosts Lucene's index files
            File   indexDir = new File("C:\\luceneIndex");
            Analyzer luceneAnalyzer = new StandardAnalyzer();
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            File[] textFiles  = fileDir.listFiles();
            long startTime = new Date().getTime();
            //Add documents to the index
            for(int i = 0; i < textFiles.length; i++){
            if(textFiles[i].isFile() >> textFiles[i].getName().endsWith(".txt")){
            System.out.println("File " + textFiles[i].getCanonicalPath()
            + " is being indexed");
            Reader textReader = new FileReader(textFiles[i]);
            Document document = new Document();
            document.add(Field.Text("content",textReader));
            document.add(Field.Text("path",textFiles[i].getPath()));
            indexWriter.addDocument(document);
            }
            }
            indexWriter.optimize();
            indexWriter.close();
            long endTime = new Date().getTime();
            System.out.println("It took " + (endTime - startTime)
            + " milliseconds to create an index for the files in the directory "
            + fileDir.getPath());
            }
            }
            

正如清单1所C,你可以利?Lucene 非常方便的ؓ文创徏索引。接下来我们分析一下清?中的比较关键的代码,我们先从下面的一条语句开始看赗?/p>
Analyzer luceneAnalyzer = new StandardAnalyzer();
            

q条语句创徏了类 StandardAnalyzer 的一个实例,q个cL用来从文本中提取出烦引项的。它只是抽象c?Analyzer 的其中一个实现。Analyzer 也有一些其它的子类Q比?SimpleAnalyzer {?/p>

我们接着看另外一条语句:


IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            

q条语句创徏了类 IndexWriter 的一个实例,该类也是 Lucene 索引机制里面的一个关键类。这个类能创Z个新的烦引或者打开一个已存在的烦引ƈ所引添加文。我们注意到该类的构造函数接受三个参敎ͼW一个参数指定了存储索引文g的\径。第二个参数指定了在索引q程中用什么样的分词器。最后一个参数是个布变量,如果gؓ真,那么pC创徏一个新的烦引,如果gؓ假,pC打开一个已l存在的索引?/p>

接下来的代码演示了如何添加一个文档到索引文g中?/p>
Document document = new Document();
            document.add(Field.Text("content",textReader));
            document.add(Field.Text("path",textFiles[i].getPath()));
            indexWriter.addDocument(document);
            

首先W一行创Zc?Document 的一个实例,它由一个或者多个的?Field)l成。你可以把这个类惌成代表了一个实际的文Q比如一?HTML 面Q一?PDF 文Q或者一个文本文件。而类 Document 中的域一般就是实际文的一些属性。比如对于一?HTML 面Q它的域可能包括标题Q内容,URL {。我们可以用不同cd?Field 来控制文档的哪些内容应该索引Q哪些内容应该存储。如果想获取更多的关?Lucene 的域的信息,可以参?Lucene 的帮助文档。代码的W二行和W三行ؓ文档d了两个域Q每个域包含两个属性,分别是域的名字和域的内容。在我们的例子中两个域的名字分别?content"?path"。分别存储了我们需要烦引的文本文g的内容和路径。最后一行把准备好的文档dC索引当中?/p>

当我们把文d到烦引中后,不要忘记关闭索引Q这h保证 Lucene 把添加的文写回到硬盘上。下面的一句代码演CZ如何关闭索引?/p>
indexWriter.close();
            

利用清单1中的代码Q你可以成功的文本文添加到索引中去。接下来我们看看对烦引进行的另外一U重要的操作Q从索引中删除文档?/p>



回页?/font>


从烦引中删除文档

cIndexReader负责从一个已l存在的索引中删除文档,如清?所C?/p>
清单2Q从索引中删除文?/strong>
File   indexDir = new File("C:\\luceneIndex");
            IndexReader ir = IndexReader.open(indexDir);
            ir.delete(1);
            ir.delete(new Term("path","C:\\file_to_index\lucene.txt"));
            ir.close();
            

在清?中,W二行用静态方?IndexReader.open(indexDir) 初始化了c?IndexReader 的一个实例,q个Ҏ的参数指定了索引的存储\径。类 IndexReader 提供了两U方法去删除一个文档,如程序中的第三行和第四行所C。第三行利用文的编h删除文。每个文都有一个系l自动生成的~号。第四行删除了\径ؓ"C:\\file_to_index\lucene.txt"的文档。你可以通过指定文g路径来方便的删除一个文档。值得注意的是虽然利用上述代码删除文使得该文档不能被索到Q但是ƈ没有物理上删除该文。Lucene 只是通过一个后~名ؓ .delete 的文件来标记哪些文已经被删除。既然没有物理上删除Q我们可以方便的把这些标Cؓ删除的文档恢复过来,如清?3 所C,首先打开一个烦引,然后调用Ҏ ir.undeleteAll() 来完成恢复工作?/p>
清单3Q恢复已删除文
File   indexDir = new File("C:\\luceneIndex");
            IndexReader ir = IndexReader.open(indexDir);
            ir.undeleteAll();
            ir.close();
            

你现在也许想知道如何物理上删除烦引中的文,Ҏ也非常简单。清?4 演示了这个过E?/p>
清单4Q如何物理上删除文档
File   indexDir = new File("C:\\luceneIndex");
            Analyzer luceneAnalyzer = new StandardAnalyzer();
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,false);
            indexWriter.optimize();
            indexWriter.close();
            

在清?4 中,W三行创Zc?IndexWriter 的一个实例,q且打开了一个已l存在的索引。第 4 行对索引q行清理Q清理过E中把所有标Cؓ删除的文物理删除?/p>

Lucene 没有直接提供ҎҎ档进行更斎ͼ如果你需要更C个文,那么你首先需要把q个文从烦引中删除Q然后把新版本的文加入到烦引中厅R?/p>



回页?/font>


提高索引性能

利用 LuceneQ在创徏索引的工E中你可以充分利用机器的g资源来提高烦引的效率。当你需要烦引大量的文gӞ你会注意到烦引过E的瓉是在往盘上写索引文g的过E中。ؓ了解册个问? Lucene 在内存中持有一块缓冲区。但我们如何控制 Lucene 的缓冲区呢?q运的是QLucene 的类 IndexWriter 提供了三个参数用来调整缓冲区的大以及往盘上写索引文g的频率?/p>

1Q合q因子(mergeFactorQ?/p>

q个参数军_了在 Lucene 的一个烦引块中可以存攑֤文以及把盘上的索引块合q成一个大的烦引块的频率。比如,如果合ƈ因子的值是 10Q那么当内存中的文数达?10 的时候所有的文档都必d到磁盘上的一个新的烦引块中。ƈ且,如果盘上的索引块的隔数辑ֈ 10 的话Q这 10 个烦引块会被合ƈ成一个新的烦引块。这个参数的默认值是 10Q如果需要烦引的文数非常多的话q个值将是非怸合适的。对批处理的索引来讲Qؓq个参数赋一个比较大的g得到比较好的索引效果?/p>

2Q最合q文数

q个参数也会影响索引的性能。它军_了内存中的文档数臛_辑ֈ多少才能它们写回磁盘。这个参数的默认值是10Q如果你有够的内存Q那么将q个值尽量设的比较大一些将会显著的提高索引性能?/p>

3Q最大合q文数

q个参数军_了一个烦引块中的最大的文数。它的默认值是 Integer.MAX_VALUEQ将q个参数讄为比较大的值可以提高烦引效率和索速度Q由于该参数的默认值是整型的最大|所以我们一般不需要改动这个参数?/p>

清单 5 列出了这个三个参数用法,清单 5 和清?1 非常怼Q除了清?5 中会讄刚才提到的三个参数?/p>
清单5Q提高烦引性能
/**
            * This class demonstrates how to improve the indexing performance
            * by adjusting the parameters provided by IndexWriter.
            */
            public class AdvancedTextFileIndexer  {
            public static void main(String[] args) throws Exception{
            //fileDir is the directory that contains the text files to be indexed
            File   fileDir  = new File("C:\\files_to_index");
            //indexDir is the directory that hosts Lucene's index files
            File   indexDir = new File("C:\\luceneIndex");
            Analyzer luceneAnalyzer = new StandardAnalyzer();
            File[] textFiles  = fileDir.listFiles();
            long startTime = new Date().getTime();
            int mergeFactor = 10;
            int minMergeDocs = 10;
            int maxMergeDocs = Integer.MAX_VALUE;
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            indexWriter.mergeFactor = mergeFactor;
            indexWriter.minMergeDocs = minMergeDocs;
            indexWriter.maxMergeDocs = maxMergeDocs;
            //Add documents to the index
            for(int i = 0; i < textFiles.length; i++){
            if(textFiles[i].isFile() >> textFiles[i].getName().endsWith(".txt")){
            Reader textReader = new FileReader(textFiles[i]);
            Document document = new Document();
            document.add(Field.Text("content",textReader));
            document.add(Field.Keyword("path",textFiles[i].getPath()));
            indexWriter.addDocument(document);
            }
            }
            indexWriter.optimize();
            indexWriter.close();
            long endTime = new Date().getTime();
            System.out.println("MergeFactor: " + indexWriter.mergeFactor);
            System.out.println("MinMergeDocs: " + indexWriter.minMergeDocs);
            System.out.println("MaxMergeDocs: " + indexWriter.maxMergeDocs);
            System.out.println("Document number: " + textFiles.length);
            System.out.println("Time consumed: " + (endTime - startTime) + " milliseconds");
            }
            }
            

通过q个例子Q我们注意到在调整缓冲区的大以及写盘的频率上?Lucene l我们提供了非常大的灉|性。现在我们来看一下代码中的关键语句。如下的代码首先创徏了类 IndexWriter 的一个实例,然后对它的三个参数进行赋倹{?/p>
int mergeFactor = 10;
            int minMergeDocs = 10;
            int maxMergeDocs = Integer.MAX_VALUE;
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            indexWriter.mergeFactor = mergeFactor;
            indexWriter.minMergeDocs = minMergeDocs;
            indexWriter.maxMergeDocs = maxMergeDocs;
            

下面我们来看一下这三个参数取不同的值对索引旉的媄响,注意参数值的不同和烦引之间的关系。我们ؓq个实验准备?10000 个测试文档。表 1 昄了测试结果?/p>
?Q测试结?/strong>
?Q测试结?src="http://www-128.ibm.com/developerworks/cn/java/wa-lucene/images/table1.gif"

通过?1Q你可以清楚地看C个参数对索引旉的媄响。在实践中,你会l常的改变合q因子和最合q文数的值来提高索引性能。只要你有够大的内存,你可以ؓ合ƈ因子和最合q文数q两个参数赋量大的g提高索引效率Q另外我们一般无需更改最大合q文数q个参数的|因ؓpȝ已经默认它讄成了最大?/p>



回页?/font>


Lucene 索引文gl构分析

在分?Lucene 的烦引文件结构之前,我们先要理解反向索引QInverted indexQ这个概念,反向索引是一U以索引ؓ中心来组l文档的方式Q每个烦引项指向一个文序列,q个序列中的文都包含该索引V相反,在正向烦引中Q文档占据了中心的位|,每个文指向了一个它所包含的烦引项的序列。你可以利用反向索引L的找到那些文包含了特定的烦引项。Lucene正是使用了反向烦引作为其基本的烦引结构?/p>



回页?/font>


索引文g的逻辑视图

在Lucene 中有索引块的概念Q每个烦引块包含了一定数目的文。我们能够对单独的烦引块q行索。图 2 昄?Lucene 索引l构的逻辑视图。烦引块的个数由索引的文档的L以及每个索引块所能包含的最大文数来决定?/p>
?Q烦引文件的逻辑视图
?Q烦引文件的逻辑视图




回页?/font>


Lucene 中的关键索引文g

下面的部分将会分析Lucene中的主要的烦引文Ӟ可能分析有些索引文g的时候没有包含文件的所有的字段Q但不会影响到对索引文g的理解?/p>

1Q烦引块文g

q个文g包含了烦引中的烦引块信息Q这个文件包含了每个索引块的名字以及大小{信息。表 2 昄了这个文件的l构信息?/p>
?Q烦引块文gl构
?Q烦引块文gl构

2Q域信息文g

我们知道Q烦引中的文由一个或者多个域l成Q这个文件包含了每个索引块中的域的信息。表 3 昄了这个文件的l构?/p>
?Q域信息文gl构
?Q域信息文gl构

3Q烦引项信息文g

q是索引文g里面最核心的一个文Ӟ它存储了所有的索引的g及相关信息,q且以烦引项来排序。表 4 昄了这个文件的l构?/p>
?Q烦引项信息文gl构
?Q烦引项信息文gl构

4Q频率文?/p>

q个文g包含了包含烦引项的文的列表Q以及烦引项在每个文档中出现的频率信息。如果Lucene在烦引项信息文g中发现有索引和搜烦词相匚w。那?Lucene ׃在频率文件中找有哪些文g包含了该索引V表5昄了这个文件的一个大致的l构Qƈ没有包含q个文g的所有字Dc?/p>
?Q频率文件的l构
?Q频率文件的l构

5Q位|文?/p>

q个文g包含了烦引项在每个文中出现的位|信息,你可以利用这些信息来参与对烦引结果的排序。表 6 昄了这个文件的l构


?Q位|文件的l构
?Q位|文件的l构

到目前ؓ止我们介l了 Lucene 中的主要的烦引文件结构,希望能对你理?Lucene 的物理的存储l构有所帮助?/p>



回页?/font>


ȝ

目前已经有非常多的知名的l织正在使用 LuceneQ比如,Lucene ?Eclipse 的帮助系l,ȝ理工学院?OpenCourseWare 提供了搜索功能。通过阅读q篇文章Q希望你能对 Lucene 的烦引机制有所了解Qƈ且你会发现利?Lucene 创徏索引是非常简单的事情?/p>

Masen 2007-05-31 11:52 发表评论
]]>
lucene?/title><link>http://www.aygfsteel.com/masen/articles/120785.html</link><dc:creator>Masen</dc:creator><author>Masen</author><pubDate>Tue, 29 May 2007 16:43:00 GMT</pubDate><guid>http://www.aygfsteel.com/masen/articles/120785.html</guid><wfw:comment>http://www.aygfsteel.com/masen/comments/120785.html</wfw:comment><comments>http://www.aygfsteel.com/masen/articles/120785.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/masen/comments/commentRss/120785.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/masen/services/trackbacks/120785.html</trackback:ping><description><![CDATA[<h3 class=entry-header>在应用中加入全文索功能——基于Java的全文烦引引擎Lucene?/h3> <div id="wmqeeuq" class=entry-content> <div id="wmqeeuq" class=entry-body> <p>关键词:Lucene java full-text search engine Chinese word segment</p> <p><span style="FONT-WEIGHT: bold"></span></p> Lucene不是一个完整的全文索引应用Q而是是一个用Java写的全文索引引擎工具包,它可以方便的嵌入到各U应用中实现针对应用的全文烦?索功能? <p>Lucene的作者:Lucene的A献?a ><u><font color=#0000ff>Doug Cutting</font></u></a>?一位资深全文烦?索专Ӟ曄是V-Twin搜烦引擎(Apple的Copland操作pȝ的成׃一)的主要开发者,后在Excite担Q高pȝ 架构设计师,目前从事于一些INTERNET底层架构的研I。他贡献出的Lucene的目标是为各U中型应用E序加入全文索功能?/p> </div> <div id="wmqeeuq" class=entry-more id=more>Lucene的发展历E:早先发布在作者自q<a ><u><font color=#0000ff>www.lucene.com</font></u></a>Q后来发布在<a ><u><font color=#0000ff>SourceForge</font></u></a>Q?001q年底成为APACHE基金会jakarta的一个子目Q?a ><u><font color=#800080>http://jakarta.apache.org/lucene/</font></u></a> <p>已经有很多Java目都用了Lucene作ؓ其后台的全文索引引擎Q比较著名的有:</p> <ul> <li><a ><u><font color=#0000ff>J</font></u></a><a ><u><font color=#0000ff>ive</font></u></a>QWEB论坛pȝQ? <li><a ><u><font color=#0000ff>Eyebrows</font></u></a>Q邮件列表HTML归档/览/查询pȝQ本文的主要参考文?#8220;<a ><u><font color=#0000ff>TheLucene search engine: Powerful, flexible, and free</font></u></a>”作者就是EyeBrowspȝ的主要开发者之一Q而EyeBrows已经成ؓ目前APACHE目的主要邮件列表归系l? <li><a ><u><font color=#0000ff>Cocoon</font></u></a>:ZXML的web发布框架Q全文检索部分用了Lucene <li> <p align=left><a ><u><font color=#0000ff>Eclipse</font></u></a>:ZJava的开攑ּ发^収ͼ帮助部分的全文烦引用了Lucene</p> </li> </ul> <p>对于中文用户来说Q最兛_的问题是其是否支持中文的全文索。但通过后面对于Lucene的结构的介绍Q你会了解到׃Lucene良好架构设计Q对中文的支持只需对其语言词法分析接口q行扩展p实现对中文检索的支持?/p> <p><strong><a name=compare>全文索的实现机制</a></strong></p> <p>Lucene的API接口设计的比较通用Q输入输出结构都很像数据库的?=>记录==>字段Q所以很多传l的应用的文件、数据库{都可以比较方便的映到Lucene的存储结?接口中。M上看Q可以先?strong>Lucene当成一个支持全文烦引的数据库系l?/strong>?/p> <p>比较一下Lucene和数据库Q?/p> <table width="100%" border=1> <tbody> <tr> <td align=middle width="50%">Lucene</td> <td align=middle width="50%">数据?/td> </tr> <tr> <td width="50%"> <pre>索引数据源:doc(field1,field2...) doc(field1,field2...)<br> \ indexer /<br> _____________<br> | Lucene Index|<br> --------------<br> / searcher \<br> l果输出QHits(doc(field1,field2) doc(field1...))</pre> </td> <td width="50%"> <pre> 索引数据源:record(field1,field2...) record(field1..)<br> \ SQL: insert/<br> _____________<br> | DB Index |<br> -------------<br> / SQL: select \<br>l果输出Qresults(record(field1,field2..) record(field1...))</pre> </td> </tr> <tr> <td width="50%">DocumentQ一个需要进行烦引的“单元”<br>一个Document由多个字D늻?/td> <td width="50%">RecordQ记录,包含多个字段</td> </tr> <tr> <td width="50%">FieldQ字D?/td> <td width="50%">FieldQ字D?/td> </tr> <tr> <td width="50%">HitsQ查询结果集Q由匚w的Documentl成</td> <td width="50%">RecordSetQ查询结果集Q由多个Recordl成</td> </tr> </tbody> </table> <p><strong>全文?≠ like "%keyword%"</strong></p> <p>通常比较厚的书籍后面常常附关键词索引表(比如Q北京:12, 34, 上vQ?,77?#8230;…Q,它能够帮助读者比较快地找到相兛_容的늠。而数据库索引能够大大提高查询的速度原理也是一P惛_一下通过书后面的索引查找的速度要比一一地d定w多少?#8230;…而烦引之所以效率高Q另外一个原因是它是排好序的?strong>对于索系l来说核心是一个排序问?/strong>?/p> <p align=left>׃数据库烦引不是ؓ全文索引设计的,因此Q?strong>使用like "%keyword%"Ӟ数据库烦引是不v作用?/strong>Q在使用like查询Ӟ搜烦q程又变成类g一页M的遍历过E了Q所以对于含有模p查询的数据库服务来_LIKEҎ能的危x极大的。如果是需要对多个关键词进行模p匹配:like"%keyword1%" and like "%keyword2%" ...其效率也可惌知了?/p> <p>所以徏立一个高效检索系l的关键是徏立一个类gU技索引一L反向索引机制Q将数据源(比如多篇文章Q排序顺序存储的同时Q有另外一个排好序的关 键词列表Q用于存储关键词==>文章映射关系Q利用这L映射关系索引Q[关键?=>出现关键词的文章~号Q出现次敎ͼ甚至包括位置Qv?偏移量,l束偏移量)Q出现频率]Q检索过E就是把<strong>模糊查询变成多个可以利用索引的精查询的逻辑l合的过E?/strong>。从而大大提高了多关键词查询的效率,所以,全文索问题归l到最后是一个排序问题?/p> <p>由此可以看出模糊查询相对数据库的_查询是一个非怸定的问题,q也是大部分数据库对全文索支持有限的原因。Lucene最核心的特征是通过Ҏ的烦引结构实C传统数据库不擅长的全文烦引机Ӟq提供了扩展接口Q以方便针对不同应用的定制?/p> <p>可以通过一下表格对比一下数据库的模p查询:</p> <table height=283 width="100%" border=1> <tbody> <tr> <td align=middle width="9%" height=16> </td> <td align=middle width="47%" height=16>Lucene全文索引引擎</td> <td align=middle width="40%" height=16>数据?/td> </tr> <tr> <td width="9%" height=48>索引</td> <td width="47%" height=48>数据源中的数据都通过全文索引一一建立反向索引</td> <td width="40%" height=48>对于LIKE查询来说Q数据传l的索引是根本用不上的。数据需要逐个便利记录q行GREP式的模糊匚wQ比有烦引的搜烦速度要有多个数量U的下降?/td> </tr> <tr> <td width="9%" height=49>匚w效果</td> <td width="47%" height=49>通过词元(term)q行匚wQ通过语言分析接口的实玎ͼ可以实现对中文等非英语的支持?/td> <td width="40%" height=49>使用Qlike "%net%" 会把netherlands也匹配出来,<br>多个关键词的模糊匚wQ用like "%com%net%"Q就不能匚w词序颠倒的xxx.net..xxx.com</td> </tr> <tr> <td width="9%" height=32>匚w?/td> <td width="47%" height=32>有匹配度法Q将匚wE度Q相似度Q比较高的结果排在前面?/td> <td width="40%" height=32>没有匚wE度的控Ӟ比如有记录中net出现5词和出现1ơ的Q结果是一L?/td> </tr> <tr> <td width="9%" height=32>l果输出</td> <td width="47%" height=32>通过特别的算法,最匚w度最高的?00条结果输出,l果集是~冲式的批量读取的?/td> <td width="40%" height=32>q回所有的l果集,在匹配条目非常多的时候(比如上万条)需要大量的内存存放q些临时l果集?/td> </tr> <tr> <td width="9%" height=32>可定制?/td> <td width="47%" height=32>通过不同的语a分析接口实现Q可以方便的定制出符合应用需要的索引规则Q包括对中文的支持)</td> <td width="40%" height=32>没有接口或接口复杂,无法定制</td> </tr> <tr> <td width="9%" height=32>l论</td> <td width="47%" height=32>高负载的模糊查询应用Q需要负责的模糊查询的规则,索引的资料量比较?/td> <td width="40%" height=32>使用率低Q模p匹配规则简单或者需要模p查询的资料量少</td> </tr> </tbody> </table> <p><span style="FONT-WEIGHT: bold">全文索和数据库应用最大的不同在于Q让</span><span style="FONT-WEIGHT: bold">最相关?/span><span style="FONT-WEIGHT: bold">?00条结果满?8%以上用户的需?br></span><br>Lucene的创C处:</p> <p>大部分的搜烦Q数据库Q引擎都是用B树结构来l护索引Q烦引的更新会导致大量的IO操作QLucene在实CQ对此稍微有所改进Q不是维护一个烦 引文Ӟ而是在扩展烦引的时候不断创建新的烦引文Ӟ然后定期的把q些新的烦引文件合q到原先的大索引中(针对不同的更新策略,Ҏ的大可以调_Q?q样在不影响索的效率的前提下Q提高了索引的效率?/p> <p>Lucene和其他一些全文检索系l?应用的比较:</p> <table width="100%" border=1> <tbody> <tr> <td align=middle width="18%"> </td> <td align=middle width="45%">Lucene</td> <td align=middle width="37%">其他开源全文检索系l?/td> </tr> <tr> <td width="18%">增量索引和批量烦?/td> <td width="45%">可以q行增量的烦?Append)Q可以对于大量数据进行批量烦引,q且接口设计用于优化扚w索引和小扚w的增量烦引?/td> <td width="37%">很多pȝ只支持批量的索引Q有时数据源有一点增加也需要重建烦引?/td> </tr> <tr> <td width="18%">数据?/td> <td width="45%">Lucene没有定义具体的数据源Q而是一个文的l构Q因此可以非常灵zȝ适应各种应用Q只要前端有合适的转换器把数据源{换成相应l构Q,</td> <td width="37%">很多pȝ只针对网,~Z其他格式文档的灵zL?/td> </tr> <tr> <td width="18%">索引内容抓取</td> <td width="45%">Lucene的文是由多个字D늻成的Q甚臛_以控刉些字D需要进行烦引,那些字段不需要烦引,q一步烦引的字段也分为需要分词和不需要分词的cdQ?br>   需要进行分词的索引Q比如:标题Q文章内容字D?br>   不需要进行分词的索引Q比如:作?日期字段</td> <td width="37%">~Z通用性,往往文整个烦引了</td> </tr> <tr> <td width="18%">语言分析</td> <td width="45%">通过语言分析器的不同扩展实现Q?br>可以qo掉不需要的词:an the of {,<br>西文语法分析Q将jumps jumped jumper都归l成jumpq行索引/?br>非英文支持:对亚z语aQ阿拉伯语言的烦引支?/td> <td width="37%">~Z通用接口实现</td> </tr> <tr> <td width="18%">查询分析</td> <td width="45%">通过查询分析接口的实玎ͼ可以定制自己的查询语法规则:<br>比如Q?多个关键词之间的 + - and or关系{?/td> <td width="37%"> </td> </tr> <tr> <td width="18%">q发讉K</td> <td width="45%">能够支持多用L使用</td> <td width="37%"> </td> </tr> </tbody> </table> <p> </p> <p><strong><a name=segment>关于亚洲语言的的切分词问?Word Segment)</a></strong></p> <p>对于中文来说Q全文烦引首先还要解决一个语a分析的问题,对于英文来说Q语句中单词之间是天焉过I格分开的,但亚z语a的中日韩文语句中的字是一个字挨一个,所有,首先要把语句中按“?#8221;q行索引的话Q这个词如何切分出来是一个很大的问题?/p> <p>首先Q肯定不能用单个字符?si-gram)为烦引单元,否则?#8220;上v”Ӟ不能让含?#8220;上”也匹配?/p> <p>但一句话Q?#8220;北京天安?#8221;Q计机如何按照中文的语a习惯q行切分呢?<br>“北京 天安?#8221; q是“??天安?#8221;Q让计算够按照语a习惯q行切分Q往往需要机器有一个比较丰富的词库才能够比较准的识别句中的单词?/p> <p>另外一个解决的办法是采用自动切分算法:单词按?元语?bigram)方式切分出来Q比如:<br>"北京天安? ==> "北京 京天 天安 安门"?/p> <p>q样Q在查询的时候,无论是查?北京" q是查询"天安?Q将查询词组按同L规则q行切分Q?北京"Q?天安安门"Q多个关键词之间按与"and"的关pȝ合,同样能够正确地映到相应的烦引中。这U方式对于其他亚z语aQ韩文,日文都是通用的?/p> <p>Z自动切分的最大优Ҏ没有词表l护成本Q实现简单,~点是烦引效率低Q但对于中小型应用来_Z2元语法的切分q是够用的。基?元切分后的烦引一般大和源文件差不多Q而对于英文,索引文g一般只有原文g?0%-40%不同Q?/p> <table height=68 width="100%" border=1> <tbody> <tr> <td align=middle width="11%" height=18><br></td> <td align=middle width="39%" height=18>自动切分</td> <td align=middle width="50%" height=18>词表切分</td> </tr> <tr> <td width="11%" height=16>实现</td> <td width="39%" height=16>实现非常?/td> <td width="50%" height=16>实现复杂</td> </tr> <tr> <td width="11%" height=16>查询</td> <td width="39%" height=16>增加了查询分析的复杂E度Q?/td> <td width="50%" height=16>适于实现比较复杂的查询语法规?/td> </tr> <tr> <td width="11%" height=16>存储效率</td> <td width="39%" height=16>索引冗余大,索引几乎和原文一样大</td> <td width="50%" height=16>索引效率高,为原文大的30Q左?/td> </tr> <tr> <td width="11%" height=16>l护成本</td> <td width="39%" height=16>无词表维护成?/td> <td width="50%" height=16>词表l护成本非常高:中日韩等语言需要分别维护?br>q需要包括词频统计等内容</td> </tr> <tr> <td width="11%" height=16>适用领域</td> <td width="39%" height=16>嵌入式系l:q行环境资源有限<br>分布式系l:无词表同步问?br>多语a环境Q无词表l护成本</td> <td width="50%" height=16>Ҏ询和存储效率要求高的专业搜烦引擎<br></td> </tr> </tbody> </table> <p>目前比较大的搜烦引擎的语a分析法一般是Z以上2个机制的l合。关于中文的语言分析法Q大家可以在Google查关键词"wordsegment search"能找到更多相关的资料?/p> <p><a name=demo><strong>安装和?/strong></a></p> <p>下蝲Q?a ><u><font color=#800080>http://jakarta.apache.org/lucene/</font></u></a></p> <p>注意QLucene中的一些比较复杂的词法分析是用JavaCC生成的(JavaCCQJavaCompilerCompilerQ纯Java的词法分析生成器Q,所以如果从源代码编译或需要修改其中的QueryParser、定制自q词法分析器,q需要从<a ><u><font color=#0000ff>https://javacc.dev.java.net/</font></u></a>下蝲javacc?/p> <p>lucene的组成结构:对于外部应用来说索引模块(index)和检索模?search)是主要的外部应用入口</p> <table width="100%" border=1> <tbody> <tr> <td width="27%">org.apache.Lucene.search/</td> <td width="73%">搜烦入口</td> </tr> <tr> <td width="27%">org.apache.Lucene.index/</td> <td width="73%">索引入口</td> </tr> <tr> <td width="27%">org.apache.Lucene.analysis/</td> <td width="73%">语言分析?/td> </tr> <tr> <td width="27%">org.apache.Lucene.queryParser/</td> <td width="73%">查询分析?/td> </tr> <tr> <td width="27%">org.apache.Lucene.document/</td> <td width="73%">存储l构</td> </tr> <tr> <td width="27%">org.apache.Lucene.store/ </td> <td width="73%">底层IO/存储l构</td> </tr> <tr> <td width="27%">org.apache.Lucene.util/</td> <td width="73%">一些公用的数据l构</td> </tr> </tbody> </table> <p>单的例子演示一下Lucene的用方法:</p> 索引q程Q从命o行读取文件名Q多个)Q将文g分\?path字段)和内?body字段)2个字D进行存储,q对内容q行全文索引Q烦引的单位?Document对象Q每个Document对象包含多个字段Field对象Q针对不同的字段属性和数据输出的需求,对字D还可以选择不同的烦?存储?D规则,列表如下Q? <table border=1> <tbody> <tr> <th>Ҏ</th> <th>切词</th> <th>索引</th> <th>存储</th> <th>用?/th> </tr> <tr> <td>Field.Text(String name, String value)</td> <td>Yes</td> <td>Yes</td> <td>Yes</td> <td vAlign=top>切分词烦引ƈ存储Q比如:标题Q内容字D?/td> </tr> <tr> <td>Field.Text(String name, Reader value)</td> <td>Yes</td> <td>Yes</td> <td>No</td> <td vAlign=top>切分词烦引不存储Q比如:META信息Q?br>不用于返回显C,但需要进行检索内?/td> </tr> <tr> <td>Field.Keyword(String name, String value)</td> <td>No</td> <td>Yes</td> <td>Yes</td> <td vAlign=top>不切分烦引ƈ存储Q比如:日期字段</td> </tr> <tr> <td>Field.UnIndexed(String name, String value)</td> <td>No</td> <td>No</td> <td>Yes</td> <td vAlign=top>不烦引,只存储,比如Q文件\?/td> </tr> <tr> <td>Field.UnStored(String name, String value)</td> <td>Yes</td> <td>Yes</td> <td>No</td> <td vAlign=top>只全文烦引,不存?/td> </tr> </tbody> </table> <pre>public class IndexFiles { <br> //使用ҎQ? IndexFiles [索引输出目录] [索引的文件列表] ... <br> public static void main(String[] args) throws Exception {<br> String indexPath = args[0];<br> IndexWriter writer;<br> //用指定的语言分析器构造一个新的写索引器(W?个参数表C是否ؓq加索引Q?br> writer = new IndexWriter(indexPath, new SimpleAnalyzer(), false);<br><br> for (int i=1; i<args.length; i++) {<br> System.out.println("Indexing file " + args[i]);<br> InputStream is = new FileInputStream(args[i]);<br><br> //构造包?个字DField的Document对象<br> //一个是路径path字段Q不索引Q只存储<br> //一个是内容body字段Q进行全文烦引,q存?br> Document doc = new Document();<br> doc.add(Field.UnIndexed("path", args[i]));<br> doc.add(Field.Text("body", (Reader) new InputStreamReader(is)));<br> //文档写入烦?br> writer.addDocument(doc);<br> is.close();<br> };<br> //关闭写烦引器<br> writer.close();<br> }<br>}<br> </pre> <p>索引q程中可以看刎ͼ</p> <ul> <li>语言分析器提供了抽象的接口,因此语言分析(Analyser)是可以定制的Q虽然lucene~省提供?个比较通用的分析器 SimpleAnalyser和StandardAnalyserQ这2个分析器~省都不支持中文Q所以要加入对中文语a的切分规则,需要修改这2个分?器? <li>Luceneq没有规定数据源的格式,而只提供了一个通用的结构(Document对象Q来接受索引的输入,因此输入的数据源可以是:数据库,WORD文QPDF文QHTML文……只要能够设计相应的解析{换器数据源构造成成Docuement对象卛_q行索引? <li>对于大批量的数据索引Q还可以通过调整IndexerWrite的文件合q率属性(mergeFactorQ来提高扚w索引的效率?</li> </ul> <p>索过E和l果昄Q?/p> <p>搜烦l果q回的是Hits对象Q可以通过它再讉KDocument==>Field中的内容?/p> <p>假设Ҏbody字段q行全文索,可以查询结果的path字段和相应查询的匚w?score)打印出来Q?/p> <pre>public class Search { <br> public static void main(String[] args) throws Exception {<br> String indexPath = args[0], queryString = args[1];<br> //指向索引目录的搜索器<br> Searcher searcher = new IndexSearcher(indexPath);<br> //查询解析器:使用和烦引同L语言分析?br> Query query = QueryParser.parse(queryString, "body", <br> new SimpleAnalyzer());<br> //搜烦l果使用Hits存储<br> Hits hits = searcher.search(query);<br> //通过hits可以讉K到相应字D늚数据和查询的匚w?br> for (int i=0; i<hits.length(); i++) {<br> System.out.println(hits.doc(i).get("path") + "; Score: " + <br> hits.score(i));<br> };<br> }<br>}</pre> 在整个检索过E中Q语a分析器,查询分析器,甚至搜烦器(SearcherQ都是提供了抽象的接口,可以Ҏ需要进行定制? <p><strong><a name=hacking>Hacking Lucene</a></strong></p> <p><strong>化的查询分析?/strong></p> <p>个h感觉lucene成ؓJAKARTA目后,d了太多的旉用于调试日趋复杂QueryParserQ而其中大部分是大多数用户q不很熟悉的Q目前LUCENE支持的语法:</p> <p>Query ::= ( Clause )*<br>Clause ::= ["+", "-"] [<TERM> ":"] ( <TERM> | "(" Query ")")</p> <p>中间的逻辑包括Qand or + - &&||{符P而且q有"短语查询"和针对西文的前缀/模糊查询{,个h感觉对于一般应用来_q些功能有一些华而不实,其实能够实现 目前cM于Google的查询语句分析功能其实对于大多数用户来说已经够了。所以,Lucene早期版本的QueryParser仍是比较好的选择?/p> <p><strong>d修改删除指定记录QDocumentQ?/strong></p> <p>Lucene提供了烦引的扩展机制Q因此烦引的动态扩展应该是没有问题的,而指定记录的修改也似乎只能通过记录的删除,然后重新加入实现。如何删?指定的记录呢Q删除的Ҏ也很单,只是需要在索引时根据数据源中的记录ID专门另徏索引Q然后利用IndexReader.delete (Termterm)Ҏ通过q个记录ID删除相应的Document?/p> <p><strong>Ҏ某个字段值的排序功能</strong></p> <p>lucene~省是按照自q相关度算法(scoreQ进行结果排序的Q但能够Ҏ其他字段q行l果排序是一个在LUCENE的开发邮件列表中l常 提到的问题,很多原先Z数据库应用都需要除了基于匹配度QscoreQ以外的排序功能。而从全文索的原理我们可以了解刎ͼM不基于烦引的搜烦q程?率都会导致效率非常的低,如果Z其他字段的排序需要在搜烦q程中访问存储字D,速度回大大降低,因此非常是不可取的?/p> <p>但这里也有一个折中的解决ҎQ在搜烦q程中能够媄响排序结果的只有索引中已l存储的docID和scoreq?个参敎ͼ所以,Zscore以外 的排序,其实可以通过数据源预先排好序,然后ҎdocIDq行排序来实现。这样就避免了在LUCENE搜烦l果外对l果再次q行排序和在搜烦q程中访 问不在烦引中的某个字D倹{?/p> <p>q里需要修改的是IndexSearcher中的HitCollectorq程Q?/p> <pre>...<br> scorer.score(new HitCollector() {<br> private float minScore = 0.0f;<br> public final void collect(int doc, float score) {<br> if (score > 0.0f && // ignore zeroed buckets<br> (bits==null || bits.get(doc))) { // skip docs not in bits<br> totalHits[0]++;<br> if (score >= minScore) {<br> /* 原先QLucenedocID和相应的匚w度score例入l果命中列表中:<br> * hq.put(new ScoreDoc(doc, score)); // update hit queue<br> * 如果用doc ?1/doc 代替 scoreQ就实现了根据docID排或逆排<br> * 假设数据源烦引时已经按照某个字段排好了序Q而结果根据docID排序也就实现?br> * 针对某个字段的排序,甚至可以实现更复杂的score和docID的拟合?br> */<br> hq.put(new ScoreDoc(doc, (float) 1/doc )); <br> if (hq.size() > nDocs) { // if hit queue overfull<br> hq.pop(); // remove lowest in hit queue<br> minScore = ((ScoreDoc)hq.top()).score; // reset minScore<br> }<br> }<br> }<br> }<br> }, reader.maxDoc());</pre> <p><strong>更通用的输入输出接?/strong></p> <p>虽然lucene没有定义一个确定的输入文档格式Q但来多的h惛_使用一个标准的中间格式作ؓLucene的数据导入接口,然后其他数据Q比?PDF只需要通过解析器{换成标准的中间格式就可以q行数据索引了。这个中间格式主要以XMLZQ类似实现已l不?Q?个:</p> <pre>数据? WORD PDF HTML DB other<br> \ | | | /<br> XML中间格式<br> |<br> Lucene INDEX</pre> <p>目前q没有针对MSWord文档的解析器Q因为Word文档和基于ASCII的RTF文档不同Q需要用COM对象机制解析。这个是我在Google上查的相兌料:<a ><u><font color=#0000ff>http://www.intrinsyc.com/products/enterprise_applications.asp</font></u></a><br>另外一个办法就是把Word文档转换成textQ?a ><u><font color=#0000ff>http://www.winfield.demon.nl/index.html</font></u></a><br></p> <p><br><strong>索引q程优化</strong></p> <p>索引一般分2U情况,一U是批量的索引扩展Q一U是大批量的索引重徏。在索引q程中,q不是每ơ新的DOC加入q去索引都重新进行一ơ烦引文件的写入操作Q文件I/O是一仉常消耗资源的事情Q?/p> <p>Lucene先在内存中进行烦引操作,q根据一定的扚wq行文g的写入。这个批ơ的间隔大Q文件的写入ơ数少Q但占用内存会很多。反之占用内?,但文件IO操作频繁Q烦引速度会很慢。在IndexWriter中有一个MERGE_FACTOR参数可以帮助你在构造烦引器后根据应用环境的情况?分利用内存减文件的操作。根据我的用经验:~省Indexer是每20条记录烦引后写入一ơ,每将MERGE_FACTOR增加50倍,索引速度可以 提高1倍左叟?br></p> <p><span style="FONT-WEIGHT: bold">搜烦q程优化<br></span></p> <p><span style="FONT-WEIGHT: bold"></span>lucene支持内存索引Q这L搜烦比基于文件的I/O有数量的速度提升?br><a ><u><font color=#0000ff>http://www.onjava.com/lpt/a/3273</font></u></a><br>而尽可能减少IndexSearcher的创建和Ҏ索结果的前台的缓存也是必要的?br><span style="FONT-WEIGHT: bold"></span></p> <p>Lucene面向全文索的优化在于首次索引索后Qƈ不把所有的记录QDocumentQ具体内容读取出来,而v只将所有结果中匚w度最高的?100条结果(TopDocsQ的ID攑ֈl果集缓存中q返回,q里可以比较一下数据库索:如果是一?0,000条的数据库检索结果集Q数据库是一?要把所有记录内定w取得以后再开始返回给应用l果集的。所以即使检索匹配L很多QLucene的结果集占用的内存空间也不会很多。对于一般的模糊索应 用是用不到这么多的结果的Q头100条已l可以满?0%以上的检索需求?br></p> <p>如果首批~存l果数用完后q要d更后面的l果时Searcher会再ơ检索ƈ生成一个上ơ的搜烦~存数大1倍的~存Qƈ再重新向后抓取。所以如?构造一个SearcherL1Q?20条结果,Searcher其实是进行了2ơ搜索过E:?00条取完后Q缓存结果用完,Searcher重新?再构造一?00条的l果~存Q依此类推,400条缓存,800条缓存。由于每ơSearcher对象消失后,q些~存也访问那不到了,你有可能惛_l果 记录~存下来Q缓存数量保证?00以下以充分利用首ơ的l果~存Q不让Lucene费多次索,而且可以分q行l果~存?br></p> <p>Lucene的另外一个特Ҏ在收集结果的q程中将匚w度低的结果自动过滤掉了。这也是和数据库应用需要将搜烦的结果全部返回不同之处?/p> <p><a ><u><font color=#0000ff>我的一些尝?/font></u></a>Q?/p> <ul> <li>支持中文的TokenizerQ这里有2个版本,一个是通过JavaCC生成的,对CJK部分按一个字W一个TOKEN索引Q另外一个是从SimpleTokenizer改写的,对英文支持数字和字母TOKENQ对中文按P代烦引? <li>ZXML数据源的索引器:XMLIndexerQ因此所有数据源只要能够按照DTD转换成指定的XMLQ就可以用XMLIndxerq行索引了? <li>?据某个字D|序:按记录烦引顺序排序结果的搜烦器:IndexOrderSearcherQ因此如果需要让搜烦l果Ҏ某个字段排序Q可以让数据源先按某 个字D|好序Q比如:PriceFieldQ,q样索引后,然后在利用这个按记录的ID序索的搜烦器,l果是相当于是那个字段排序的结果了?</li> </ul> <p><a name=learn><strong>从Lucene学到更多</strong></a></p> <p>Luene的确是一个面对对象设计的典范</p> <ul> <li>所有的问题都通过一个额外抽象层来方便以后的扩展和重用:你可以通过重新实现来达到自q目的Q而对其他模块而不需要; <li>单的应用入口Searcher, IndexerQƈ调用底层一pdlg协同的完成搜索Q务; <li>所 有的对象的Q务都非常专一Q比如搜索过E:QueryParser分析查询语句{换成一pd的精查询的l合(Query),通过底层的烦引读取结?IndexReaderq行索引的读取,q用相应的打分器l搜索结果进行打?排序{。所有的功能模块原子化程度非帔RQ因此可以通过重新实现而不需要修 改其他模块?nbsp; <li>除了灉|的应用接口设计,Luceneq提供了一些适合大多数应用的语言分析器实玎ͼSimpleAnalyser,StandardAnalyserQ,q也是新用户能够很快上手的重要原因之一?</li> </ul> <p>q些优点都是非常值得在以后的开发中学习借鉴的。作Z个通用工具包,Lunece的确l予了需要将全文索功能嵌入到应用中的开发者很多的便利?/p> <p>此外Q通过对Lucene的学习和使用Q我也更深刻地理解了Z么很多数据库优化设计中要求,比如Q?/p> <ul> <li>可能对字段q行索引来提高查询速度Q但q多的烦引会Ҏ据库表的更新操作变慢Q而对l果q多的排序条Ӟ实际上往往也是性能的杀手之一? <li>很多商业数据库对大批量的数据插入操作会提供一些优化参敎ͼq个作用和烦引器的merge_factor的作用是cM的, <li>20%/80%原则Q查的结果多q不{于质量好,其对于q回l果集很大,如何优化q头几十条结果的质量往往才是最重要的? <li>可能让应用从数据库中获得比较小的结果集Q因为即使对于大型数据库Q对l果集的随机讉K也是一个非常消耗资源的操作?br></li> </ul> <p>参考资料:</p> <p>Apache: Lucene Project<br><a ><u><font color=#800080>http://jakarta.apache.org/lucene/<br></font></u></a>Lucene开?用户邮g列表归<br><a ><font color=#0000ff><u>Lucene-dev@jakarta.apache.org</u></font></a><br><a ><u><font color=#0000ff>Lucene-user@jakarta.apache.org</font></u></a></p> <p>The Lucene search engine: Powerful, flexible, and free<br><a ><u><font color=#0000ff>http://www.javaworld.com/javaworld/jw-09-2000/jw-0915-Lucene_p.html</font></u></a></p> <p>Lucene Tutorial<br><a ><u><font color=#0000ff>http://www.darksleep.com/puff/lucene/lucene.html</font></u></a></p> <p>Notes on distributed searching with Lucene<br><a ><u><font color=#0000ff>http://home.clara.net/markharwood/lucene/</font></u></a></p> <p>中文语言的切分词<br><a ><u><font color=#0000ff>http://www.google.com/search?sourceid=navclient&hl=zh-CN&q=chinese+word+segment</font></u></a></p> <p>搜烦引擎工具介绍<a ><br><u><font color=#0000ff>http://searchtools.com/</font></u></a></p> <p>Lucene作者Cutting的几论文和专利<br><a ><u><font color=#0000ff>http://lucene.sourceforge.net/publications.html</font></u></a> </p> <p>Lucene?NET实现QdotLucene<br><a ><u><font color=#0000ff>http://sourceforge.net/projects/dotlucene/<br></font></u></a></p> <p>Lucene作者Cutting的另外一个项目:ZJava的搜索引擎Nutch<br><a ><u><font color=#0000ff>http://www.nutch.org/</font></u></a>   <a ><u><font color=#0000ff>http://sourceforge.net/projects/nutch/<br></font></u></a></p> <p>关于Z词表和N-Gram的切分词比较<br><a ><u><font color=#0000ff>http://china.nikkeibp.co.jp/cgi-bin/china/news/int/int200302100112.html</font></u></a><br><br>2005-01-08 <a ><u><font color=#0000ff>Cutting在Pisa大学做的关于Lucene的讲座:非常详细的Lucene架构解说</font></u></a> </p> <p>特别感谢Q?br><a ><u><font color=#0000ff>前网易CTO许良?Jack Xu)</font></u></a>l我的指|是您我带入了搜索引擎这个行业?/p> 原文出处Qhttp://www.chedong.com/tech/lucene.html </div> </div> <img src ="http://www.aygfsteel.com/masen/aggbug/120785.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/masen/" target="_blank">Masen</a> 2007-05-30 00:43 <a href="http://www.aygfsteel.com/masen/articles/120785.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank">û</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ϫ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">п</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɳ</a>| <a href="http://" target="_blank">ղ</a>| <a href="http://" target="_blank">Ԫ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">̨</a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ӽ</a>| <a href="http://" target="_blank">ԭ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ͬ</a>| <a href="http://" target="_blank">˶</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">˳</a>| <a href="http://" target="_blank">첼</a>| <a href="http://" target="_blank">ƽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ϰ</a>| <a href="http://" target="_blank">˴</a>| <a href="http://" target="_blank">ͨ</a>| <a href="http://" target="_blank">÷</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">¸</a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>