﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-路漫漫其修远兮,吾将上下而求索!-随笔分类-lucene</title><link>http://www.blogjava.net/tangzurui/category/34670.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 29 Dec 2008 15:50:26 GMT</lastBuildDate><pubDate>Mon, 29 Dec 2008 15:50:26 GMT</pubDate><ttl>60</ttl><item><title>lucene查询一个简单的例子</title><link>http://www.blogjava.net/tangzurui/archive/2008/12/12/245969.html</link><dc:creator>梓枫</dc:creator><author>梓枫</author><pubDate>Fri, 12 Dec 2008 07:48:00 GMT</pubDate><guid>http://www.blogjava.net/tangzurui/archive/2008/12/12/245969.html</guid><wfw:comment>http://www.blogjava.net/tangzurui/comments/245969.html</wfw:comment><comments>http://www.blogjava.net/tangzurui/archive/2008/12/12/245969.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/tangzurui/comments/commentRss/245969.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tangzurui/services/trackbacks/245969.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: lucene查询一个简单的例子&nbsp;&nbsp;<a href='http://www.blogjava.net/tangzurui/archive/2008/12/12/245969.html'>阅读全文</a><img src ="http://www.blogjava.net/tangzurui/aggbug/245969.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tangzurui/" target="_blank">梓枫</a> 2008-12-12 15:48 <a href="http://www.blogjava.net/tangzurui/archive/2008/12/12/245969.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Lucene搜索引擎API的主要类介绍</title><link>http://www.blogjava.net/tangzurui/archive/2008/10/07/232867.html</link><dc:creator>梓枫</dc:creator><author>梓枫</author><pubDate>Tue, 07 Oct 2008 03:16:00 GMT</pubDate><guid>http://www.blogjava.net/tangzurui/archive/2008/10/07/232867.html</guid><wfw:comment>http://www.blogjava.net/tangzurui/comments/232867.html</wfw:comment><comments>http://www.blogjava.net/tangzurui/archive/2008/10/07/232867.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tangzurui/comments/commentRss/232867.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tangzurui/services/trackbacks/232867.html</trackback:ping><description><![CDATA[Lucene搜索的api的类主要有4个 IndexSearcher ,Query（包括子类）,QueryParser,Hits<br /><strong>一:IndexSearcher是搜索的入口，他的search方法提供了搜索功能</strong><br />Query有很多子类， 各种不同的子类代表了不同的查询条件,下文详述<br />QueryParser是一个非常通用的帮助类，他的作用是把用户输入的文本转换为内置的Query对象（大多数web搜索引擎都提供一个查询输入框来让用户输入查询条件）。QueryParser内置提供了很多语法来使使用可以输入各种高级条件的Query。比如: "Hello AND world"会被解析为一个AND关系的BooleanQuery，他包含两个TermQuery(Hell和world)。这些语法虽然强大，但都针对英文设计，对我们需要中文搜索来说都不需要了解太多的Query类型，一般几个简单的就够用了。QueryParser的使用如下<br />QueryParser.parse(String query, String field, Analyzer analyzer) throws ParseException<br />其中：query是用户输入的内容,field是搜索默认的field（其他field需要显式指定），analyzer是用来将用户输入的内容也作分析处理（分词），一般情况下这里的anaylyzer是index的时候采用的同一analyzer。<br />另外我们也可以自己构造一个QueryParser: new QueryParser(String field, Analyzer a)(含义同上),这样做的好处是可以自己定义调整一些参数.<br />搜索结果的处理:Hits对象<br />Hits对象是搜索结果的集合 主要有下面几个方法 <br />length() ,这个方法记录有多少条结果返回(lazy loading) <br />doc(n) 返回第n个记录 <br />id(in) 返回第n个记录的Document ID <br />score(n) 第n个记录的相关度(积分)<br />由于搜索的结果一般比较大，从性能上考虑，Hits对象并不会真正把所有的结果全部取回，默认情况下是保留前100个记录(对于一般的搜索引擎,100个记录足够了).<br />分页的处理<br />100条记录还是太多，我们多半会每页显示20条记录，然后分为若干页显示，对于分页，一般有两个办法 <br />在session中保留indexreader对象和hit对象，翻页的时候提取内容 <br />不使用session，每次都简单处理为重新查询<br />lucene推荐先使用第二个办法，即每次都重新查询，这样做的好处是简单方便，不需要考虑session的问题，lucene的查询效率也能保证每次查询时间不长，除非真正有了性能问题，否则不用考虑第一个办法。<br />缓存：RAMDirectory的用法<br />RAMDirectory对象很好用，通过它，我们可以把一个普通的index完全读取到内存中,用法如下：<br />RAMDirectory ramDir = new RAMDirectory(dir);<br />这样的ramdir效率自然比真正的文件系统快很多<br />Lucene的scoring算法<br />lucence查询的纪录默认按照相关度排序，这个相关度就是score,scoring的算法是比较复杂的,对于我们做应用的人似乎没有什么帮助，（先说一下Term: 我的理解是Term为一个独立的查询词,用户输入的的查询通过各种分词，大小写处理(正规化),消除stopwords等）以后，会已Term为基本单位），几个关键参数稍微留意一下即可。<br />Term在文章中出现的频率量 <br />包含同一个Term的文章的频率 <br />field中的boosting参数 <br />term的长度 <br />term在文章中的数量<br />一般来说,这些参数我们都不可能去调整, 如果你想了解更多,IndexSearcher还提供了一个explain方法, 通过传入一个Query和document ID,你可以得到一个Explaination对象,他是对内部算法信息的简单封装,toString()一下就可以看到详细的说明 <br /><strong>二:创建Query:各种query介绍</strong><br />最普通的TermQuery<br />TermQuery最普通, 用Term t=new Term("contents","cap"); new TermQuery(t)就可以构造<br />TermQuery把查询条件视为一个key, 要求和查询内容完全匹配,比如Field.Keyword类型就可以使用TermQuery<br />RangeQuery<br />RangeQuery表示一个范围的搜索条件,RangeQuery query = new RangeQuery(begin, end, included);<br />最后一个boolean值表示是否包含边界条件本身, 用字符表示为"[begin TO end]" 或者"{begin TO end}"<br />PrefixQuery<br />顾名思义,就是表示以某某开头的查询, 字符表示为"something*"<br />BooleanQuery<br />这个是一个组合的Query,你可以把各种Query添加进去并标明他们的逻辑关系,添加条件用<br />public void add(Query query, boolean required, boolean prohibited)<br />方法, 后两个boolean变量是标示AND or NOT三种关系 字符表示为" AND or NOT" 或 "+ -" ,一个BooleanQuery中可以添加多个Query, 如果超过setMaxClauseCount(int)的值(默认1024个)的话,会抛出TooManyClauses错误.<br />PhraseQuery<br />表示不严格语句的查询,比如"red pig"要匹配"red fat pig","red fat big pig"等,PhraseQuery所以提供了一个setSlop()参数,在查询中,lucene会尝试调整单词的距离和位置,这个参数表示可以接受调整次数限制,如果实际的内容可以在这么多步内调整为完全匹配,那么就被视为匹配.在默认情况下slop的值是0, 所以默认是不支持非严格匹配的, 通过设置slop参数(比如"red pig"匹配"red fat pig"就需要1个slop来把pig后移动1位),我们可以让lucene来模糊查询. 值得注意的是,PhraseQuery不保证前后单词的次序,在上面的例子中,"pig red"需要2个slop,也就是如果slop如果大于等于2,那么"pig red"也会被认为是匹配的.<br />WildcardQuery<br />使用?和*来表示一个或多个字母比如wil*可以匹配 wild ,wila ,wilxaaaa...,值得注意的是,在wildcard中,只要是匹配上的纪录,他们的相关度都是一样的,比如wilxaaaa和wild的对于wil*的相关度就是一样的.<br />FuzzyQuery<br />这个Query对中文没有什么用处,他能模糊匹配英文单词(前面的都是词组),比如fuzzy和wuzzy他们可以看成类似, 对于英文的各种时态变化和复数形式,这个FuzzyQuery还算有用,匹配结果的相关度是不一样的.字符表示为 "fuzzy~"<br /><strong>三:QueryParser使用</strong><br />对于搜索引擎, 很多情况下用户只需要一个输入框就要输入所有的查询条件(比如google), 这时,QueryParser就派上用场了,他的作用就是把各种用户输入转为Query或者Query组, 他把上面提到的Query的字符表示(Query.toString)转化为实际的Query对象,比如"wuzzy~"就会转换为FuzzyQuery, 不过QueryParser用到了Analyzer,所以QueryParser parse过后的Query再toString未必和原来的一样.Query额外的语法有:<br />分组:Groupping<br />比如"(a AND b) or C",就是括号分组,很容易理解<br />FieldSelectiong<br />QueryParser的查询条件是对默认的Field进行的, 它在QueryParser解析的时候编码指定, 如果用户需要在查询条件中选用另外的Field, 可以使用如下语法: fieldname:fielda, 如果是多个分组,可以用fieldname:(fielda fieldb fieldc)表示.<br />*号问题<br />QueryParse默认不允许*号出现在开始部分，这样做的目的主要是为了防止用户误输入*来头导致严重的性能问题（会把所有记录读出）<br />boosting<br />通过hello^2.0 可以对hello这个term进行boosting，(我想不到什么用户会这样么bt)<br />QueryParser是一个准备好的,立即可以工作的帮助类,不过他还是提供了很多参数供程序员调整，首先,我们需要自己构造一个新的QueryParser,然后对他的各种参数来定制化 <br /><img src ="http://www.blogjava.net/tangzurui/aggbug/232867.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tangzurui/" target="_blank">梓枫</a> 2008-10-07 11:16 <a href="http://www.blogjava.net/tangzurui/archive/2008/10/07/232867.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>lucene具体的查询语句</title><link>http://www.blogjava.net/tangzurui/archive/2008/09/22/230357.html</link><dc:creator>梓枫</dc:creator><author>梓枫</author><pubDate>Mon, 22 Sep 2008 02:17:00 GMT</pubDate><guid>http://www.blogjava.net/tangzurui/archive/2008/09/22/230357.html</guid><wfw:comment>http://www.blogjava.net/tangzurui/comments/230357.html</wfw:comment><comments>http://www.blogjava.net/tangzurui/archive/2008/09/22/230357.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tangzurui/comments/commentRss/230357.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tangzurui/services/trackbacks/230357.html</trackback:ping><description><![CDATA[
		<p>本文主要结合测试案例介绍了Lucene下的各种查询语句以及它们的简化方法.<br />通过本文你将了解Lucene的基本查询语句,并可以学习所有的测试代码已加强了解.<br /><br /></p>
		<p>
				<strong>
						<strong>具体的查询语句</strong>
						<strong>
								<br />
						</strong>
				</strong>
		</p>
		<p>在了解了SQL后, 你是否想了解一下查询语法树?在这里简要介绍一些能被Lucene直接使用的查询语句.</p>
		<p>
				<strong>
						<strong>1.         </strong>
						<strong>TermQuery</strong>
				</strong>
				<strong>
						<br />
				</strong>查询某个特定的词,在文章开始的例子中已有介绍.常用于查询关键字.</p>
		<p>       <span class="code"><strong><font face="Courier New" color="#3366ff">      [Test]<br /></font></strong></span><span class="code"><strong><font face="Courier New" color="#3366ff">         public void Keyword()<br />         {<br />              IndexSearcher searcher = new IndexSearcher(directory);<br />              Term t = new Term("isbn", "1930110995");<br />              Query query = new TermQuery(t);<br />              Hits hits = searcher.Search(query);<br /></font></strong></span><span class="code"><strong><font face="Courier New" color="#3366ff">              Assert.AreEqual(1, hits.Length(), "JUnit in Action");<br />         }<br /></font></strong></span></p>
		<p align="left">注意Lucene中的关键字,是需要用户去保证唯一性的.</p>
		<p>
				<strong> TermQuery和QueryParse<br /></strong>
		</p>
		<p>只要在QueryParse的Parse方法中只有一个word,就会自动转换成TermQuery.</p>
		<p>
				<strong>
						<strong>
								<strong>2.         </strong>
								<strong>RangeQuery<br /></strong>
						</strong>
				</strong>用于查询范围,通常用于时间,还是来看例子:</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>namespace dotLucene.inAction.BasicSearch<br />{<br />     public class RangeQueryTest : LiaTestCase<br />     {<br />         private Term begin, end; </strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         [SetUp]<br />         protected override void Init()<br />         {<br />              begin = new Term("pubmonth", "200004");</strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>              end = new Term("pubmonth", "200206");<br />              base.Init();<br />         }<br /></strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         [Test]<br />         public void Inclusive()<br />         {<br />              RangeQuery query = new RangeQuery(begin, end, true);<br />              IndexSearcher searcher = new IndexSearcher(directory);<br /></strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>              Hits hits = searcher.Search(query);<br />              Assert.AreEqual(1, hits.Length());<br />         } </strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         [Test]<br />         public void Exclusive()<br />         {<br />              RangeQuery query = new RangeQuery(begin, end, false);<br />              IndexSearcher searcher = new IndexSearcher(directory);<br /></strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>              Hits hits = searcher.Search(query);<br />              Assert.AreEqual(0, hits.Length());<br />         }</strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<strong>
								<font face="Courier New" color="#3366ff">     }<br />}<br /></font>
						</strong>
				</span>
		</p>
		<p align="left">RangeQuery的第三个参数用于表示是否包含该起止日期.</p>
		<p>
				<strong>RangeQuery</strong>
				<strong>和</strong>
				<strong>QueryParse</strong>
		</p>
		<p>        <span class="code"><font face="Courier New" color="#3366ff"><strong>      [Test]<br />         public void TestQueryParser()<br />         {<br />              Query query = QueryParser.Parse("pubmonth:[200004 TO 200206]", "subject", new SimpleAnalyzer());<br />              Assert.IsTrue(query is RangeQuery);<br />              IndexSearcher searcher = new IndexSearcher(directory);<br />              Hits hits = searcher.Search(query);<br /></strong></font></span></p>
		<p>
				<span class="code">
						<strong>
								<font face="Courier New" color="#3366ff">              query = QueryParser.Parse("{200004 TO 200206}", "pubmonth", new SimpleAnalyzer());<br />              hits = searcher.Search(query);<br />              Assert.AreEqual(0, hits.Length(), "JDwA in 200206");<br />         } </font>
						</strong>
				</span>
		</p>
		<p align="left">Lucene用[] 和{}分别表示包含和不包含.</p>
		<p>
				<strong>3.   </strong>
				<strong>PrefixQuery</strong>
		</p>
		<p align="left">用于搜索是否包含某个特定前缀,常用于Catalog的检索.</p>
		<p>    <span class="code"><font face="Courier New" color="#3366ff"><strong>       [Test]<br />         public  void  TestPrefixQuery()<br />         {<br />              PrefixQuery query = new PrefixQuery(new Term("category", "/Computers"));<br /></strong></font></span></p>
		<p>
				<span class="code">
						<strong>
								<font face="Courier New" color="#3366ff">              IndexSearcher searcher = new IndexSearcher(directory);<br />              Hits hits = searcher.Search(query);<br />              Assert.AreEqual(2, hits.Length());<br />              <br />              query = new PrefixQuery(new Term("category", "/Computers/JUnit"));<br />              hits = searcher.Search(query);<br />              Assert.AreEqual(1, hits.Length(), "JUnit in Action");<br />         }<br /></font>
						</strong>
				</span>
		</p>
		<p>
				<strong>PrefixQuery和QueryParse</strong>
		</p>
		<p>              <span class="code"><font face="Courier New" color="#3366ff"><strong>[Test]<br />         public void TestQueryParser()<br />         {</strong></font></span></p>
		<p>
				<span class="code">
						<strong>
								<font face="Courier New" color="#3366ff">              QueryParser qp = new QueryParser("category", new SimpleAnalyzer());<br />              qp.SetLowercaseWildcardTerms(false);<br />              Query query =qp.Parse("/Computers*");<br />              Console.Out.WriteLine("query = {0}", query.ToString());<br />              IndexSearcher searcher = new IndexSearcher(directory);<br />              Hits hits = searcher.Search(query);<br />              Assert.AreEqual(2, hits.Length());<br />              query =qp.Parse("/Computers/JUnit*");<br />              hits = searcher.Search(query);<br />              Assert.AreEqual(1, hits.Length(), "JUnit in Action");<br />         }<br /></font>
						</strong>
				</span>
		</p>
		<p align="left">这里需要注意的是我们使用了QueryParser对象,而不是QueryParser类. 原因在于使用对象可以对QueryParser的一些默认属性进行修改.比如在上面的例子中我们的category是大写的,而QueryParser默认会把所有的含*的查询字符串变成小写/computer*. 这样我们就会查不到原文中的/Computers* ,所以我们需要通过设置QueryParser的默认属性来改变这一默认选项.即qp.SetLowercaseWildcardTerms(false)所做的工作. </p>
		<p>
				<strong>4.    </strong>
				<strong>BooleanQuery<br /></strong>
		</p>
		<p align="left">用于测试满足多个条件.</p>
		<p align="left">下面两个例子用于分别测试了满足与条件和或条件的情况.</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         [Test]<br />         public void And()<br />         {<br />              TermQuery searchingBooks =<br />                   new TermQuery(new Term("subject", "junit"));<br /></strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>              RangeQuery currentBooks =<br />                   new RangeQuery(new Term("pubmonth", "200301"),<br />                                  new Term("pubmonth", "200312"),<br />                                  true);<br /></strong>
						</font>
				</span>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>              BooleanQuery currentSearchingBooks = new BooleanQuery();<br />              currentSearchingBooks.Add(searchingBooks, true, false);<br />              currentSearchingBooks.Add(currentBooks, true, false);<br /></strong>
						</font>
				</span>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>              IndexSearcher searcher = new IndexSearcher(directory);<br />              Hits hits = searcher.Search(currentSearchingBooks);</strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>              AssertHitsIncludeTitle(hits, "JUnit in Action");<br />         }<br /></strong>
						</font>
				</span>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         [Test]<br />         public void Or()<br />         {<br />              TermQuery methodologyBooks = new TermQuery(<br />                   new Term("category",<br />                            "/Computers/JUnit"));<br /></strong>
						</font>
				</span>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>              TermQuery easternPhilosophyBooks = new TermQuery(<br />                   new Term("category",<br />                            "/Computers/Ant"));<br /></strong>
						</font>
				</span>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>              BooleanQuery enlightenmentBooks = new BooleanQuery();<br />              enlightenmentBooks.Add(methodologyBooks, false, false);<br />              enlightenmentBooks.Add(easternPhilosophyBooks, false, false);<br /></strong>
						</font>
				</span>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>              IndexSearcher searcher = new IndexSearcher(directory);<br />              Hits hits = searcher.Search(enlightenmentBooks);<br />              Console.Out.WriteLine("or = " + enlightenmentBooks);<br /></strong>
						</font>
				</span>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>              AssertHitsIncludeTitle(hits, "Java Development with Ant");<br />              AssertHitsIncludeTitle(hits, "JUnit in Action");</strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<strong>
								<font face="Courier New" color="#3366ff">         }</font>
						</strong>
				</span>
		</p>
		<p>什么时候是与什么时候又是或? 关键在于BooleanQuery对象的Add方法的参数.</p>
		<p>参数一是待添加的查询条件.</p>
		<p>参数二Required表示这个条件必须满足吗? True表示必须满足, False表示可以不满足该条件.</p>
		<p>参数三Prohibited表示这个条件必须拒绝吗? True表示这么满足这个条件的结果要排除, False表示可以满足该条件.</p>
		<p>这样会有三种组合情况,如下表所示:</p>
		<p>
				<img src="http://www.alphatom.com/images/stories/img_pictures/Lucene6.1.Jpeg" onload="imgResize(this)" border="0" script_onload="imgResize(this)" />
		</p>
		<p>
				<strong>BooleanQuery</strong>
				<strong>和</strong>
				<strong>QueryParse</strong>
		</p>
		<p>
				<strong>
						<font color="#3366ff">
								<font face="Courier New">
										<span class="code">         [Test]<br />         public void TestQueryParser()<br />         {<br />              Query query = QueryParser.Parse("pubmonth:[200301 TO 200312] AND junit", "subject", new SimpleAnalyzer());<br />              IndexSearcher searcher = new IndexSearcher(directory);<br />              Hits hits = searcher.Search(query);<br />              Assert.AreEqual(1, hits.Length());<br />              query = QueryParser.Parse("/Computers/JUnit OR /Computers/Ant", "category", new WhitespaceAnalyzer());<br />              hits = searcher.Search(query);<br />              Assert.AreEqual(2, hits.Length());<br />         }</span>
										<br />
								</font>
						</font>
				</strong>
		</p>
		<p>注意AND和OR的大小 如果想要Ａ与非B 就用 A AND –B 表示, +A –B也可以.</p>
		<p>默认的情况下QueryParser会把空格认为是或关系,就象google一样.但是你可以通过QueryParser对象修改这一属性.</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>[Test]<br />         public void TestQueryParserDefaultAND()<br />         {<br />              QueryParser qp = new QueryParser("subject", new SimpleAnalyzer());<br />              qp.SetOperator(QueryParser.DEFAULT_OPERATOR_AND );<br />              Query query = qp.Parse("pubmonth:[200301 TO 200312] junit");<br />              IndexSearcher searcher = new IndexSearcher(directory);<br />              Hits hits = searcher.Search(query);<br />              Assert.AreEqual(1, hits.Length());</strong>
						</font>
				</span>
		</p>
		<p>
				<strong>
						<font color="#3366ff">
								<font face="Courier New">
										<span class="code">         }</span>
										<br />
								</font>
						</font>5.         PhraseQuery<br /></strong>查询短语,这里面主要有一个slop的概念, 也就是各个词之间的位移偏差, 这个值会影响到结果的评分.如果slop为0,当然最匹配.看看下面的例子就比较容易明白了,有关slop的计算用户就不需要理解了,不过slop太大的时候对查询效率是有影响的,所以在实际使用中要把该值设小一点.<strong> </strong>PhraseQuery对于短语的顺序是不管的,这点在查询时除了提高命中率外,也会对性能产生很大的影响, 利用SpanNearQuery可以对短语的顺序进行控制,提高性能.<br />        <span class="code"><font face="Courier New" color="#3366ff"><strong>[SetUp]<br />     protected void Init()<br />     {<br />         // set up sample document<br />         RAMDirectory directory = new RAMDirectory();<br />         IndexWriter writer = new IndexWriter(directory,<br />                                              new WhitespaceAnalyzer(), true);<br />         Document doc = new Document();<br />         doc.Add(Field.Text("field",<br />                            "the quick brown fox jumped over the lazy dog"));<br />         writer.AddDocument(doc);<br />         writer.Close();</strong></font></span></p>
		<p>
				<span class="code">
						<strong>
								<font face="Courier New" color="#3366ff">         searcher = new IndexSearcher(directory);<br />     }<br /></font>
						</strong>
				</span>    <span class="code"><font face="Courier New" color="#3366ff"><strong>  private bool matched(String[] phrase, int slop)<br />     {<br />         PhraseQuery query = new PhraseQuery();<br />         query.SetSlop(slop);<br /></strong></font></span></p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         for (int i = 0; i &lt; phrase.Length; i++)<br />         {<br />              query.Add(new Term("field", phrase[i]));<br />         }<br /></strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         Hits hits = searcher.Search(query);<br />         return hits.Length() &gt; 0;<br />     }</strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>     [Test]<br />     public void SlopComparison()<br />     {<br />         String[] phrase = new String[]{"quick", "fox"};<br /></strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         Assert.IsFalse(matched(phrase, 0), "exact phrase not found");</strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         Assert.IsTrue(matched(phrase, 1), "close enough");<br />     }<br /></strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>     [Test]<br />     public void Reverse()<br />     {<br />         String[] phrase = new String[] {"fox", "quick"};</strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         Assert.IsFalse(matched(phrase, 2), "exact phrase not found");</strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         Assert.IsTrue(matched(phrase, 3), "close enough");<br />     }</strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<strong>
								<font face="Courier New" color="#3366ff">     [Test]<br />     public void Multiple()-<br />     {<br />         Assert.IsFalse(matched(new String[] {"quick", "jumped", "lazy"}, 3), "not close enough");<br />         Assert.IsTrue(matched(new String[] {"quick", "jumped", "lazy"}, 4), "just enough");<br />         Assert.IsFalse(matched(new String[] {"lazy", "jumped", "quick"}, 7), "almost but not quite");<br />         Assert.IsTrue(matched(new String[] {"lazy", "jumped", "quick"}, 8), "bingo");<br />     }</font>
						</strong>
				</span>
		</p>
		<p align="left">
				<strong>PhraseQuery和QueryParse</strong>
		</p>
		<p align="left">利用QueryParse进行短语查询的时候要先设定slop的值,有两种方式如下所示</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>[Test]<br />     public void TestQueryParser()<br />     {<br />         Query q1 = QueryParser.Parse(""quick fox"",<br />              "field", new SimpleAnalyzer());<br />         Hits hits1 = searcher.Search(q1);<br />         Assert.AreEqual(hits1.Length(), 0);<br /></strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         Query q2 = QueryParser.Parse(""quick fox"~1",          //第一种方式<br />                                     "field", new SimpleAnalyzer());<br />         Hits hits2 = searcher.Search(q2);<br />         Assert.AreEqual(hits2.Length(), 1);</strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<strong>
								<font face="Courier New" color="#3366ff">         QueryParser qp = new QueryParser("field", new SimpleAnalyzer());<br />         qp.SetPhraseSlop(1);                                    //第二种方式<br />         Query q3=qp.Parse(""quick fox"");<br />         Assert.AreEqual(""quick fox"~1", q3.ToString("field"),"sloppy, implicitly");<br />         Hits hits3 = searcher.Search(q2);<br />         Assert.AreEqual(hits3.Length(), 1);<br />     }<br /></font>
						</strong>
				</span>
		</p>
		<p>
				<strong>6.         WildcardQuery<br /></strong>通配符搜索,需要注意的是child, mildew的分值是一样的. <br /><strong><font color="#3366ff"><font face="Courier New"><span class="code">         [Test]<br />         public void Wildcard()<br />         {<br />              IndexSingleFieldDocs(new Field[]<br />                   {<br />                       Field.Text("contents", "wild"),<br />                       Field.Text("contents", "child"),<br />                       Field.Text("contents", "mild"),<br />                       Field.Text("contents", "mildew")<br />                   });<br />              IndexSearcher searcher = new IndexSearcher(directory);<br />              Query query = new WildcardQuery(<br />                   new Term("contents", "?ild*"));<br />              Hits hits = searcher.Search(query);<br />              Assert.AreEqual(3, hits.Length(), "child no match");<br />              Assert.AreEqual(hits.Score(0), hits.Score(1), 0.0, "score the same");<br />              Assert.AreEqual(hits.Score(1), hits.Score(2), 0.0, "score the same");<br />         }</span><br /></font></font>WildcardQuery和QueryParse<br /></strong>需要注意的是出于性能的考虑使用QueryParse的时候,不允许在开头就使用就使用通配符.<br />同样处于性能考虑会将只在末尾含有*的查询词转换为PrefixQuery.<br /><font color="#3366ff"><strong><font face="Courier New"><span class="code">         [Test, ExpectedException(typeof (ParseException))]<br />         public void TestQueryParserException()<br />         {<br />              Query query = QueryParser.Parse("?ild*", "contents", new WhitespaceAnalyzer());<br /></span><span class="code">         }</span></font></strong></font></p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         [Test]<br />         public void TestQueryParserTailAsterrisk()<br />         {<br />              Query query = QueryParser.Parse("mild*", "contents", new WhitespaceAnalyzer());<br />              Assert.IsTrue(query is PrefixQuery);<br />              Assert.IsFalse(query is WildcardQuery);</strong>
						</font>
				</span>
		</p>
		<p>
				<span class="code">
						<font face="Courier New" color="#3366ff">
								<strong>         }</strong>
						</font>
				</span>
		</p>
		<p>
				<strong>
						<span class="code">
								<font face="Courier New" color="#3366ff">         [Test]<br />         public void TestQueryParser()<br />         {<br />              Query query = QueryParser.Parse("mi?d*", "contents", new WhitespaceAnalyzer());<br />              Hits hits = searcher.Search(query);<br />              Assert.AreEqual(2, hits.Length());<br />         }<br /></font>
						</span>7.         FuzzyQuery<br /></strong>模糊查询, 需要注意的是两个匹配项的分值是不同的,这点和WildcardQuery是不同的</p>
		<p>
				<span class="code">
						<strong>
								<font face="Courier New" color="#3366ff">         [Test]<br />         public void Fuzzy()<br />         {<br />              Query query = new FuzzyQuery(new Term("contents", "wuzza"));<br />              Hits hits = searcher.Search(query);<br />              Assert.AreEqual( 2, hits.Length(),"both close enough");<br />              Assert.IsTrue(hits.Score(0) != hits.Score(1),"wuzzy closer than fuzzy");<br />              Assert.AreEqual("wuzzy", hits.Doc(0).Get("contents"),"wuzza bear");<br />         }</font>
						</strong>
				</span>
		</p>
		<span class="code">
				<p>
						<br />
						<strong>FuzzyQuery和QueryParse</strong>
				</p>
		</span>
		<p>注意和PhraseQuery中表示slop的区别,前者~后要跟数字.</p>
		<p>
				<span class="code">
						<strong>
								<font face="Courier New" color="#3366ff">         [Test]<br />         public void TestQueryParser()<br />         {<br />              Query query =QueryParser.Parse("wuzza~","contents",new SimpleAnalyzer());<br />              Hits hits = searcher.Search(query);<br />              Assert.AreEqual( 2, hits.Length(),"both close enough");<br />         }<br /></font>
						</strong>
				</span>
		</p>
<img src ="http://www.blogjava.net/tangzurui/aggbug/230357.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tangzurui/" target="_blank">梓枫</a> 2008-09-22 10:17 <a href="http://www.blogjava.net/tangzurui/archive/2008/09/22/230357.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第 1 部分: 初识 Lucene</title><link>http://www.blogjava.net/tangzurui/archive/2008/09/17/229380.html</link><dc:creator>梓枫</dc:creator><author>梓枫</author><pubDate>Wed, 17 Sep 2008 04:10:00 GMT</pubDate><guid>http://www.blogjava.net/tangzurui/archive/2008/09/17/229380.html</guid><wfw:comment>http://www.blogjava.net/tangzurui/comments/229380.html</wfw:comment><comments>http://www.blogjava.net/tangzurui/archive/2008/09/17/229380.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/tangzurui/comments/commentRss/229380.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/tangzurui/services/trackbacks/229380.html</trackback:ping><description><![CDATA[
		<blockquote>本文首先介绍了Lucene的一些基本概念，然后开发了一个应用程序演示了利用Lucene建立索引并在该索引上进行搜索的过程。</blockquote>
		<!--START RESERVED FOR FUTURE USE INCLUDE FILES-->
		<!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters -->
		<!--END RESERVED FOR FUTURE USE INCLUDE FILES-->
		<p>
				<a name="N10043">
						<span class="atitle">Lucene 简介</span>
				</a>
		</p>
		<p>Lucene 是一个基于 Java 的全文信息检索工具包，它不是一个完整的搜索应用程序，而是为你的应用程序提供索引和搜索功能。Lucene 目前是 Apache Jakarta 家族中的一个开源项目。也是目前最为流行的基于 Java 开源全文检索工具包。</p>
		<p>目前已经有很多应用程序的搜索功能是基于 Lucene 的，比如 Eclipse 的帮助系统的搜索功能。Lucene 能够为文本类型的数据建立索引，所以你只要能把你要索引的数据格式转化的文本的，Lucene 就能对你的文档进行索引和搜索。比如你要对一些 HTML 文档，PDF 文档进行索引的话你就首先需要把 HTML 文档和 PDF 文档转化成文本格式的，然后将转化后的内容交给 Lucene 进行索引，然后把创建好的索引文件保存到磁盘或者内存中，最后根据用户输入的查询条件在索引文件上进行查询。不指定要索引的文档的格式也使 Lucene 能够几乎适用于所有的搜索应用程序。</p>
		<p>图 1 表示了搜索应用程序和 Lucene 之间的关系，也反映了利用 Lucene 构建搜索应用程序的流程：</p>
		<br />
		<a name="N10054">
				<b>图1. 搜索应用程序和 Lucene 之间的关系</b>
		</a>
		<br />
		<img alt="图1. 搜索应用程序和 Lucene 之间的关系" src="http://www.ibm.com/developerworks/cn/java/j-lo-lucene1/fig001.jpg" /> <br /><br /><br /><br /><p><a name="N1005E"><span class="atitle">索引和搜索</span></a></p><p>索引是现代搜索引擎的核心，建立索引的过程就是把源数据处理成非常方便查询的索引文件的过程。为什么索引这么重要呢，试想你现在要在大量的文档中搜索含有某个关键词的文档，那么如果不建立索引的话你就需要把这些文档顺序的读入内存，然后检查这个文章中是不是含有要查找的关键词，这样的话就会耗费非常多的时间，想想搜索引擎可是在毫秒级的时间内查找出要搜索的结果的。这就是由于建立了索引的原因，你可以把索引想象成这样一种数据结构，他能够使你快速的随机访问存储在索引中的关键词，进而找到该关键词所关联的文档。Lucene 采用的是一种称为反向索引（inverted index）的机制。反向索引就是说我们维护了一个词/短语表，对于这个表中的每个词/短语，都有一个链表描述了有哪些文档包含了这个词/短语。这样在用户输入查询条件的时候，就能非常快的得到搜索结果。我们将在本系列文章的第二部分详细介绍 Lucene 的索引机制，由于 Lucene 提供了简单易用的 API，所以即使读者刚开始对全文本进行索引的机制并不太了解，也可以非常容易的使用 Lucene 对你的文档实现索引。</p><p>对文档建立好索引后，就可以在这些索引上面进行搜索了。搜索引擎首先会对搜索的关键词进行解析，然后再在建立好的索引上面进行查找，最终返回和用户输入的关键词相关联的文档。</p><br /><br /><p><a name="N1006A"><span class="atitle">Lucene 软件包分析</span></a></p><p>Lucene 软件包的发布形式是一个 JAR 文件，下面我们分析一下这个 JAR 文件里面的主要的 JAVA 包，使读者对之有个初步的了解。</p><p>Package: org.apache.lucene.document</p><p>这个包提供了一些为封装要索引的文档所需要的类，比如 Document, Field。这样，每一个文档最终被封装成了一个 Document 对象。</p><p>Package: org.apache.lucene.analysis</p><p>这个包主要功能是对文档进行分词，因为文档在建立索引之前必须要进行分词，所以这个包的作用可以看成是为建立索引做准备工作。</p><p>Package: org.apache.lucene.index</p><p>这个包提供了一些类来协助创建索引以及对创建好的索引进行更新。这里面有两个基础的类：IndexWriter 和 IndexReader，其中 IndexWriter 是用来创建索引并添加文档到索引中的，IndexReader 是用来删除索引中的文档的。</p><p>Package: org.apache.lucene.search</p><p>这个包提供了对在建立好的索引上进行搜索所需要的类。比如 IndexSearcher 和 Hits, IndexSearcher 定义了在指定的索引上进行搜索的方法，Hits 用来保存搜索得到的结果。</p><br /><br /><p><a name="N1008B"><span class="atitle">一个简单的搜索应用程序</span></a></p><p>假设我们的电脑的目录中含有很多文本文档，我们需要查找哪些文档含有某个关键词。为了实现这种功能，我们首先利用 Lucene 对这个目录中的文档建立索引，然后在建立好的索引中搜索我们所要查找的文档。通过这个例子读者会对如何利用 Lucene 构建自己的搜索应用程序有个比较清楚的认识。</p><br /><br /><p><a name="N10094"><span class="atitle">建立索引</span></a></p><p>为了对文档进行索引，Lucene 提供了五个基础的类，他们分别是 Document, Field, IndexWriter, Analyzer, Directory。下面我们分别介绍一下这五个类的用途：</p><p><b>Document</b></p><p>Document 是用来描述文档的，这里的文档可以指一个 HTML 页面，一封电子邮件，或者是一个文本文件。一个 Document 对象由多个 Field 对象组成的。可以把一个 Document 对象想象成数据库中的一个记录，而每个 Field 对象就是记录的一个字段。</p><p><b>Field</b></p><p>Field 对象是用来描述一个文档的某个属性的，比如一封电子邮件的标题和内容可以用两个 Field 对象分别描述。</p><p><b>Analyzer</b></p><p>在一个文档被索引之前，首先需要对文档内容进行分词处理，这部分工作就是由 Analyzer 来做的。Analyzer 类是一个抽象类，它有多个实现。针对不同的语言和应用需要选择适合的 Analyzer。Analyzer 把分词后的内容交给 IndexWriter 来建立索引。</p><p><b>IndexWriter</b></p><p>IndexWriter 是 Lucene 用来创建索引的一个核心的类，他的作用是把一个个的 Document 对象加到索引中来。</p><p><b>Directory</b></p><p>这个类代表了 Lucene 的索引的存储的位置，这是一个抽象类，它目前有两个实现，第一个是 FSDirectory，它表示一个存储在文件系统中的索引的位置。第二个是 RAMDirectory，它表示一个存储在内存当中的索引的位置。</p><p>熟悉了建立索引所需要的这些类后，我们就开始对某个目录下面的文本文件建立索引了，清单1给出了对某个目录下的文本文件建立索引的源代码。</p><br /><a name="N100C3"><b>清单 1. 对文本文件建立索引</b></a><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="code-outline"><pre class="displaycode">package TestLucene;
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 demonstrate the process of creating index with Lucene 
 * for text files
 */
public class TxtFileIndexer {
	public static void main(String[] args) throws Exception{
		//indexDir is the directory that hosts Lucene's index files
        File   indexDir = new File("D:\\luceneIndex");
        //dataDir is the directory that hosts the text files that to be indexed
        File   dataDir  = new File("D:\\luceneData");
        Analyzer luceneAnalyzer = new StandardAnalyzer();
        File[] dataFiles  = dataDir.listFiles();
        IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
        long startTime = new Date().getTime();
        for(int i = 0; i &lt; dataFiles.length; i++){
        	if(dataFiles[i].isFile() &amp;&amp; dataFiles[i].getName().endsWith(".txt")){
        		System.out.println("Indexing file " + dataFiles[i].getCanonicalPath());
<!-- code sample is too wide -->        		Document document = new Document();
        		Reader txtReader = new FileReader(dataFiles[i]);
        		document.add(Field.Text("path",dataFiles[i].getCanonicalPath()));
        		document.add(Field.Text("contents",txtReader));
        		indexWriter.addDocument(document);
        	}
        }
        indexWriter.optimize();
        indexWriter.close();
        long endTime = new Date().getTime();
        
        System.out.println("It takes " + (endTime - startTime) 
                           + " milliseconds to create index for the files in directory "
        		           + dataDir.getPath());        
	}
}
</pre></td></tr></tbody></table><br /><p>在清单1中，我们注意到类 IndexWriter 的构造函数需要三个参数，第一个参数指定了所创建的索引要存放的位置，他可以是一个 File 对象，也可以是一个 FSDirectory 对象或者 RAMDirectory 对象。第二个参数指定了 Analyzer 类的一个实现，也就是指定这个索引是用哪个分词器对文挡内容进行分词。第三个参数是一个布尔型的变量，如果为 true 的话就代表创建一个新的索引，为 false 的话就代表在原来索引的基础上进行操作。接着程序遍历了目录下面的所有文本文档，并为每一个文本文档创建了一个 Document 对象。然后把文本文档的两个属性：路径和内容加入到了两个 Field 对象中，接着在把这两个 Field 对象加入到 Document 对象中，最后把这个文档用 IndexWriter 类的 add 方法加入到索引中去。这样我们便完成了索引的创建。接下来我们进入在建立好的索引上进行搜索的部分。</p><br /><br /><br /><p><a name="N100CF"><span class="atitle">搜索文档</span></a></p><p>利用Lucene进行搜索就像建立索引一样也是非常方便的。在上面一部分中，我们已经为一个目录下的文本文档建立好了索引，现在我们就要在这个索引上进行搜索以找到包含某个关键词或短语的文档。Lucene提供了几个基础的类来完成这个过程，它们分别是呢IndexSearcher, Term, Query, TermQuery, Hits. 下面我们分别介绍这几个类的功能。</p><p><b>Query</b></p><p>这是一个抽象类，他有多个实现，比如TermQuery, BooleanQuery, PrefixQuery. 这个类的目的是把用户输入的查询字符串封装成Lucene能够识别的Query。</p><p><b>Term</b></p><p>Term是搜索的基本单位，一个Term对象有两个String类型的域组成。生成一个Term对象可以有如下一条语句来完成：Term term = new Term(“fieldName”,”queryWord”); 其中第一个参数代表了要在文档的哪一个Field上进行查找，第二个参数代表了要查询的关键词。</p><p><b>TermQuery</b></p><p>TermQuery是抽象类Query的一个子类，它同时也是Lucene支持的最为基本的一个查询类。生成一个TermQuery对象由如下语句完成： TermQuery termQuery = new TermQuery(new Term(“fieldName”,”queryWord”)); 它的构造函数只接受一个参数，那就是一个Term对象。</p><p><b>IndexSearcher</b></p><p>IndexSearcher是用来在建立好的索引上进行搜索的。它只能以只读的方式打开一个索引，所以可以有多个IndexSearcher的实例在一个索引上进行操作。</p><p><b>Hits</b></p><p>Hits是用来保存搜索的结果的。</p><p>介绍完这些搜索所必须的类之后，我们就开始在之前所建立的索引上进行搜索了，清单2给出了完成搜索功能所需要的代码。</p><br /><a name="N100FE"><b>清单2 ：在建立好的索引上进行搜索</b></a><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td class="code-outline"><pre class="displaycode">package TestLucene;
import java.io.File;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.store.FSDirectory;
/**
 * This class is used to demonstrate the 
 * process of searching on an existing 
 * Lucene index
 *
 */
public class TxtFileSearcher {
	public static void main(String[] args) throws Exception{
	    String queryStr = "lucene";
	    //This is the directory that hosts the Lucene index
        File indexDir = new File("D:\\luceneIndex");
        FSDirectory directory = FSDirectory.getDirectory(indexDir,false);
        IndexSearcher searcher = new IndexSearcher(directory);
        if(!indexDir.exists()){
        	System.out.println("The Lucene index is not exist");
        	return;
        }
        Term term = new Term("contents",queryStr.toLowerCase());
        TermQuery luceneQuery = new TermQuery(term);
        Hits hits = searcher.search(luceneQuery);
        for(int i = 0; i &lt; hits.length(); i++){
        	Document document = hits.doc(i);
        	System.out.println("File: " + document.get("path"));
        }
	}
}
</pre></td></tr></tbody></table><br /><p>在清单2中，类IndexSearcher的构造函数接受一个类型为Directory的对象，Directory是一个抽象类，它目前有两个子类：FSDirctory和RAMDirectory. 我们的程序中传入了一个FSDirctory对象作为其参数，代表了一个存储在磁盘上的索引的位置。构造函数执行完成后，代表了这个IndexSearcher以只读的方式打开了一个索引。然后我们程序构造了一个Term对象，通过这个Term对象，我们指定了要在文档的内容中搜索包含关键词”lucene”的文档。接着利用这个Term对象构造出TermQuery对象并把这个TermQuery对象传入到IndexSearcher的search方法中进行查询，返回的结果保存在Hits对象中。最后我们用了一个循环语句把搜索到的文档的路径都打印了出来。好了，我们的搜索应用程序已经开发完毕，怎么样，利用Lucene开发搜索应用程序是不是很简单。<br /><br /></p><p><a name="N1010A"><span class="atitle">总结</span></a></p><p>本文首先介绍了 Lucene 的一些基本概念，然后开发了一个应用程序演示了利用 Lucene 建立索引并在该索引上进行搜索的过程。希望本文能够为学习 Lucene 的读者提供帮助。</p><img src ="http://www.blogjava.net/tangzurui/aggbug/229380.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/tangzurui/" target="_blank">梓枫</a> 2008-09-17 12:10 <a href="http://www.blogjava.net/tangzurui/archive/2008/09/17/229380.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>