﻿<?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/super2/category/35589.html</link><description>潇洒的一条犬</description><language>zh-cn</language><lastBuildDate>Thu, 30 Oct 2008 03:48:29 GMT</lastBuildDate><pubDate>Thu, 30 Oct 2008 03:48:29 GMT</pubDate><ttl>60</ttl><item><title>[转]lucene学习笔记十二 -- 结果内容显示的文本数量</title><link>http://www.blogjava.net/super2/archive/2008/10/29/237309.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 02:08:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237309.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237309.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237309.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237309.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237309.html</trackback:ping><description><![CDATA[1, highlighter.setTextFragmenter(new SimpleFragmenter(15))<br />
这个控制显示的结果数量多少.<br />
结果展现: <br />
String result= highlighter.getBestFragment(tokenStream, hits.doc(i).get("key"));
<img src ="http://www.blogjava.net/super2/aggbug/237309.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 10:08 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237309.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]lucene学习笔记十 -- 关于高亮显示和显示部分原始文件的原则</title><link>http://www.blogjava.net/super2/archive/2008/10/29/237306.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 02:06:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237306.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237306.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237306.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237306.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237306.html</trackback:ping><description><![CDATA[高亮显示查询项<br />
<br />
有一个能使搜索引擎变得更友好的办法，那就是向你的用户提供一些搜索命中结果的上下文，而且更为重要的是这样做是非常有用
的。最好的例子就是本系统用户在查找天气Web服务时的搜索结果。如下图1所示，每个命中结果包括了匹配文档的三行左右的内容，并且将查询项高亮显示出
来。通常，我们只需要对搜索项 上下文内容浏览一眼就足以 了解该结果是否值得我们深入地进行研究。<br />
<br />
<br />
<br />
<br />
图4.1 高亮显示查询项<br />
<br />
<br />
Highlighter
最近已经充分升级为一个复杂而灵活的工具。Highlighter包括了三个主要部分：段划分器（Fragmenter）、计分器（Scorer）和格式
化器（Formatter）。这几个部分对应于Java的同名接口，并且每部分都有一个内置的实现以便我们使用。最简单的Highlighter将返回在
匹配项周围的最佳段落，并使用HTML的&lt;B&gt;将这些项标记出来：<br />
<br />
String text = &#8220;The quick brown fox jumps over the lazy dog&#8221;;<br />
TermQuery query = new TermQuery(new Term(&#8220;field&#8221;, &#8220;fox&#8221;));<br />
Scorer scorer = new QueryScorer(query);<br />
Highlighter highlighter = new Highlighter(scorer);<br />
TokenStream tokenStream =<br />
new SimpleAnalyzer().tokenStream(&#8220;field&#8221;,<br />
new StringReader(text));<br />
System.out.println(highlighter.getBestFragment(tokenStream,text));<br />
前述代码将产生如下输出<br />
<br />
The quick brown &lt;B&gt;fox&lt;/B&gt; jumps over the lazy dog<br />
<br />
Highlighter不仅需要你提供记分器和需要高亮显示的文本，还需要一个TokenStream实例。这个TokenStream实例是由分析器生
成的。为了成功地对项进行高亮显示，Query中的这些项需要匹配TokenStream产生的Token实例。我们提供的文本则被用于生成
TokenStream，而这个TokenStream又被用作高亮显示的原始文本。每个由TokenStream生成的Token实例都包含语汇单元的
位置信息，这些信息用来指示原始文本中高亮部分的起始和结束位置。 <br />
<br />
Highlighter利用Fragmenter将原始文本分割成多个片段。内置的SimpleFragmenter将原始文本分割成相同大小的片段，片段默认的大小为100个字符。这个大小是可控制的。<br />
<br />
QueryScorer是内置的计分器。计分器的工作首先是将片段排序。QueryScorer使用的项是从用户输入的查询中得到的；它会从原始输入的单
词、词组和布尔查询中提取项，并且基于相应的加权因子（boost
factor）给它们加权。为了便于QueryScoere使用，还必须对查询的原始形式进行重写。比如，带通配符查询、模糊查询、前缀查询以及范围查询
等，都被重写为BoolenaQuery中所使用的项。在将Query实例传递到QueryScorer之前，可以调用
Query.rewrite(IndexReader)方法来重写Query对象（否则，你必须确保用户输入的查询文本就是Lucene直接可以处理最基
本的项）。<br />
<br />
最后，格式化器（Formatter）用于装饰项文本。如果不指定其他的格式化器，Lucene会默认使用内置的格式化器
SimpleHTMLFormatter，这个格式化器将会用HTML的黑体开始标签（begin bold tags
&lt;B&gt;）和黑体结束标签（end bold tags
&lt;/B&gt;）来标识出高亮显示的项文本。Highlighter默认地使用SimpleHTMLFormatter和
SimpleFragmenter这两个格式化器。每一个由Formatter高亮显示的项都将会带有一个语汇单元评分。当使用QueryScorer
时，这个评分将作为查询该项的加权因子。这个语汇单元评分能够被用来决定该项的重要性。要利用这个特性就必须实现自定义的格式化器。<br />
<br />
注：我们项目所用到的 Lucene
API是基于最新版Lucene2.1的，如果你用的是以前版本可能这些例子不能很好的运行。不过我觉得看了以上的东西，再结合网上大量的Lucene资
料还有一些例子就能对Lucene有一定的理解了，最起码就可以开始使用Lucene着手项目了。<br />
另外，在文章开始提到了，我们以前一起做项目时没有使用过Lucene，这次是我们团队的赵宁同学开始接触Lucene，然后在我们项目中使用这个工具，
我是在他指导的基础上对Lucene有一点点的理解而已。感兴趣的可以就项目中的更细节问题跟赵宁同学联系：MSN:program-
maker@hotmail.com
<img src ="http://www.blogjava.net/super2/aggbug/237306.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 10:06 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237306.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]lucene学习笔记十一 -- 建索引优化,复杂排序HitCollector,匹配算法</title><link>http://www.blogjava.net/super2/archive/2008/10/29/237307.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 02:06:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237307.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237307.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237307.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237307.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237307.html</trackback:ping><description><![CDATA[1, 提高建索引的速度<br />
<br />
/**<br />
*
在IndexWriter中有一个MERGE_FACTOR参数可以帮助你在构造索引器后根据应用环境的情况充分利用内存减少文件的操作。根据我的使用经
验：缺省Indexer是每20条记录索引后写入一次，每将MERGE_FACTOR增加50倍，索引速度可以提高1倍左右。<br />
*/<br />
indexWriter.setMergeFactor(1000);<br />
<br />
2, 排序<br />
&amp;laquo; 从 汉化 到 国际化 | (回到Blog入口)|(回到首页) | Resin学习笔记 &amp;raquo; <br />
<br />
Lucene：基于Java的全文检索引擎简介<br />
作者：车东 发表于：2002-08-06 18:08 最后更新于：2007-04-12 11:04<br />
版权声明：可以任意转载，转载时请务必以超链接形式标明文章原始出处和作者信息及本声明。<br />
http://www.chedong.com/tech/lucene.html <br />
--------------------------------------------------------------------------------<br />
Lucene是一个基于Java的全文索引工具包。<br />
<br />
基于Java的全文索引引擎Lucene简介：关于作者和Lucene的历史 <br />
全文检索的实现：Luene全文索引和数据库索引的比较 <br />
中文切分词机制简介：基于词库和自动切分词算法的比较 <br />
具体的安装和使用简介：系统结构介绍和演示 <br />
Hacking Lucene：简化的查询分析器，删除的实现，定制的排序，应用接口的扩展 <br />
从Lucene我们还可以学到什么 <br />
基于Java的全文索引/检索引擎——Lucene<br />
<br />
Lucene不是一个完整的全文索引应用，而是是一个用Java写的全文索引引擎工具包，它可以方便的嵌入到各种应用中实现针对应用的全文索引/检索功能。<br />
<br />
Lucene的作者：Lucene的贡献者Doug
Cutting是一位资深全文索引/检索专家，曾经是V-Twin搜索引擎(Apple的Copland操作系统的成就之一)的主要开发者，后在
Excite担任高级系统架构设计师，目前从事于一些INTERNET底层架构的研究。他贡献出的Lucene的目标是为各种中小型应用程序加入全文检索
功能。<br />
<br />
Lucene的发展历程：早先发布在作者自己的www.lucene.com，后来发布在SourceForge，2001年年底成为APACHE基金会
jakarta的一个子项目：http://jakarta.apache.org/lucene/<br />
<br />
已经有很多Java项目都使用了Lucene作为其后台的全文索引引擎，比较著名的有：<br />
<br />
Jive：WEB论坛系统； <br />
Eyebrows：邮件列表HTML归档/浏览/查询系统，本文的主要参考文档&#8220;TheLucene search engine:
Powerful, flexible, and
free&#8221;作者就是EyeBrows系统的主要开发者之一，而EyeBrows已经成为目前APACHE项目的主要邮件列表归档系统。 <br />
Cocoon:基于XML的web发布框架，全文检索部分使用了Lucene <br />
Eclipse:基于Java的开放开发平台，帮助部分的全文索引使用了Lucene<br />
<br />
对于中文用户来说，最关心的问题是其是否支持中文的全文检索。但通过后面对于Lucene的结构的介绍，你会了解到由于Lucene良好架构设计，对中文的支持只需对其语言词法分析接口进行扩展就能实现对中文检索的支持。<br />
<br />
全文检索的实现机制<br />
<br />
Lucene的API接口设计的比较通用，输入输出结构都很像数据库的表==&gt;记录==&gt;字段，所以很多传统的应用的文件、数据库等都可以比
较方便的映射到Lucene的存储结构/接口中。总体上看：可以先把Lucene当成一个支持全文索引的数据库系统。<br />
<br />
比较一下Lucene和数据库：<br />
<br />
Lucene 数据库 <br />
索引数据源：doc(field1,field2...) doc(field1,field2...) \ indexer /
_____________ | Lucene Index| -------------- / searcher \
结果输出：Hits(doc(field1,field2) doc(field1...))
索引数据源：record(field1,field2...) record(field1..) \ SQL: insert/
_____________ | DB Index | ------------- / SQL: select
\结果输出：results(record(field1,field2..) record(field1...)) <br />
Document：一个需要进行索引的&#8220;单元&#8221;<br />
一个Document由多个字段组成 Record：记录，包含多个字段 <br />
Field：字段 Field：字段 <br />
Hits：查询结果集，由匹配的Document组成 RecordSet：查询结果集，由多个Record组成 <br />
<br />
全文检索 &#8800; like "%keyword%"<br />
<br />
通常比较厚的书籍后面常常附关键词索引表（比如：北京：12,
34页，上海：3,77页&#8230;&#8230;），它能够帮助读者比较快地找到相关内容的页码。而数据库索引能够大大提高查询的速度原理也是一样，想像一下通过书后面的索
引查找的速度要比一页一页地翻内容高多少倍&#8230;&#8230;而索引之所以效率高，另外一个原因是它是排好序的。对于检索系统来说核心是一个排序问题。<br />
<br />
由于数据库索引不是为全文索引设计的，因此，使用like
"%keyword%"时，数据库索引是不起作用的，在使用like查询时，搜索过程又变成类似于一页页翻书的遍历过程了，所以对于含有模糊查询的数据库
服务来说，LIKE对性能的危害是极大的。如果是需要对多个关键词进行模糊匹配：like"%keyword1%" and like
"%keyword2%" ...其效率也就可想而知了。<br />
<br />
所以建立一个高效检索系统的关键是建立一个类似于科技索引一样的反向索引机制，将数据源（比如多篇文章）排序顺序存储的同时，有另外一个排好序的关键词列
表，用于存储关键词==&gt;文章映射关系，利用这样的映射关系索引：[关键词==&gt;出现关键词的文章编号，出现次数（甚至包括位置：起始偏移
量，结束偏移量），出现频率]，检索过程就是把模糊查询变成多个可以利用索引的精确查询的逻辑组合的过程。从而大大提高了多关键词查询的效率，所以，全文
检索问题归结到最后是一个排序问题。<br />
<br />
由此可以看出模糊查询相对数据库的精确查询是一个非常不确定的问题，这也是大部分数据库对全文检索支持有限的原因。Lucene最核心的特征是通过特殊的
索引结构实现了传统数据库不擅长的全文索引机制，并提供了扩展接口，以方便针对不同应用的定制。<br />
<br />
可以通过一下表格对比一下数据库的模糊查询：<br />
<br />
Lucene全文索引引擎 数据库 <br />
索引 将数据源中的数据都通过全文索引一一建立反向索引 对于LIKE查询来说，数据传统的索引是根本用不上的。数据需要逐个便利记录进行GREP式的模糊匹配，比有索引的搜索速度要有多个数量级的下降。 <br />
匹配效果 通过词元(term)进行匹配，通过语言分析接口的实现，可以实现对中文等非英语的支持。 使用：like "%net%" 会把netherlands也匹配出来，<br />
多个关键词的模糊匹配：使用like "%com%net%"：就不能匹配词序颠倒的xxx.net..xxx.com <br />
匹配度 有匹配度算法，将匹配程度（相似度）比较高的结果排在前面。 没有匹配程度的控制：比如有记录中net出现5词和出现1次的，结果是一样的。 <br />
结果输出 通过特别的算法，将最匹配度最高的头100条结果输出，结果集是缓冲式的小批量读取的。 返回所有的结果集，在匹配条目非常多的时候（比如上万条）需要大量的内存存放这些临时结果集。 <br />
可定制性 通过不同的语言分析接口实现，可以方便的定制出符合应用需要的索引规则（包括对中文的支持） 没有接口或接口复杂，无法定制 <br />
结论 高负载的模糊查询应用，需要负责的模糊查询的规则，索引的资料量比较大 使用率低，模糊匹配规则简单或者需要模糊查询的资料量少 <br />
<br />
全文检索和数据库应用最大的不同在于：让最相关的头100条结果满足98%以上用户的需求<br />
<br />
Lucene的创新之处：<br />
<br />
大部分的搜索（数据库）引擎都是用B树结构来维护索引，索引的更新会导致大量的IO操作，Lucene在实现中，对此稍微有所改进：不是维护一个索引文
件，而是在扩展索引的时候不断创建新的索引文件，然后定期的把这些新的小索引文件合并到原先的大索引中（针对不同的更新策略，批次的大小可以调整），这样
在不影响检索的效率的前提下，提高了索引的效率。<br />
<br />
Lucene和其他一些全文检索系统/应用的比较：<br />
<br />
Lucene 其他开源全文检索系统 <br />
增量索引和批量索引 可以进行增量的索引(Append)，可以对于大量数据进行批量索引，并且接口设计用于优化批量索引和小批量的增量索引。 很多系统只支持批量的索引，有时数据源有一点增加也需要重建索引。 <br />
数据源 Lucene没有定义具体的数据源，而是一个文档的结构，因此可以非常灵活的适应各种应用（只要前端有合适的转换器把数据源转换成相应结构）， 很多系统只针对网页，缺乏其他格式文档的灵活性。 <br />
索引内容抓取 Lucene的文档是由多个字段组成的，甚至可以控制那些字段需要进行索引，那些字段不需要索引，近一步索引的字段也分为需要分词和不需要分词的类型：<br />
需要进行分词的索引，比如：标题，文章内容字段<br />
不需要进行分词的索引，比如：作者/日期字段 缺乏通用性，往往将文档整个索引了 <br />
语言分析 通过语言分析器的不同扩展实现：<br />
可以过滤掉不需要的词：an the of 等，<br />
西文语法分析：将jumps jumped jumper都归结成jump进行索引/检索<br />
非英文支持：对亚洲语言，阿拉伯语言的索引支持 缺乏通用接口实现 <br />
查询分析 通过查询分析接口的实现，可以定制自己的查询语法规则：<br />
比如： 多个关键词之间的 + - and or关系等 　 <br />
并发访问 能够支持多用户的使用 　 <br />
<br />
<br />
<br />
关于亚洲语言的的切分词问题(Word Segment)<br />
<br />
对于中文来说，全文索引首先还要解决一个语言分析的问题，对于英文来说，语句中单词之间是天然通过空格分开的，但亚洲语言的中日韩文语句中的字是一个字挨一个，所有，首先要把语句中按&#8220;词&#8221;进行索引的话，这个词如何切分出来就是一个很大的问题。<br />
<br />
首先，肯定不能用单个字符作(si-gram)为索引单元，否则查&#8220;上海&#8221;时，不能让含有&#8220;海上&#8221;也匹配。<br />
<br />
但一句话：&#8220;北京天安门&#8221;，计算机如何按照中文的语言习惯进行切分呢？<br />
&#8220;北京 天安门&#8221; 还是&#8220;北 京 天安门&#8221;？让计算机能够按照语言习惯进行切分，往往需要机器有一个比较丰富的词库才能够比较准确的识别出语句中的单词。<br />
<br />
另外一个解决的办法是采用自动切分算法：将单词按照2元语法(bigram)方式切分出来，比如：<br />
"北京天安门" ==&gt; "北京 京天 天安 安门"。<br />
<br />
这样，在查询的时候，无论是查询"北京"
还是查询"天安门"，将查询词组按同样的规则进行切分："北京"，"天安安门"，多个关键词之间按与"and"的关系组合，同样能够正确地映射到相应的索
引中。这种方式对于其他亚洲语言：韩文，日文都是通用的。<br />
<br />
基于自动切分的最大优点是没有词表维护成本，实现简单，缺点是索引效率低，但对于中小型应用来说，基于2元语法的切分还是够用的。基于2元切分后的索引一般大小和源文件差不多，而对于英文，索引文件一般只有原文件的30%-40%不同，<br />
<br />
<br />
自动切分 词表切分 <br />
实现 实现非常简单 实现复杂 <br />
查询 增加了查询分析的复杂程度， 适于实现比较复杂的查询语法规则 <br />
存储效率 索引冗余大，索引几乎和原文一样大 索引效率高，为原文大小的30％左右 <br />
维护成本 无词表维护成本 词表维护成本非常高：中日韩等语言需要分别维护。<br />
还需要包括词频统计等内容 <br />
适用领域 嵌入式系统：运行环境资源有限<br />
分布式系统：无词表同步问题<br />
多语言环境：无词表维护成本 对查询和存储效率要求高的专业搜索引擎<br />
<br />
<br />
目前比较大的搜索引擎的语言分析算法一般是基于以上2个机制的结合。关于中文的语言分析算法，大家可以在Google查关键词"wordsegment search"能找到更多相关的资料。<br />
<br />
安装和使用<br />
<br />
下载：http://jakarta.apache.org/lucene/<br />
<br />
注意：Lucene中的一些比较复杂的词法分析是用JavaCC生成的（JavaCC：JavaCompilerCompiler，纯Java的词法分析
生成器），所以如果从源代码编译或需要修改其中的QueryParser、定制自己的词法分析器，还需要从
https://javacc.dev.java.net/下载javacc。<br />
<br />
lucene的组成结构：对于外部应用来说索引模块(index)和检索模块(search)是主要的外部应用入口<br />
<br />
org.apache.Lucene.search/ 搜索入口 <br />
org.apache.Lucene.index/ 索引入口 <br />
org.apache.Lucene.analysis/ 语言分析器 <br />
org.apache.Lucene.queryParser/ 查询分析器 <br />
org.apache.Lucene.document/ 存储结构 <br />
org.apache.Lucene.store/ 底层IO/存储结构 <br />
org.apache.Lucene.util/ 一些公用的数据结构 <br />
<br />
简单的例子演示一下Lucene的使用方法：<br />
<br />
索引过程：从命令行读取文件名（多个），将文件分路径(path字段)和内容(body字段)2个字段进行存储，并对内容进行全文索引：索引的单位是
Document对象，每个Document对象包含多个字段Field对象，针对不同的字段属性和数据输出的需求，对字段还可以选择不同的索引/存储字
段规则，列表如下： 方法 切词 索引 存储 用途 <br />
Field.Text(String name, String value) Yes Yes Yes 切分词索引并存储，比如：标题，内容字段 <br />
Field.Text(String name, Reader value) Yes Yes No 切分词索引不存储，比如：META信息，<br />
不用于返回显示，但需要进行检索内容 <br />
Field.Keyword(String name, String value) No Yes Yes 不切分索引并存储，比如：日期字段 <br />
Field.UnIndexed(String name, String value) No No Yes 不索引，只存储，比如：文件路径 <br />
Field.UnStored(String name, String value) Yes Yes No 只全文索引，不存储 <br />
<br />
public class IndexFiles { //使用方法：: IndexFiles [索引输出目录] [索引的文件列表] ...
public static void main(String[] args) throws Exception { String
indexPath = args[0]; IndexWriter writer;
//用指定的语言分析器构造一个新的写索引器（第3个参数表示是否为追加索引） writer = new
IndexWriter(indexPath, new SimpleAnalyzer(), false); for (int i=1;
i&lt;args.length; i++) { System.out.println("Indexing file " + args<em>); InputStream is = new FileInputStream(args<em>);
//构造包含2个字段Field的Document对象 //一个是路径path字段，不索引，只存储
//一个是内容body字段，进行全文索引，并存储 Document doc = new Document();
doc.add(Field.UnIndexed("path", args<em>)); doc.add(Field.Text("body",
(Reader) new InputStreamReader(is))); //将文档写入索引
writer.addDocument(doc); is.close(); }; //关闭写索引器 writer.close();
}}　索引过程中可以看到：<br />
<br />
语言分析器提供了抽象的接口，因此语言分析(Analyser)是可以定制的，虽然lucene缺省提供了2个比较通用的分析器
SimpleAnalyser和StandardAnalyser，这2个分析器缺省都不支持中文，所以要加入对中文语言的切分规则，需要修改这2个分析
器。 <br />
Lucene并没有规定数据源的格式，而只提供了一个通用的结构（Document对象）来接受索引的输入，因此输入的数据源可以是：数据库，WORD文
档，PDF文档，HTML文档&#8230;&#8230;只要能够设计相应的解析转换器将数据源构造成成Docuement对象即可进行索引。 <br />
对于大批量的数据索引，还可以通过调整IndexerWrite的文件合并频率属性（mergeFactor）来提高批量索引的效率。 <br />
检索过程和结果显示：<br />
<br />
搜索结果返回的是Hits对象，可以通过它再访问Document==&gt;Field中的内容。<br />
<br />
假设根据body字段进行全文检索，可以将查询结果的path字段和相应查询的匹配度(score)打印出来，<br />
<br />
public class Search { public static void main(String[] args) throws
Exception { String indexPath = args[0], queryString = args[1];
//指向索引目录的搜索器 Searcher searcher = new IndexSearcher(indexPath);
//查询解析器：使用和索引同样的语言分析器 Query query = QueryParser.parse(queryString,
"body", new SimpleAnalyzer()); //搜索结果使用Hits存储 Hits hits =
searcher.search(query); //通过hits可以访问到相应字段的数据和查询的匹配度 for (int i=0;
i&lt;hits.length(); i++) { System.out.println(hits.doc(i).get("path") +
"; Score: " + hits.score(i)); };
}}在整个检索过程中，语言分析器，查询分析器，甚至搜索器（Searcher）都是提供了抽象的接口，可以根据需要进行定制。 <br />
Hacking Lucene<br />
<br />
简化的查询分析器<br />
<br />
个人感觉lucene成为JAKARTA项目后，画在了太多的时间用于调试日趋复杂QueryParser，而其中大部分是大多数用户并不很熟悉的，目前LUCENE支持的语法：<br />
<br />
Query ::= ( Clause )*<br />
Clause ::= ["+", "-"] [&lt;TERM&gt; ":"] ( &lt;TERM&gt; | "(" Query ")")<br />
<br />
中间的逻辑包括：and or + -
&amp;&amp;||等符号，而且还有"短语查询"和针对西文的前缀/模糊查询等，个人感觉对于一般应用来说，这些功能有一些华而不实，其实能够实现
目前类似于Google的查询语句分析功能其实对于大多数用户来说已经够了。所以，Lucene早期版本的QueryParser仍是比较好的选择。<br />
<br />
添加修改删除指定记录（Document）<br />
<br />
Lucene提供了索引的扩展机制，因此索引的动态扩展应该是没有问题的，而指定记录的修改也似乎只能通过记录的删除，然后重新加入实现。如何删除指定的
记录呢？删除的方法也很简单，只是需要在索引时根据数据源中的记录ID专门另建索引，然后利用IndexReader.delete(Termterm)
方法通过这个记录ID删除相应的Document。<br />
<br />
根据某个字段值的排序功能<br />
<br />
lucene缺省是按照自己的相关度算法（score）进行结果排序的，但能够根据其他字段进行结果排序是一个在LUCENE的开发邮件列表中经常提到的
问题，很多原先基于数据库应用都需要除了基于匹配度（score）以外的排序功能。而从全文检索的原理我们可以了解到，任何不基于索引的搜索过程效率都会
导致效率非常的低，如果基于其他字段的排序需要在搜索过程中访问存储字段，速度回大大降低，因此非常是不可取的。<br />
<br />
但这里也有一个折中的解决方法：在搜索过程中能够影响排序结果的只有索引中已经存储的docID和score这2个参数，所以，基于score以外的排
序，其实可以通过将数据源预先排好序，然后根据docID进行排序来实现。这样就避免了在LUCENE搜索结果外对结果再次进行排序和在搜索过程中访问不
在索引中的某个字段值。<br />
<br />
这里需要修改的是IndexSearcher中的HitCollector过程：<br />
<br />
...　scorer.score(new HitCollector() { private float minScore = 0.0f;
public final void collect(int doc, float score) { if (score &gt; 0.0f
&amp;&amp; // ignore zeroed buckets (bits==null || bits.get(doc))) { //
skip docs not in bits totalHits[0]++; if (score &gt;= minScore) { /*
原先：Lucene将docID和相应的匹配度score例入结果命中列表中： * hq.put(new ScoreDoc(doc,
score)); // update hit queue * 如果用doc 或 1/doc 代替 score，就实现了根据docID顺排或逆排
* 假设数据源索引时已经按照某个字段排好了序，而结果根据docID排序也就实现了 *
针对某个字段的排序，甚至可以实现更复杂的score和docID的拟合。 */ hq.put(new ScoreDoc(doc, (float)
1/doc )); if (hq.size() &gt; nDocs) { // if hit queue overfull
hq.pop(); // remove lowest in hit queue minScore =
((ScoreDoc)hq.top()).score; // reset minScore } } } } },
reader.maxDoc());<br />
<br />
3, 计算匹配得分. 小于1.0的我们认为是相关的记录了.下面的代码在输出结果循环中. 如果要获取完全匹配的记录,<br />
<br />
//计算匹配得分<br />
Explanation explanation = searcher.explain(query, hits.id(i)) ;<br />
System.out.println("匹配得分:"+explanation.getValue());<br />
System.out.println("=========");<br />
<br />
<br />
4, 关于短语匹配的用法<br />
<br />
通过短语搜索：PhraseQuery<br />
索引中包含了各个项的位置信息。PhraseQuery利用这些信息去搜索文档，在这些文档集中，我们所查找的各个项之间可能都相隔着一定的距离。例如，
假设某个域中包含了&#8220;the quick brown fox jumped over the lazy
dog&#8221;这个短语，即使我们不知道这个短语的确切完整写法，也一样可以通过查找域中quick和fox距离相近的文档来找出我们需要的文档。当然，一个简
单的TermQuery也能够通过对这两个项的单独查询成功地找到同样文档；但是在以上所讨论的情况中，我们仅仅希望查到域中quick的位置紧挨着
fox或者隔一个不相关的单词的文档（如quick [不相关的词] fox）。<br />
<br />
在匹配的情况下，两个项的位置之间允许的最大间隔距离称为slop。距离是指项要按顺序组成给定的短语，所需要移动位置的次数。我们用刚刚提到的那个短
语，看看slop因子是怎么样工作的。首先，我们需要构建一个小的基本测试构架，程序里用一个setUp()方法来索引一个文档，并通过
matched(String[], int)方法构造、执行并断言一个短语查询与我们的测试文档相匹配：<br />
<br />
<br />
<br />
// 建立样本文档<br />
<br />
<br />
<br />
<br />
<br />
由于只想示范一下几个短语查询的例子，因此在以上程序中我们简化了matched方法的代码。这个程序按照一定的顺序添加各个项来进行短语查询。默认情况
下，PhraseQuery的slop因子设置为0，即要求查询的结果必须和我们输入的字符串组完全精确一致地匹配。通过setUp()和
matched()方法，测试用例对PhraseQuery的工作方式做出了简洁的示范。程序以查询失败或超出slop因子作为其边界：<br />
<br />
<br />
<br />
<br />
<br />
图3.2 解释短语查询slop因子：短语&#8220;quick fox&#8221;需要slop值为1的移动才能和原文档匹配，而&#8220;fox quick&#8221;需要slop值为3的移动才能匹配<br />
<br />
在短语查询中，虽然项出现的先后顺序会对slop因子的选取有一定影响，但是我们不一定需要按照这些项在文档中出现的先后顺序来将它们添加至
PhraseQuery中。例如，如果把上述String数组中的两个项颠倒（先是项&#8220;fox&#8221;，然后是&#8220;quick&#8221;），要和文档匹配就需要移动三个位
置，而不是原先的一个了。为了表达得更形象一些，可以思考一下单词&#8220;fox&#8221;需要移动多少个位置才能位于单词&#8220;quick&#8221;的两个位置之后。你会发现
fox移动一次到达quick的位置，然后再移动两次才能使之变成&#8220;quick X fox&#8221;，从而和&#8220;quick brown fox&#8221;充分地匹配。<br />
<br />
图3.2展示了slop位置因子在这两个短语查询场景的应用是如何工作的，下面的测试用例示范了程序如何通过slop因子的设置实现对String[] {"fox", "quick"}的匹配：<br />
<br />
<br />
<br />
现在我们开始深入学习如何对多个项进行复合查询的问题。<br />
<br />
复合项短语<br />
PhraseQuery支持复合项短语（multiple-term phrases）。不管短语中有多少个项，slop因子都规定了项按顺序移动位置的所允许的最大值。下面看看关于复合项短语查询的一个示例：<br />
<br />
<br />
<br />
<br />
<br />
到目前为止，你已经了解了短语查询是如何进行匹配的，下面我们把注意力转向于短语查询对文档评分的影响。<br />
<br />
短语查询评分<br />
短语查询是根据短语匹配所需要的编辑距离来进行评分的。项之间距离越小的匹配具有的权重也就越大。短语查询的评分因子如图3.3所示。评分与距离成反比关系，距离越大的匹配其评分越低。<br />
<br />
<br />
<br />
图3.3 短语查询的评分公式<br />
<br />
注：在QueryParser的分析表达式中双引号里的若干个项被被转换为一个PhraseQuery对象。Slop因子的默认值是0，但是你可以在
QueryParser的查询表达式中加上~n的声明，以此来调整slop因子的值。例如，表达式&#8220;quick
fox&#8221;~3的意义为：为fox和quick项生成一个slop因子为3的PhraseQuery对象。更多关于PhraseQuery和slop因子的
细节请参看3.5.6小节。短语由传给QueryParser的分析器进行分析，在此过程中还会加入另外一个复杂的层，这个内容将会在4.1.2小节中加
以讨论。</em></em></em>
<img src ="http://www.blogjava.net/super2/aggbug/237307.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 10:06 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237307.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]lucene学习笔记九-- 关于结果分页</title><link>http://www.blogjava.net/super2/archive/2008/10/29/237305.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 02:04:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237305.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237305.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237305.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237305.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237305.html</trackback:ping><description><![CDATA[<p>一 ,Hits对象是搜索结果的集合 主要有下面几个方法 [list=1]</p>
<table class="blog-content">
    <tbody>
        <tr>
            <td>
            <li>length() ,这个方法记录有多少条结果返回(lazy loading)</li>
            <li>doc(n) 返回第n个记录</li>
            <li>id(in) 返回第n个记录的Document ID</li>
            <li>score(n) 第n个记录的相关度(积分)
            由于搜索的结果一般比较大，从性能上考虑，Hits对象并不会真正把所有的结果全部取回，默认情况下是保留前100个记录(对于一般的搜索引擎,100个记录足够了).<br />
            <font size="3"><strong>分页的处理</strong></font><br />
            100条记录还是太多，我们多半会每页显示20条记录，然后分为若干页显示，对于分页，一般有两个办法 <br />
            [list=1]</li>
            <li>在session中保留indexreader对象和hit对象，翻页的时候提取内容</li>
            <li>不使用session，每次都简单处理为重新查询
            lucene推荐先使用第二个办法，即每次都重新查询，这样做的好处是简单方便，不需要考虑session的问题，lucene的查询效率也能保证每次查询时间不长，除非真正有了性能问题，否则不用考虑第一个办法。<br />
            <br />
            <br />
            Lucene面向全文检索的优化在于首次索引检索后，并不把所有的记录（Document）具体内容读取出来，而起只将所有结果中匹配度最高的头100条
            结果（TopDocs）的ID放到结果集缓存中并返回，这里可以比较一下数据库检索：如果是一个10,000条的数据库检索结果集，数据库是一定要把所有
            记录内容都取得以后再开始返回给应用结果集的。所以即使检索匹配总数很多，Lucene的结果集占用的内存空间也不会很多。对于一般的模糊检索应用是用不
            到这么多的结果的，头100条已经可以满足90%以上的检索需求。<br />
            <br />
            如果首批缓存结果数用完后还要读取更后面的结果时Searcher会再次检索并生成一个上次的搜索缓存数大1倍的缓存，并再重新向后抓取。所以如果构造一
            个Searcher去查1－120条结果，Searcher其实是进行了2次搜索过程：头100条取完后，缓存结果用完，Searcher重新检索再构造
            一个200条的结果缓存，依此类推，400条缓存，800条缓存。由于每次Searcher对象消失后，这些缓存也访问那不到了，你有可能想将结果记录缓
            存下来，缓存数尽量保证在100以下以充分利用首次的结果缓存，不让Lucene浪费多次检索，而且可以分级进行结果缓存。<br />
            <br />
            Lucene的另外一个特点是在收集结果的过程中将匹配度低的结果自动过滤掉了。这也是和数据库应用需要将搜索的结果全部返回不同之处。<br />
            <a href="http://sourceforge.net/projects/weblucene/" target="_blank"><font color="#bc694c">我的一些尝试</font></a>：</li>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/super2/aggbug/237305.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 10:04 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237305.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]lucene学习笔记八 分词</title><link>http://www.blogjava.net/super2/archive/2008/10/29/237303.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 02:03:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237303.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237303.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237303.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237303.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237303.html</trackback:ping><description><![CDATA[1, Lucene的结构框架： <br />
注意：Lucene中的一些比较复杂的词法分析是用JavaCC生成的（JavaCC：JavaCompilerCompiler，纯Java的词法
分析生成器），所以如果从源代码编译或需要修改其中的QueryParser、定制自己的词法分析器，还需要从<a href="https://javacc.dev.java.net/" target="_blank"><font color="#bc694c">https://javacc.dev.java.net/</font></a>下载javacc。 <br />
lucene的组成结构：对于外部应用来说索引模块(index)和检索模块(search)是主要的外部应用入口。 org.apache.Lucene.search/ 搜索入口 <br />
org.apache.Lucene.index/ 索引入口 <br />
org.apache.Lucene.analysis/ 语言分析器 <br />
org.apache.Lucene.queryParser/ 查询分析器 <br />
org.apache.Lucene.document/ 存储结构 <br />
org.apache.Lucene.store/ 底层IO/存储结构 <br />
org.apache.Lucene.util/ 一些公用的数据结构 <br />
<br />
2, 关于计划于词库的分词和一元分词,二元分词的区别. noise.chs 是词库中作为stopword而存在的.请大家注意. <br />
下面做了详细描述: <br />
<br />
2006年01月22日 星期日 于 2:39 am &#183; 发表在: 默认 <br />
<br />
Lucene应用越来越多，在对中文对索引过程中，中文分词问题也就越来越重要。 <br />
<br />
在已有的分词模式中，目前比较常用的也是比较通用的有一元分词、二元分词和基于词库的分词三种。一元分词在Java版本上由yysun实现，并且已经收录
到Apache。其实现方式比较简单，即将每一个汉字作为一个Token，例如：&#8220;这是中文字&#8221;，在经过一元分词模式分词后的结果为五个Token：这、
是、中、文、字。而二元分词，则将两个相连的汉字作为一个Token划分，例如：&#8220;这是中文字&#8221;，运用二元分词模式分词后，得到的结果为：这是、是中、中
文、文字。 <br />
<br />
一元分词和二元分词实现原理比较简单，基本支持所有东方语言。但二者的缺陷也比较明显。一元分词单纯的考虑了中文的文字而没有考虑到中文的词性，例如在上
述的例子中，&#8220;中文&#8221;、&#8220;文字&#8221;这两个十分明显的中文词语就没有被识别出来。相反，二元分词则分出了太多的冗余的中文词，如上所述，&#8220;这是&#8221;、&#8220;是中&#8221;毫
无意义的文字组合竟被划分为一个词语，而同样的缺陷，命中的词语也不十分准确，如上：在&#8220;这是中文字&#8221;中，&#8220;中文字&#8221;这个词语应该优先考虑的。而二元分词
也未能实现。 <br />
<br />
基于词库的分词实现难度比较大，其模式也有多种，如微软在自己的软件中的汉语分词、海量的中文分词研究版，还有目前在.Net下实现的使用率较高的猎兔，
和一些其他人自发实现的分词工具等等。其都有自己的分析体系，虽然分析精度高，但实现难度大，实现周期长，而且，对一般的中小型应用系统来讲，在精度的要
求不是十分苛刻的环境下，这种模式对系统对消耗是一种奢侈行为。 <br />
<br />
在综合考虑一元分词、二元分词及基于词库的分词模式后，我大胆提出一种基于StopWord分割的分词模式。这种分词模式的设计思想是，针对要分割的段
落，先由标点分割成标准的短句。然后根据设定的StopWord，将短句由StopWord最大化分割，分割为一个个词语。如：输入短句为&#8220;这是中文字
&#8221;，设定的StopWord列表为：&#8220;这&#8221;、&#8220;是&#8221;，则最终的结果为：&#8220;中文字&#8221;。 <br />
<br />
这个例子相对比较简单，举个稍微长一点的例子：输入短句&#8220;中文软件需要具有对中文文本的输入、显示、编辑、输出等基本功能&#8221;，设定的StopWord列表为：&#8220;这&#8221;、&#8220;是&#8221;、&#8220;的&#8221;、&#8220;对&#8221;、&#8220;等&#8221;、&#8220;需要&#8221;、&#8220;具有&#8221;，则分割出对结果列表为： <br />
<br />
==================== <br />
中文软件 <br />
中文文本 <br />
输入 <br />
显示 <br />
编辑 <br />
输出 <br />
基本功能 <br />
==================== <br />
<br />
基本实现了想要的结果，但其中也不乏不足之处，如上述的结果中&#8220;中文软件&#8221;与&#8220;中文文本&#8221;应该分割为三个独立词&#8220;中文&#8221;、&#8220;软件&#8221;和&#8220;文本&#8221;，而不是上述的结果。 <br />
<br />
并且，对StopWord列表对设置，也是相对比较复杂的环节，没有一个确定的约束来设定StopWord。我的想法是，可以将一些无意义的主语，如&#8220;我
&#8221;、&#8220;你&#8221;、&#8220;他&#8221;、&#8220;我们&#8221;、&#8220;他们&#8221;等，动词&#8220;是&#8221;、&#8220;对&#8221;、&#8220;有&#8221;等等其他各种词性诸如&#8220;的&#8221;、&#8220;啊&#8221;、&#8220;一&#8221;、&#8220;不&#8221;、&#8220;在&#8221;、&#8220;人&#8221;等等
（System32目录下noise.chs文件里的内容可以作为参考）作为StopWord。 <br />
<br />
noise.chs 是词库中作为stopword而存在的.请大家注意. <br />
<br />
3, 关于分词的.还可以关注这个帖子: <br />
<br />
<a href="http://lucene-group.group.javaeye.com/group/blog/58701" target="_blank"><font color="#bc694c">http://lucene-group.group.javaeye.com/group/blog/58701</font></a> <br />
<br />
自己写的一个基于词库的lucene分词程序--ThesaurusAnalyzer <br />
<br />
我已经测试过.还可以.18万分词. <br />
<br />
<br />
4, lucene的自带分词的测试如下:\ <br />
<br />
Lucene本身提供了几个分词接口,我后来有给写了一个分词接口. <br />
<br />
功能递增如下: <br />
<br />
WhitespaceAnalyzer:仅仅是去除空格，对字符没有lowcase化,不支持中文 <br />
<br />
SimpleAnalyzer:功能强于WhitespaceAnalyzer,将除去letter之外的符号全部过滤掉,并且将所有的字符lowcase化,不支持中文 <br />
<br />
StopAnalyzer:StopAnalyzer的功能超越了SimpleAnalyzer，在SimpleAnalyzer的基础上 <br />
增加了去除StopWords的功能,不支持中文 <br />
<br />
StandardAnalyzer:英文的处理能力同于StopAnalyzer.支持中文采用的方法为单字切分. <br />
<br />
ChineseAnalyzer:来自于Lucene的sand box.性能类似于StandardAnalyzer,缺点是不支持中英文混和分词. <br />
<br />
CJKAnalyzer:chedong写的CJKAnalyzer的功能在英文处理上的功能和StandardAnalyzer相同 <br />
但是在汉语的分词上，不能过滤掉标点符号，即使用二元切分 <br />
<br />
TjuChineseAnalyzer:我写的,功能最为强大.TjuChineseAnlyzer的功能相当强大,在中文分词方面由于其调用的为
ICTCLAS的java接口.所以其在中文方面性能上同与ICTCLAS.其在英文分词上采用了Lucene的StopAnalyzer,可以去除
stopWords,而且可以不区分大小写,过滤掉各类标点符号. <br />
<br />
程序调试于:JBuilder 2005 <br />
<br />
package org.apache.lucene.analysis; <br />
<br />
//Author:zhangbufeng <br />
//TjuAILab(天津大学人工智能实验室) <br />
//2005.9.22.11:00 <br />
<br />
<br />
import java.io.*; <br />
import junit.framework.*; <br />
<br />
import org.apache.lucene.*; <br />
import org.apache.lucene.analysis.*; <br />
import org.apache.lucene.analysis.StopAnalyzer; <br />
import org.apache.lucene.analysis.standard.*; <br />
import org.apache.lucene.analysis.cn.*; <br />
import org.apache.lucene.analysis.cjk.*; <br />
import org.apache.lucene.analysis.tjucn.*; <br />
import com.xjt.nlp.word.*; <br />
public class TestAnalyzers extends TestCase { <br />
<br />
public TestAnalyzers(String name) { <br />
super(name); <br />
} <br />
<br />
public void assertAnalyzesTo(Analyzer a, <br />
String input, <br />
String[] output) throws Exception { <br />
//前面的"dummy"好像没有用到 <br />
TokenStream ts = a.tokenStream("dummy", new StringReader(input)); <br />
StringReader readerInput=new StringReader(input); <br />
for (int i=0; i Token t = ts.next(); <br />
//System.out.println(t); <br />
assertNotNull(t); <br />
//使用下面这条语句即可以输出Token的每项的text,并且用空格分开 <br />
System.out.print(t.termText); <br />
System.out.print(" "); <br />
assertEquals(t.termText(), output<em>); <br />
} <br />
System.out.println(" "); <br />
assertNull(ts.next()); <br />
ts.close(); <br />
} <br />
public void outputAnalyzer(Analyzer a ,String input) throws Exception{ <br />
TokenStream ts = a.tokenStream("dummy",new StringReader(input)); <br />
StringReader readerInput = new StringReader(input); <br />
while(true){ <br />
Token t = ts.next(); <br />
if(t!=null){ <br />
System.out.print(t.termText); <br />
System.out.print(" "); <br />
} <br />
else <br />
break; <br />
<br />
} <br />
System.out.println(" "); <br />
ts.close(); <br />
} <br />
<br />
public void testSimpleAnalyzer() throws Exception { <br />
//学习使用SimpleAnalyzer(); <br />
//SimpleAnalyzer将除去letter之外的符号全部过滤掉,并且将所有的字符lowcase化 <br />
Analyzer a = new SimpleAnalyzer(); <br />
assertAnalyzesTo(a, "foo bar FOO BAR", <br />
new String[] { "foo", "bar", "foo", "bar" }); <br />
assertAnalyzesTo(a, "foo bar . FOO &lt;&gt; BAR", <br />
new String[] { "foo", "bar", "foo", "bar" }); <br />
assertAnalyzesTo(a, "foo.bar.FOO.BAR", <br />
new String[] { "foo", "bar", "foo", "bar" }); <br />
assertAnalyzesTo(a, "U.S.A.", <br />
new String[] { "u", "s", "a" }); <br />
assertAnalyzesTo(a, "C++", <br />
new String[] { "c" }); <br />
assertAnalyzesTo(a, "B2B", <br />
new String[] { "b", "b" }); <br />
assertAnalyzesTo(a, "2B", <br />
new String[] { "b" }); <br />
assertAnalyzesTo(a, "\"QUOTED\" word", <br />
new String[] { "quoted", "word" }); <br />
assertAnalyzesTo(a,"zhang ./ bu &lt;&gt; feng", <br />
new String[]{"zhang","bu","feng"}); <br />
ICTCLAS splitWord = new ICTCLAS(); <br />
String result = splitWord.paragraphProcess("我爱大家 i LOVE chanchan"); <br />
assertAnalyzesTo(a,result, <br />
new String[]{"我","爱","大家","i","love","chanchan"}); <br />
<br />
} <br />
<br />
public void testWhiteSpaceAnalyzer() throws Exception { <br />
//WhiterspaceAnalyzer仅仅是去除空格，对字符没有lowcase化 <br />
Analyzer a = new WhitespaceAnalyzer(); <br />
assertAnalyzesTo(a, "foo bar FOO BAR", <br />
new String[] { "foo", "bar", "FOO", "BAR" }); <br />
assertAnalyzesTo(a, "foo bar . FOO &lt;&gt; BAR", <br />
new String[] { "foo", "bar", ".", "FOO", "&lt;&gt;", "BAR" }); <br />
assertAnalyzesTo(a, "foo.bar.FOO.BAR", <br />
new String[] { "foo.bar.FOO.BAR" }); <br />
assertAnalyzesTo(a, "U.S.A.", <br />
new String[] { "U.S.A." }); <br />
assertAnalyzesTo(a, "C++", <br />
new String[] { "C++" }); <br />
<br />
assertAnalyzesTo(a, "B2B", <br />
new String[] { "B2B" }); <br />
assertAnalyzesTo(a, "2B", <br />
new String[] { "2B" }); <br />
assertAnalyzesTo(a, "\"QUOTED\" word", <br />
new String[] { "\"QUOTED\"", "word" }); <br />
<br />
assertAnalyzesTo(a,"zhang bu feng", <br />
new String []{"zhang","bu","feng"}); <br />
ICTCLAS splitWord = new ICTCLAS(); <br />
String result = splitWord.paragraphProcess("我爱大家 i love chanchan"); <br />
assertAnalyzesTo(a,result, <br />
new String[]{"我","爱","</em><em>大家</em><em>","i","love","chanchan"}); <br />
} <br />
<br />
public void testStopAnalyzer() throws Exception { <br />
//StopAnalyzer的功能超越了SimpleAnalyzer，在SimpleAnalyzer的基础上 <br />
//增加了去除StopWords的功能 <br />
Analyzer a = new StopAnalyzer(); <br />
assertAnalyzesTo(a, "foo bar FOO BAR", <br />
new String[] { "foo", "bar", "foo", "bar" }); <br />
assertAnalyzesTo(a, "foo a bar such FOO THESE BAR", <br />
new String[] { "foo", "bar", "foo", "bar" }); <br />
assertAnalyzesTo(a,"foo ./ a bar such ,./&lt;&gt; FOO THESE BAR ", <br />
new String[]{"foo","bar","foo","bar"}); <br />
ICTCLAS splitWord = new ICTCLAS(); <br />
String result = splitWord.paragraphProcess("我爱</em><em>大家</em><em> i Love chanchan such"); <br />
assertAnalyzesTo(a,result, <br />
new String[]{"我","爱","</em><em>大家</em><em>","i","love","chanchan"}); <br />
<br />
} <br />
public void testStandardAnalyzer() throws Exception{ <br />
//StandardAnalyzer的功能最为强大，对于中文采用的为单字切分 <br />
Analyzer a = new StandardAnalyzer(); <br />
assertAnalyzesTo(a,"foo bar Foo Bar", <br />
new String[]{"foo","bar","foo","bar"}); <br />
assertAnalyzesTo(a,"foo bar ./ Foo ./ BAR", <br />
new String[]{"foo","bar","foo","bar"}); <br />
assertAnalyzesTo(a,"foo ./ a bar such ,./&lt;&gt; FOO THESE BAR ", <br />
new String[]{"foo","bar","foo","bar"}); <br />
assertAnalyzesTo(a,"张步峰是天大学生", <br />
new String[]{"张","步","峰","是","天","大","学","生"}); <br />
//验证去除英文的标点符号 <br />
assertAnalyzesTo(a,"张,/步/,峰,.是.,天大&lt;&gt;学生", <br />
new String[]{"张","步","峰","是","天","大","学","生"}); <br />
//验证去除中文的标点符号 <br />
assertAnalyzesTo(a,"张。、步。、峰是。天大。学生", <br />
new String[]{"张","步","峰","是","天","大","学","生"}); <br />
} <br />
public void testChineseAnalyzer() throws Exception{ <br />
//可见ChineseAnalyzer在功能上和standardAnalyzer的功能差不多，但是可能在速度上慢于StandardAnalyzer <br />
Analyzer a = new ChineseAnalyzer(); <br />
<br />
//去空格 <br />
assertAnalyzesTo(a,"foo bar Foo Bar", <br />
new String[]{"foo","bar","foo","bar"}); <br />
assertAnalyzesTo(a,"foo bar ./ Foo ./ BAR", <br />
new String[]{"foo","bar","foo","bar"}); <br />
assertAnalyzesTo(a,"foo ./ a bar such ,./&lt;&gt; FOO THESE BAR ", <br />
new String[]{"foo","bar","foo","bar"}); <br />
assertAnalyzesTo(a,"张步峰是天大学生", <br />
new String[]{"张","步","峰","是","天","大","学","生"}); <br />
//验证去除英文的标点符号 <br />
assertAnalyzesTo(a,"张,/步/,峰,.是.,天大&lt;&gt;学生", <br />
new String[]{"张","步","峰","是","天","大","学","生"}); <br />
//验证去除中文的标点符号 <br />
assertAnalyzesTo(a,"张。、步。、峰是。天大。学生", <br />
new String[]{"张","步","峰","是","天","大","学","生"}); <br />
//不支持中英文写在一起 <br />
// assertAnalyzesTo(a,"我爱你 i love chanchan", <br />
/// new String[]{"我","爱","你","i","love","chanchan"}); <br />
<br />
} <br />
public void testCJKAnalyzer() throws Exception { <br />
//chedong写的CJKAnalyzer的功能在英文处理上的功能和StandardAnalyzer相同 <br />
//但是在汉语的分词上，不能过滤掉标点符号，即使用二元切分 <br />
Analyzer a = new CJKAnalyzer(); <br />
assertAnalyzesTo(a,"foo bar Foo Bar", <br />
new String[]{"foo","bar","foo","bar"}); <br />
assertAnalyzesTo(a,"foo bar ./ Foo ./ BAR", <br />
new String[]{"foo","bar","foo","bar"}); <br />
assertAnalyzesTo(a,"foo ./ a bar such ,./&lt;&gt; FOO THESE BAR ", <br />
new String[]{"foo","bar","foo","bar"}); <br />
<br />
// assertAnalyzesTo(a,"张,/步/,峰,.是.,天大&lt;&gt;学生", <br />
// new String[]{"张步","步峰","峰是","是天","天大","大学","学生"}); <br />
//assertAnalyzesTo(a,"张。、步。、峰是。天大。学生", <br />
// new String[]{"张步","步峰","峰是","是天","天大","大学","学生"}); <br />
//支持中英文同时写 <br />
assertAnalyzesTo(a,"张步峰是天大学生 i love", <br />
new String[]{"张步","步峰","峰是","是天","天大","大学","学生","i","love"}); <br />
<br />
} <br />
public void testTjuChineseAnalyzer() throws Exception{ <br />
/** <br />
* TjuChineseAnlyzer的功能相当强大,在中文分词方面由于其调用的为ICTCLAS的java接口. <br />
* 所以其在中文方面性能上同与ICTCLAS.其在英文分词上采用了Lucene的StopAnalyzer,可以去除 <br />
* stopWords,而且可以不区分大小写,过滤掉各类标点符号. <br />
*/ <br />
Analyzer a = new TjuChineseAnalyzer(); <br />
String input = "体育讯　在被尤文淘汰之后，皇马主帅博斯克拒绝接受媒体对球队后防线的批评，同时还为自己排出的首发阵容进行了辩护。"+ <br />
"&#8220;失利是全队的责任，而不仅仅是后防线该受指责，&#8221;博斯克说，&#8220;我并不认为我们踢得一塌糊涂。&#8221;&#8220;我们进入了半决赛，而且在晋级的道路上一路奋 "+ <br />
"战。即使是今天的比赛我们也有几个翻身的机会，但我们面对的对手非常强大，他们踢得非常好。&#8221;&#8220;我们的球迷应该为过去几个赛季里我们在冠军杯中的表现感到骄傲。&#8221;"+ <br />
"博斯克还说。对于博斯克在首发中排出了久疏战阵的坎比亚索，赛后有记者提出了质疑，认为完全应该将队内的另一 "+ <br />
"名球员帕文派遣上场以加强后卫线。对于这一疑议，博斯克拒绝承担所谓的&#8220;责任&#8221;，认为球队的首发没有问题。&#8220;我们按照整个赛季以来的方式做了，"+ <br />
"对于人员上的变化我没有什么可说的。&#8221;对于球队在本赛季的前景，博斯克表示皇马还有西甲联赛的冠军作为目标。&#8220;皇家马德里在冠军 "+ <br />
"杯中战斗到了最后，我们在联赛中也将这么做。&#8221;"+ <br />
"A Java User Group is a group of people who share a common interest in
Java technology and meet on a regular basis to share"+ <br />
" technical ideas and information. The actual structure of a JUG can
vary greatly - from a small number of friends and coworkers"+ <br />
" meeting informally in the evening, to a large group of companies based in the same geographic area. "+ <br />
"Regardless of the size and focus of a particular JUG, the sense of community spirit remains the same. "; <br />
<br />
outputAnalyzer(a,input); <br />
//此处我已经对大文本进行过测试,不会有问题效果很好 <br />
outputAnalyzer(a,"我爱</em><em>大家</em><em> ,，。 I love China 我喜欢唱歌 "); <br />
assertAnalyzesTo(a,"我爱</em><em>大家</em><em> ,，。I love China 我喜欢唱歌", <br />
new String[]{"爱","</em><em>大家</em><em>","i","love","china","喜欢","唱歌"}); <br />
} <br />
} </em>
<img src ="http://www.blogjava.net/super2/aggbug/237303.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 10:03 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237303.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]lucene学习笔记七: 几个问题</title><link>http://www.blogjava.net/super2/archive/2008/10/29/237299.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 02:00:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237299.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237299.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237299.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237299.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237299.html</trackback:ping><description><![CDATA[1, 被搜索的结果中,如何取得关键字周围的数据. 例如获取第一个关键字后面的数据.例如一段字符: <br />
<br />
我爱北京天安门,你喜欢吗. <br />
<br />
我搜:北京 <br />
获取结果如何获取: 北京天安门 . <br />
不要用substring或者正则解决了.那样对于大文本不是解决方案. 因为这个数据没必要全取出来 <br />
<br />
网上也有人问: 做全文检索时，想把查询到的附近的一段文本提取出来，像google那样，如何才能使性能根好？ 感觉indexof substring这些东性能会很差，如果是很大的文本 不知道大家有什么根好的办法，获取什么其它组件？ <br />
<br />
按照在 term vectors 中增加了 位置和偏移信息。(Grant Ingersoll &amp; Christoph)的bug修改后的提示.应该可以找到. <br />
<br />
2, 高亮显示. 下面有一例子说明. 顺便把2.0的那个bug说明也贴到下面 <br />
Lucene 中文分词的 highlight 显示 <br />
<br />
下面这个需要外的包: lucene-highlighter-2.2.0.jar 支持.请下载. 否则里面关于高亮显示的都不会编译成功. 下面程序是没有问题的.结果也对.就是有版主说的问题.<br />
<br />
lucene2.0 中文高亮的问题。新手问老问题，知道的大虾赐教: <br />
<br />
代码： <br />
public static void main(String[] args) { <br />
try { <br />
String text="上海麦为公贸易发展有限公司"; <br />
StandardAnalyzer ssss=new StandardAnalyzer(); <br />
QueryParser queryParse = new QueryParser("company_name", ssss); <br />
SimpleHTMLFormatter sHtmlF = new SimpleHTMLFormatter("&lt;b&gt;", "&lt;/b&gt;"); <br />
Highlighter hh = new Highlighter(sHtmlF,new QueryScorer(queryParse.parse("公司"))); <br />
TokenStream t=ssss.tokenStream("company_name",new StringReader(text)); <br />
Token tttt=t.next(); <br />
System.out.println(hh.getBestFragment(t,text)); <br />
} catch (Exception ex) { <br />
} <br />
} <br />
结果： <br />
上海麦为&lt;b&gt;公&lt;/b&gt;贸易发展有限&lt;b&gt;公&lt;/b&gt;&lt;b&gt;司&lt;/b&gt; <br />
<br />
<br />
两个问题: <br />
1，怎么让单字&#8220;公&#8221;不高亮。因为我只搜索了&#8220;公司&#8221; <br />
2，怎么实现&lt;b&gt;公司&lt;/b&gt;这样的高亮，而不是&lt;b&gt;公&lt;/b&gt;&lt;b&gt;司&lt;/b&gt; <br />
<br />
答: <br />
<br />
用中文分词器,,,StandardAnalyzer是单字分词的 <br />
1、分词问题 <br />
2、Highlighter highlighter =new Highlighter(new
SimpleHTMLFormatter("&lt;fontcolor=red&gt;","&lt;/font&gt;"),new
QueryScorer(query)); <br />
需要有一个好的中文分词工具，能分出你需要的词语，然后加亮。比如你可以用ik-analyzer啊等等的。 <br />
<br />
<br />
2.0bug解决:: <br />
22. 增加对 contrib/highlighter 的 NullFragmenter , 这对全文本加亮很有用。 <br />
(Erik Hatcher)
<img src ="http://www.blogjava.net/super2/aggbug/237299.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 10:00 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237299.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]lucene学习笔记六——Lucene的搜索(IndexSearcher)</title><link>http://www.blogjava.net/super2/archive/2008/10/29/237296.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 01:58:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237296.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237296.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237296.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237296.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237296.html</trackback:ping><description><![CDATA[<p>Lucene包括很多种不同的搜索方式，首先生成一个检索器IndexSearcher searcher = new
IndexSearcher("Index_Path", new StandardAnalyzer(),
true)，然后再调用searcher.search(query)，其中典型的query查询方式有以下几种：</p>
<p>1）按词条搜索：<strong>TermQuery</strong>，即搜索某一词条。<br />
方法如下：Query query = new TermQuery(new Term("field", "keyword")); <br />
其中参数field指欲查找的字段，keyword指欲检索的关键字。</p>
<p>2）在某一范围类搜索：<strong>RangeQuery<br />
</strong>方法如下：RangeQuery query = new RangeQuery(begin, end, include);<br />
其中参数begin和end均是一个Term对象，分别指在索引中相应Term的起始位置和结束位置。include是一个boolean值，true表是包含起始和结束位置，false表示不包含边界值。</p>
<p>3）多关键字的搜索：<strong>PhraseQuery<br />
</strong>方法如下：<br />
PhraseQuery query = new PhraseQuery();<br />
query.add(new Term("content","keyword1"));<br />
query.add(new Term("content","keyword2"));<br />
要
注意的是PhraseQuery类中有一个setSlop方法，该方法用于设定一个称之为"坡度"的变量，来确定关键字之间是否允许、允许多少个无关词汇
存在。默认值为0，即两个关键字之间无任何词汇存在，才能被搜索到。设置该值以后，只有当两个关键字之间无关词的数目小于等于坡度值是，才能被搜索
到。（文章末尾给出了具体例子）</p>
<p>4）使用通配符搜索：<strong>WildcardQuery<br />
</strong>使用方法类似于1），只不过字段的关键字允许使用?（代表一个字符）、*（代表多个字符）</p>
<p>另外，还有以下不同的搜索方法：</p>
<p>&#8220;与或&#8221;搜索<strong>BooleanQuery、</strong>使用前缀搜索<strong>PerfixQuery、</strong>使用短语缀搜索<strong>PhrasePrefixQuery、</strong>模糊查询搜索<strong>FuzzyQuery等。</strong></p>
<br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);"><br />
&nbsp;*&nbsp;多关键字搜索的例子</span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br />
</span><span style="color: rgb(0, 0, 255);">package</span><span style="color: rgb(0, 0, 0);">&nbsp;testlucene;<br />
</span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);">&nbsp;org.apache.lucene.analysis.standard.</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">;<br />
</span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);">&nbsp;org.apache.lucene.document.</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">;<br />
</span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);">&nbsp;org.apache.lucene.index.</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">;<br />
</span><span style="color: rgb(0, 0, 255);">import</span><span style="color: rgb(0, 0, 0);">&nbsp;org.apache.lucene.search.</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">;<br />
</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;PhraseQueryTest&nbsp;{<br />
&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;main(String[]&nbsp;args)</span><span style="color: rgb(0, 0, 255);">throws</span><span style="color: rgb(0, 0, 0);">&nbsp;Exception{<br />
&nbsp;&nbsp;Document&nbsp;doc1&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Document();<br />
&nbsp;&nbsp;doc1.add(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Field(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">content</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">david&nbsp;mary&nbsp;smith&nbsp;robert</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,Field.Store.YES,Field.Index.TOKENIZED));<br />
&nbsp;&nbsp;doc1.add(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Field(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">title</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">doc1</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,Field.Store.YES,Field.Index.TOKENIZED));<br />
&nbsp;&nbsp;Document&nbsp;doc2&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Document();<br />
&nbsp;&nbsp;doc2.add(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Field(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">content</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">david&nbsp;smith&nbsp;mary&nbsp;robert</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,Field.Store.YES,Field.Index.TOKENIZED));<br />
&nbsp;&nbsp;doc2.add(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Field(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">title</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">doc2</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,Field.Store.YES,Field.Index.TOKENIZED));<br />
&nbsp;&nbsp;Document&nbsp;doc3&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Document();<br />
&nbsp;&nbsp;doc3.add(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Field(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">content</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">david&nbsp;smith&nbsp;robert&nbsp;mary</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,Field.Store.YES,Field.Index.TOKENIZED));<br />
&nbsp;&nbsp;doc3.add(</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Field(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">title</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">doc3</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,Field.Store.YES,Field.Index.TOKENIZED));<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;IndexWriter&nbsp;writer&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;IndexWriter(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">c:\\index</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;StandardAnalyzer(),</span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">writer.setUseCompoundFile(true);&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">设置为混合索引格式</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;writer.addDocument(doc1);<br />
&nbsp;&nbsp;writer.addDocument(doc2);<br />
&nbsp;&nbsp;writer.addDocument(doc3);<br />
&nbsp;&nbsp;writer.close();<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;IndexSearcher&nbsp;searcher&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;IndexSearcher(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">c:\\index</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;Term&nbsp;word1&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Term(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">content</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">david</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;Term&nbsp;word2&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Term(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">content</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">mary</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;Term&nbsp;word3&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Term(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">content</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">smith</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;Term&nbsp;word4&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Term(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">content</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">robert</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;PhraseQuery&nbsp;query&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;PhraseQuery();<br />
&nbsp;&nbsp;query.add(word1);<br />
&nbsp;&nbsp;query.add(word2);<br />
&nbsp;&nbsp;query.add(word3);<br />
&nbsp;&nbsp;query.setSlop(Integer.MAX_VALUE);<br />
&nbsp;&nbsp;Hits&nbsp;hits&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;searcher.search(query);<br />
&nbsp;&nbsp;Print.printResult(hits,</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">david&nbsp;and&nbsp;mary</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;}<br />
}</span></div>
<img src ="http://www.blogjava.net/super2/aggbug/237296.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 09:58 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237296.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]lucene学习笔记五 </title><link>http://www.blogjava.net/super2/archive/2008/10/29/237293.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 01:54:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237293.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237293.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237293.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237293.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237293.html</trackback:ping><description><![CDATA[<p>Lucene实现对查询结果的排序：</p>
<p>Sort sort = new Sort(new SortField("isbn", false)); //单个字段</p>
<p>Sort sort = new Sort(new SortField[]{new SortField("isbn", false), new SortField("pbl_dt", true)}); //多个字段</p>
<p>其中,SortField的构造函数中第二个参数能够确定是升序还是降序。(true：降序； &nbsp;false：升序)</p>
<p>提醒：索引中tokenized的字段是不能被排序的，否则会抛异常。</p>
<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.lucene.search;<br />
<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.io.File;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.io.IOException;<br />
<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;org.apache.lucene.index.Term;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;org.apache.lucene.search.Hits;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;org.apache.lucene.search.IndexSearcher;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;org.apache.lucene.search.Sort;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;org.apache.lucene.search.SortField;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;org.apache.lucene.search.TermQuery;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;org.apache.lucene.store.Directory;<br />
</span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;org.apache.lucene.store.FSDirectory;<br />
<br />
</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Searcher&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main(String[]&nbsp;args)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;indexDir&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;File(</span><span style="color: #000000;">"</span><span style="color: #000000;">C:\\target\\index\\book</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;q&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">书</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">indexDir.exists()&nbsp;</span><span style="color: #000000;">||</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">indexDir.isDirectory())&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throw</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;IOException();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;search(indexDir,&nbsp;q);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;search(File&nbsp;indexDir,&nbsp;String&nbsp;q)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Exception&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Directory&nbsp;fsDir&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;FSDirectory.getDirectory(indexDir);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IndexSearcher&nbsp;searcher&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;IndexSearcher(fsDir);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">Sort&nbsp;sort&nbsp;=&nbsp;new&nbsp;Sort(new&nbsp;SortField("isbn",&nbsp;false));</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Sort&nbsp;sort&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Sort(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;SortField[]{</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;SortField(</span><span style="color: #000000;">"</span><span style="color: #000000;">isbn</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">),&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;SortField(</span><span style="color: #000000;">"</span><span style="color: #000000;">pbl_dt</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">)});<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Term&nbsp;term&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Term(</span><span style="color: #000000;">"</span><span style="color: #000000;">content</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;q.toLowerCase());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TermQuery&nbsp;termQuery&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;TermQuery(term);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Hits&nbsp;hits&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;searcher.search(termQuery,&nbsp;sort);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">共有</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;searcher.maxDoc()&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">条索引，命中</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;hits.length()&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">条</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;hits.length();&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;DocId&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;hits.id(i);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;DocName&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;hits.doc(i).get(</span><span style="color: #000000;">"</span><span style="color: #000000;">name</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;DocIsbn&nbsp;&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;hits.doc(i).get(</span><span style="color: #000000;">"</span><span style="color: #000000;">isbn</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;DocPblDt&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;hits.doc(i).get(</span><span style="color: #000000;">"</span><span style="color: #000000;">pbl_dt</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(DocId&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">:</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;DocName&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;&nbsp;ISBN:</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;DocIsbn&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;&nbsp;PBLDT:</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;DocPblDt);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</span></div>
<img src ="http://www.blogjava.net/super2/aggbug/237293.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 09:54 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237293.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]lucene学习笔记四</title><link>http://www.blogjava.net/super2/archive/2008/10/29/237284.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 01:43:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237284.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237284.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237284.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237284.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237284.html</trackback:ping><description><![CDATA[1, 几种span的querySpanTermQuery：检索效果完全同TermQuery，但内部会记录一些位置信息，供SpanQuery的其它API使用，是其它属于SpanQuery的Query的基础。 <br />
SpanFirstQuery：查找方式为从Field的内容起始位置开始，在一个固定的宽度内查找所指定的词条。 <br />
SpanNearQuery：功能类似PharaseQuery。SpanNearQuery查找所匹配的不一定是短语，还有可能是另一个SpanQuery的查询结果作为整体考虑，进行嵌套查询。 <br />
SpanOrQuery：把所有SpanQuery查询结果综合起来，作为检索结果。 <br />
SpanNotQuery：从第一个SpanQuery查询结果中，去掉第二个SpanQuery查询结果，作为检索结果。 <br />
<br />
2, 多条件索引关系 <br />
<br />
BooleanClause用于表示布尔查询子句关系的类，包
括：BooleanClause.Occur.MUST，BooleanClause.Occur.MUST_NOT，BooleanClause.Occur.SHOULD。
有以下6种组合： <br />
1．MUST和MUST：取得连个查询子句的交集。 <br />
2．MUST和MUST_NOT：表示查询结果中不能包含MUST_NOT所对应得查询子句的检索结果。 <br />
3．MUST_NOT和MUST_NOT：无意义，检索无结果。 <br />
4．SHOULD与MUST、SHOULD与MUST_NOT：SHOULD与MUST连用时，无意义，结果为MUST子句的检索结果。与MUST_NOT连用时，功能同MUST。 <br />
5．SHOULD与SHOULD：表示&#8220;或&#8221;关系，最终检索结果为所有检索子句的并集。
<img src ="http://www.blogjava.net/super2/aggbug/237284.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 09:43 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237284.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]lucene学习笔记三 各种query</title><link>http://www.blogjava.net/super2/archive/2008/10/29/237283.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 01:42:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237283.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237283.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237283.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237283.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237283.html</trackback:ping><description><![CDATA[1,
有时对于一个Document来说，有一些Field会被频繁地操作，而另一些Field则不会。这时可以将频繁操作的Field和其他Field分开存
放，而在搜索时同时检索这两部分Field而提取出一个完整的Document。 这要求两个索引包含的Document的数量必须相同。 <br />
在创建索引的时候，可以同时创建多个IndexWriter，将一个Document根据需要拆分成多个包含部分Field的Document，并将这些Document分别添加到不同的索引。 <br />
而在搜索时，则必须借助ParallelReader类来整合。 <br />
Directory dir1=FSDirectory.getDirectory(new File(INDEX_DIR1),false); <br />
Directory dir2=FSDirectory.getDirectory(new File(INDEX_DIR2),false); <br />
<strong>ParallelReader preader=new ParallelReader(); <br />
preader.add(IndexReader.open(dir1)); <br />
preader.add(IndexReader.open(dir2));</strong> <br />
IndexSearcher searcher=new IndexSearcher(preader); <br />
之后的操作和一般的搜索相同。 <br />
<br />
2, Query的子类. 下面的几个搜索在各种不同要求的场合,都会用到. 需要大家仔细研读! <br />
<br />
Query query1 = new TermQuery(new Term(FieldValue, "name1")); // 词语搜索 <br />
Query query2 = new WildcardQuery(new Term(FieldName, "name*")); // 通配符 <br />
Query query3 = new PrefixQuery(new Term(FieldName, "name1")); // 字段搜索 Field:Keyword，自动在结尾添加 * <br />
Query query4 = new RangeQuery(new Term(FieldNumber,
NumberTools.LongToString(11L)), new Term(FieldNumber,
NumberTools.LongToString(13L)), true); // 范围搜索 <br />
Query query5 = new FilteredQuery(query, filter); // 带过滤条件的搜索 <br />
Query query6 =new MatchAllDocsQuery(... // 用来匹配所有文档 <br />
Query query7 = new FuzzyQuery (...模糊搜索 <br />
Query query8 = new RegexQuery (..   正则搜索 <br />
Query query9 = new SpanRegexQuery(...)。 同上, 正则表达式的查询： <br />
Query query9 = new SpanQuery 的子类嵌套其他SpanQuery 增加了 rewrite方法 <br />
Query query10 =new DisjunctionMaxQuery () ..类，提供了针对某个短语的最大score。这一点对多字段的搜索非常有用 <br />
Query query11 = new ConstantScoreQuery 类它包装了一个 filter produces a score <br />
equal to the query boost for every matching document. <br />
<br />
BooleanQuery query12= new BooleanQuery(); <br />
booleanQuery.add(termQuery 1, BooleanClause.Occur.SHOULD); <br />
booleanQuery.add(termQuery 2, BooleanClause.Occur.SHOULD); <br />
//这个是为了联合多个查询而做的Query类. BooleanQuery增加了最小的匹配短语。见：BooleanQuery.setMinimumNumberShouldMatch(). <br />
<br />
<br />
PhraseQuery <br />
你可能对中日关系比较感兴趣，想查找&#8216;中&#8217;和&#8216;日&#8217;挨得比较近（5个字的距离内）的文章，超过这个距离的不予考虑，你可以： <br />
<br />
PhraseQuery query 13= new PhraseQuery(); <br />
query.setSlop(5); <br />
query.add(new Term("content ", &#8220;中&#8221;)); <br />
query.add(new Term(&#8220;content&#8221;, &#8220;日&#8221;)); <br />
<br />
PhraseQuery对于短语的顺序是不管的,这点在查询时除了提高命中率外,也会对性能产生很大的影响, 利用SpanNearQuery可以对短语的顺序进行控制,提高性能 <br />
<br />
BooleanQuery query12=   new SpanNearQuery 可以对短语的顺序进行控制,提高性能 <br />
<br />
3, 索引文本文件 <br />
如果你想把纯文本文件索引起来，而不想自己将它们读入字符串创建field，你可以用下面的代码创建field： <br />
<br />
Field field = new Field("content", new FileReader(file)); <br />
<br />
这里的file就是该文本文件。该构造函数实际上是读去文件内容，并对其进行索引，但不存储 <br />
<br />
<br />
4, 如何删除索引 <br />
lucene提供了两种从索引中删除document的方法，一种是 <br />
<br />
void deleteDocument(int docNum) <br />
<br />
这种方法是根据document在索引中的编号来删除，每个document加进索引后都会有个唯一编号，所以根据编号删除是一种精确删除，但是这个编号是索引的内部结构，一般我们不会知道某个文件的编号到底是几，所以用处不大。另一种是 <br />
<br />
void deleteDocuments(Term term) <br />
<br />
这种方法实际上是首先根据参数term执行一个搜索操作，然后把搜索到的结果批量删除了。我们可以通过这个方法提供一个严格的查询条件，达到删除指定document的目的。 <br />
下面给出一个例子： <br />
<br />
Directory dir = FSDirectory.getDirectory(PATH, false); <br />
IndexReader reader = IndexReader.open(dir); <br />
Term term = new Term(field, key); <br />
reader.deleteDocuments(term); <br />
reader.close(); <br />
<br />
<br />
<br />
5, 如何更新索引 <br />
lucene并没有提供专门的索引更新方法，我们需要先将相应的document删除，然后再将新的document加入索引。例如： <br />
<br />
Directory dir = FSDirectory.getDirectory(PATH, false); <br />
IndexReader reader = IndexReader.open(dir); <br />
Term term = new Term(&#8220;title&#8221;, &#8220;lucene introduction&#8221;); <br />
reader.deleteDocuments(term); <br />
reader.close(); <br />
<br />
IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(), true); <br />
Document doc = new Document(); <br />
doc.add(new Field("title", "lucene introduction", Field.Store.YES, Field.Index.TOKENIZED)); <br />
doc.add(new Field("content", "lucene is funny", Field.Store.YES, Field.Index.TOKENIZED)); <br />
writer.addDocument(doc); <br />
writer.optimize(); <br />
writer.close(); <br />
<br />
<br />
但是在1.9RC1中说明: <br />
新增类： org.apache.lucene.index.IndexModifier ，它合并了 IndexWriter 和
IndexReader，好处是我们可以增加和删除文档的时候不同担心 synchronisation/locking 的问题了。 <br />
<br />
6, filer类.使用 Filter 对搜索结果进行过滤，可以获得更小范围内更精确的结果。 有人说: 注意它执行的是预处理，而不是对查询结果进行过滤，所以使用filter的代价是很大的，它可能会使一次查询耗时提高一百倍 <br />
<br />
<br />
ISOLatin1AccentFilter ,用 ISO Latin 1 字符集中的unaccented类字符替代 accented 类字符 <br />
DateFilter   日期过滤器 <br />
RangeFileter ,比 DateFilter 更加通用，实用 <br />
LengthFilter 类, 已经从 contrib 放到了 core 代码里。从 stream 中去掉太长和太短的单词   StopFilter 类, 增加了对处理stop words 的忽略大小写处理 <br />
<br />
<br />
7,本条是一个使用过滤的说明: <br />
<br />
过滤 <br />
<br />
使用 Filter 对搜索结果进行过滤，可以获得更小范围内更精确的结果。 <br />
<br />
举个例子，我们搜索上架时间在 2005-10-1 到 2005-10-30 之间的商品。 <br />
对于日期时间，我们需要转换一下才能添加到索引库，同时还必须是索引字段。 <br />
// index <br />
document.Add(FieldDate, DateField.DateToString(date), Field.Store.YES, Field.Index.UN_TOKENIZED); <br />
<br />
//... <br />
<br />
// search <br />
Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-1"), DateTime.Parse("2005-10-30")); <br />
Hits hits = searcher.Search(query, filter); <br />
<br />
除了日期时间，还可以使用整数。比如搜索价格在 100 ~ 200 之间的商品。 <br />
Lucene.Net NumberTools 对于数字进行了补位处理，如果需要使用浮点数可以自己参考源码进行。 <br />
// index <br />
document.Add(new Field(FieldNumber, NumberTools.LongToString((long)price), Field.Store.YES, Field.Index.UN_TOKENIZED)); <br />
<br />
//... <br />
<br />
// search <br />
Filter filter = new RangeFilter(FieldNumber, NumberTools.LongToString(100L), NumberTools.LongToString(200L), true, true); <br />
Hits hits = searcher.Search(query, filter); <br />
<br />
使用 Query 作为过滤条件。 <br />
QueryFilter filter = new QueryFilter(QueryParser.Parse("name2", FieldValue, analyzer)); <br />
<br />
我们还可以使用 FilteredQuery 进行多条件过滤。 <br />
<br />
Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-10"), DateTime.Parse("2005-10-15")); <br />
Filter filter2 = new RangeFilter(FieldNumber, NumberTools.LongToString(11L), NumberTools.LongToString(13L), true, true); <br />
<br />
Query query = QueryParser.Parse("name*", FieldName, analyzer); <br />
query = new FilteredQuery(query, filter); <br />
query = new FilteredQuery(query, filter2); <br />
<br />
IndexSearcher searcher = new IndexSearcher(reader); <br />
Hits hits = searcher.Search(query); <br />
<br />
<br />
<br />
8, Sort <br />
有时你想要一个排好序的结果集，就像SQL语句的&#8220;order by&#8221;，lucene能做到：通过Sort。 <br />
Sort sort = new Sort(&#8220;time&#8221;); //相当于SQL的&#8220;order by time&#8221; <br />
Sort sort = new Sort(&#8220;time&#8221;, true); // 相当于SQL的&#8220;order by time desc&#8221; <br />
下面是一个完整的例子： <br />
<br />
Directory dir = FSDirectory.getDirectory(PATH, false); <br />
IndexSearcher is = new IndexSearcher(dir); <br />
QueryParser parser = new QueryParser("content", new StandardAnalyzer()); <br />
Query query = parser.parse("title:lucene content:lucene"; <br />
RangeFilter filter = new RangeFilter("time", "20060101", "20060230", true, true); <br />
Sort sort = new Sort(&#8220;time&#8221;); <br />
Hits hits = is.search(query, filter, sort); <br />
for (int i = 0; i &lt; hits.length(); i++) <br />
{ <br />
Document doc = hits.doc(i); <br />
System.out.println(doc.get("title"); <br />
} <br />
is.close(); <br />
<br />
9,   性能优化 <br />
一直到这里，我们还是在讨论怎么样使lucene跑起来，完成指定任务。利用前面说的也确实能完成大部分功能。但是测试表明lucene的性能并不是很
好，在大数据量大并发的条件下甚至会有半分钟返回的情况。另外大数据量的数据初始化建立索引也是一个十分耗时的过程。那么如何提高lucene的性能呢？
下面从优化创建索引性能和优化搜索性能两方面介绍。 <br />
<br />
9.1 优化创建索引性能 <br />
这方面的优化途径比较有限，IndexWriter提供了一些接口可以控制建立索引的操作，另外我们可以先将索引写入RAMDirectory，再批量写
入FSDirectory，不管怎样，目的都是尽量少的文件IO，因为创建索引的最大瓶颈在于磁盘IO。另外选择一个较好的分析器也能提高一些性能。 <br />
<br />
9.1.1 通过设置IndexWriter的参数优化索引建立 <br />
setMaxBufferedDocs(int maxBufferedDocs) <br />
控制写入一个新的segment前内存中保存的document的数目，设置较大的数目可以加快建索引速度，默认为10。 <br />
setMaxMergeDocs(int maxMergeDocs) <br />
控制一个segment中可以保存的最大document数目，值较小有利于追加索引的速度，默认Integer.MAX_VALUE，无需修改。 <br />
setMergeFactor(int mergeFactor) <br />
控制多个segment合并的频率，值较大时建立索引速度较快，默认是10，可以在建立索引时设置为100。 <br />
<br />
9.1.2 通过RAMDirectory缓写提高性能 <br />
我们可以先把索引写入RAMDirectory，达到一定数量时再批量写进FSDirectory，减少磁盘IO次数。 <br />
<br />
FSDirectory fsDir = FSDirectory.getDirectory("/data/index", true); <br />
RAMDirectory ramDir = new RAMDirectory(); <br />
IndexWriter fsWriter = new IndexWriter(fsDir, new StandardAnalyzer(), true); <br />
IndexWriter ramWriter = new IndexWriter(ramDir, new StandardAnalyzer(), true); <br />
while (there are documents to index) <br />
{ <br />
... create Document ... <br />
ramWriter.addDocument(doc); <br />
if (condition for flushing memory to disk has been met) <br />
{ <br />
fsWriter.addIndexes(new Directory[] { ramDir }); <br />
ramWriter.close(); <br />
ramWriter = new IndexWriter(ramDir, new StandardAnalyzer(), true); <br />
} <br />
} <br />
<br />
9.1.3 选择较好的分析器 <br />
这个优化主要是对磁盘空间的优化，可以将索引文件减小将近一半，相同测试数据下由600M减少到380M。但是对时间并没有什么帮助，甚至会需要更长时
间，因为较好的分析器需要匹配词库，会消耗更多cpu，测试数据用StandardAnalyzer耗时133分钟；用MMAnalyzer耗时150分
钟。 <br />
<br />
9.2 优化搜索性能 <br />
虽然建立索引的操作非常耗时，但是那毕竟只在最初创建时才需要，平时只是少量的维护操作，更何况这些可以放到一个后台进程处理，并不影响用户搜索。我们创建索引的目的就是给用户搜索，所以搜索的性能才是我们最关心的。下面就来探讨一下如何提高搜索性能。 <br />
<br />
9.2.1 将索引放入内存 <br />
这是一个最直观的想法，因为内存比磁盘快很多。Lucene提供了RAMDirectory可以在内存中容纳索引： <br />
<br />
Directory fsDir = FSDirectory.getDirectory(&#8220;/data/index/&#8221;, false); <br />
Directory ramDir = new RAMDirectory(fsDir); <br />
Searcher searcher = new IndexSearcher(ramDir); <br />
<br />
但是实践证明RAMDirectory和FSDirectory速度差不多，当数据量很小时两者都非常快，当数据量较大时（索引文件400M）RAMDirectory甚至比FSDirectory还要慢一点，这确实让人出乎意料。 <br />
而且lucene的搜索非常耗内存，即使将400M的索引文件载入内存，在运行一段时间后都会out of memory，所以个人认为载入内存的作用并不大。 <br />
<br />
9.2.2 优化时间范围限制 <br />
既然载入内存并不能提高效率，一定有其它瓶颈，经过测试发现最大的瓶颈居然是时间范围限制，那么我们可以怎样使时间范围限制的代价最小呢？ <br />
当需要搜索指定时间范围内的结果时，可以： <br />
1、用RangeQuery，设置范围，但是RangeQuery的实现实际上是将时间范围内的时间点展开，组成一个个BooleanClause加入到
BooleanQuery中查询，
因此时间范围不可能设置太大，经测试，范围超过一个月就会抛BooleanQuery.TooManyClauses，可以通过设置
BooleanQuery.setMaxClauseCount(int
maxClauseCount)扩大，但是扩大也是有限的，并且随着maxClauseCount扩大，占用内存也扩大 <br />
2、用RangeFilter代替RangeQuery，经测试速度不会比RangeQuery慢，但是仍然有性能瓶颈，查询的90%以上时间耗费在
RangeFilter，研究其源码发现RangeFilter实际上是首先遍历所有索引，生成一个BitSet，标记每个document，在时间范围
内的标记为true，不在的标记为false，然后将结果传递给Searcher查找，这是十分耗时的。 <br />
3、进一步提高性能，这个又有两个思路： <br />
a、缓存Filter结果。既然RangeFilter的执行是在搜索之前，那么它的输入都是一定的，就是IndexReader，而
IndexReader是由Directory决定的，所以可以认为RangeFilter的结果是由范围的上下限决定的，也就是由具体的
RangeFilter对象决定，所以我们只要以RangeFilter对象为键，将filter结果BitSet缓存起来即可。lucene
API已经提供了一个CachingWrapperFilter类封装了Filter及其结果，所以具体实施起来我们可以cache
CachingWrapperFilter对象，需要注意的是，不要被CachingWrapperFilter的名字及其说明误
导，CachingWrapperFilter看起来是有缓存功能，但的缓存是针对同一个filter的，也就是在你用同一个filter过滤不同
IndexReader时，它可以帮你缓存不同IndexReader的结果，而我们的需求恰恰相反，我们是用不同filter过滤同一个
IndexReader，所以只能把它作为一个封装类。 <br />
b、降低时间精度。研究Filter的工作原理可以看出，它每次工作都是遍历整个索引的，所以时间粒度越大，对比越快，搜索时间越短，在不影响功能的情况下，时间精度越低越好，有时甚至牺牲一点精度也值得，当然最好的情况是根本不作时间限制。 <br />
下面针对上面的两个思路演示一下优化结果（都采用800线程随机关键词随即时间范围）： <br />
第一组，时间精度为秒： <br />
方式 直接用RangeFilter 使用cache 不用filter <br />
平均每个线程耗时 10s 1s 300ms <br />
<br />
第二组，时间精度为天 <br />
方式 直接用RangeFilter 使用cache 不用filter <br />
平均每个线程耗时 900ms 360ms 300ms <br />
<br />
由以上数据可以得出结论： <br />
1、 尽量降低时间精度，将精度由秒换成天带来的性能提高甚至比使用cache还好，最好不使用filter。 <br />
2、 在不能降低时间精度的情况下，使用cache能带了10倍左右的性能提高。 <br />
<br />
9.2.3 使用更好的分析器 <br />
这个跟创建索引优化道理差不多，索引文件小了搜索自然会加快。当然这个提高也是有限的。较好的分析器相对于最差的分析器对性能的提升在20%以下。 <br />
<br />
10 一些经验 <br />
<br />
10.1关键词区分大小写 <br />
<strong>or AND TO等关键词是区分大小写的，lucene只认大写的，小写的当做普通单词。</strong> <br />
<br />
10.2 读写互斥性 <br />
同一时刻只能有一个对索引的写操作，在写的同时可以进行搜索 <br />
<br />
10.3 文件锁 <br />
在写索引的过程中强行退出将在tmp目录留下一个lock文件，使以后的写操作无法进行，可以将其手工删除 <br />
<br />
10.4 时间格式 <br />
<strong>lucene只支持一种时间格式yyMMddHHmmss，所以你传一个yy-MM-dd HH:mm:ss的时间给lucene它是不会当作时间来处理的</strong> <br />
<br />
10.5 设置boost <br />
有些时候在搜索时某个字段的权重需要大一些，例如你可能认为标题中出现关键词的文章比正文中出现关键词的文章更有价值，你可以把标题的boost设置的更大，那么搜索结果会优先显示标题中出现关键词的文章（没有使用排序的前题下）。使用方法： <br />
Field. setBoost(float boost);默认值是1.0，也就是说要增加权重的需要设置得比1大。 <br />
<br />
上面这篇关于性能的讲解是很深刻. 请学习.
<img src ="http://www.blogjava.net/super2/aggbug/237283.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 09:42 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237283.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]lucene学习笔记二. 1.9版本升级的问题.</title><link>http://www.blogjava.net/super2/archive/2008/10/29/237282.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 01:41:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237282.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237282.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237282.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237282.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237282.html</trackback:ping><description><![CDATA[Lucene 1.9 改进特性列表1.9 RC1 <br />
注：lucene2.0发布版本并不是100%的和1.4.3版兼容。也就是说在你用2.0版本的Lucene开发包替换原来的1.4.3版本时，应该让你的应用程序首先和1.9的兼容。 <br />
使用前提： <br />
1. 编译和使用Lucene需要 Java1.4 或以上版本。 <br />
Lucene 1.9 在运行时的变化： <br />
1. 模糊搜索 FuzzyQuery 不再抛出 TooManyClauses 异常。当 FuzzyQuery 扩展多于
BooleanQuery.maxClauseCount 时 ，只有最相关的term会被重新写入query,因此避免了异常的抛出。
(Christoph) <br />
2. 把系统属性 "org.apache.lucene.lockdir" 改为   "org.apache.lucene.lockDir"。(Bernhard) <br />
<br />
1.9 RC1 <br />
注：lucene2.0发布版本并不是100%的和1.4.3版兼容。也就是说在你用2.0版本的Lucene开发包替换原来的1.4.3版本时，应该让你的应用程序首先和1.9的兼容。 <br />
使用前提： <br />
1. 编译和使用Lucene需要 Java1.4 或以上版本。 <br />
Lucene 1.9 在运行时的变化： <br />
1. 模糊搜索 FuzzyQuery 不再抛出 TooManyClauses 异常。当 FuzzyQuery 扩展多于
BooleanQuery.maxClauseCount 时 ，只有最相关的term会被重新写入query,因此避免了异常的抛出。
(Christoph) <br />
2. 把系统属性 "org.apache.lucene.lockdir" 改为   "org.apache.lucene.lockDir"。(Bernhard) <br />
3. RangeQueries 和 FuzzyQueries 默认被转换成小写。 (as it has been the case for
PrefixQueries and WildcardQueries before).使用
setLowercaseExpandedTerms(false) 来禁止大小写自动转换的行为；同样也影响 PrefixQueries 和
WildcardQueries。(Daniel Naber) <br />
4. 在使用 MultiSearcher 的时候文档频率也可以正确计算，全局性的计算各个 subsearchers 和 indices
中。以前计算的时候只是 locally 的，每个 index 的计算是分开的，这样引发的一个问题是：在多个indices中rank
是不相等的。 <br />
(Chuck Williams, Wolf Siberski via Otis, bug #31841) <br />
5. 在打开 IndexWriter 使用 create=true 参数，Lucene
现在只是删除index目录中属于Lucene自己的文件。( 判断文件名后缀的方式 )。原来是删除整个目录中的所有文件。(Daniel
Naber and Bernhard Messer, bug #34695) <br />
6. IndexReader 的版本 ，可以通过 getCurrentVersion() 和 getVersion()
返回。以前如果是新的indexes 那么返回的是0 。现在则用系统的毫秒数来初始化。 (Bernhard Messer via Daniel
Naber) <br />
7. 一些默认的初始化值不再允许通过 system properties 来设置。相反在 IndexWriter 中新增了相关的 set/get 方法来设置相关属性。主要包括以下属性： <br />
在 IndexWriter 的 getter/setter 方法中: <br />
org.apache.lucene.writeLockTimeout, org.apache.lucene.commitLockTimeout, <br />
org.apache.lucene.minMergeDocs, org.apache.lucene.maxMergeDocs, <br />
org.apache.lucene.maxFieldLength, org.apache.lucene.termIndexInterval, <br />
org.apache.lucene.mergeFactor, <br />
还有 BooleanQuery 的 getter/setter 方法: <br />
org.apache.lucene.maxClauseCount <br />
还有 FSDirectory 的 getter/setter 方法： <br />
disableLuceneLocks <br />
(Daniel Naber) <br />
8. 修改了 FieldCacheImpl 方法使用用户提供的 IntParser 和 FloatParser,来替代使用 Integer 和 Float 的相关方法。 <br />
(Yonik Seeley via Otis Gospodnetic) <br />
9. 高级搜索返回的 TopDocs 和 TopFieldDocs 不再规范scores。 <br />
(Luc Vanlerberghe via Yonik Seeley, LUCENE-469) <br />
1.9 的新特性： <br />
1. 增加了对压缩字段存储的支持。(patch #31149) <br />
(Bernhard Messer via Christoph) <br />
2. 增加了对压缩字段存储的支持。(patch #29370) <br />
(Bernhard Messer via Christoph) <br />
3. 在 term vectors 中增加了 位置和偏移信息。(Grant Ingersoll &amp; Christoph) <br />
4. 增加了一个新的 DateTools 。允许用户格式化日期到一种更可读的格式，以便于更好的适应索引。DateTools 不像
DateFields 类，它允许日期指定到1970年以前，但必须使用指定的日期格式。这样，在RangeQuerys中使用就更加有效率了。
(Daniel Naber) <br />
5. QueryParser 现在可以正确的和Analyzers 一起工作了，即可以在一个位置返回多个 Token 。 比如：查询：
&#8220;+fast + car&#8221;如果 Analyzer 在同一位置返回 car 和 automobile ，那么上面的查询将被解析成：&#8221;+fast
+(car automobile)&#8221;。 (Pierrick Brihaye, Daniel Naber) <br />
6. 允许unbuffered的目录实现。（e.g.,using mmap）。 <br />
InputStream 被新类 IndexInput 替换， BufferedIndexInput 和 OutputStream 则被
IndexOutput 和 BufferedIndexOutput。 InputStream 和 OutputStream
已经被废弃了。FSDirectory 现在是一个子类了。(cutting) <br />
7. 增加了原生 Directory 和 TermDocs 的实现，可以工作在 GCJ 下。GCJ的版本需要 3.4.0 以上。可以使用 ant gcj 来运行例子程序。(cutting) <br />
8. 增加了 MmapDirectory 类，它使用 nio to mmap 输入文件。现在MmapDirectory
比FSDirectory 要慢些。但他对每个查询term 使用更少的内存。(cutting &amp; Paul Elschot) <br />
9. 增加 javadocs-internal 到 build.xml &#8211; bug #30360 <br />
10. 增加了 RangeFileter ,比 DateFilter 更加通用，实用。 <br />
(Chris M Hostetter via Erik) <br />
11. 增加了 NumberTools ，一个用来索引数字字段的工具类。   (adapted from code contributed by Matt Quail; committed by Erik) <br />
12. 增加了 public static IndexReader.main(String[] args) 方法。 <br />
IndexReader 现在可以直接在命令行方式下使用，用来 列出或者从现存的索引中抽取单独的文件出来。 <br />
(adapted from code contributed by Garrett Rooney; committed by Bernhard) <br />
13. 增加 IndexWriter.setTermIndexInterval() 方法。   (Doug Cutting) <br />
14. 增加 LucenePackage ,这些静态的 get() 方法返回 java.util.Package。调用者可以用它来获得 Lucene jar 中的版本信息。 <br />
(Doug Cutting via Otis) <br />
15. 增加 Hits.iterator() 方法和相应的 HitIterator 和 Hit 对象。他提供了对 Hits对象标准的 java.util.Iterator 叠代操作。 <br />
每个iterator's next() 方法返回一个 Hit 对象。   (Jeremy Rayner via Erik) <br />
16. 增加 ParallelReader，这个一种IndexReader 他合并多个单独的索引到一个单独的虚拟索引上。(Doug Cutting) <br />
17. 增加对 FieldCache 的 IntParser ， FloatParser 接口, 这样任何格式的字段可以被以int 和float的形式缓存。 <br />
(Doug Cutting) <br />
18. 新增类： org.apache.lucene.index.IndexModifier ，它合并了 IndexWriter 和
IndexReader，好处是我们可以增加和删除文档的时候不同担心 synchronisation/locking 的问题了。 (Daniel
Naber) <br />
19. Lucene 现在可以被用在一个没有签名的applet中了，Lucene&#8217;s 读取系统属性不会抛出 SecurityException 异常。 <br />
(Jon Schuster via Daniel Naber, bug #34359) <br />
20. 增加了新类 MatchAllDocsQuery 用来匹配所有文档。 <br />
(John Wang via Daniel Naber, bug #34946) <br />
21. 当索引太多的字段时，为了消减索引大小和内存消耗，提供了忽略规范化字段的功能。 <br />
见: Field.setOmitNorms()   (Yonik Seeley, LUCENE-448) <br />
22. 增加对 contrib/highlighter 的 NullFragmenter , 这对全文本加亮很有用。 <br />
(Erik Hatcher) <br />
23. 增加了正则表达式的查询： RegexQuery 和 SpanRegexQuery。 <br />
(Erik Hatcher) <br />
24. 增加 ConstantScoreQuery 类，它包装了一个 filter produces a score <br />
equal to the query boost for every matching document. <br />
(Yonik Seeley, LUCENE-383) <br />
25. 增加了 ConstantScoreRangeQuery 类，为某个区间的每个文档提供一个不变的 score。这个类比普通的
RangeQuery 类的好处是它并不展开到 BooleanQuery ，因此也不存在区间最大term上限。 (Yonik Seeley,
LUCENE-383) <br />
26. 为BooleanQuery增加了最小的匹配短语。见：BooleanQuery.setMinimumNumberShouldMatch(). <br />
(Paul Elschot, Chris Hostetter via Yonik Seeley, LUCENE-395) <br />
27. 增加了 DisjunctionMaxQuery 类，提供了针对某个短语的最大score。这一点对多字段的搜索非常有用。 <br />
(Luc Vanlerberghe via Yonik Seeley, LUCENE-323) <br />
28. 新增类：ISOLatin1AccentFilter ,用 ISO Latin 1 字符集中的unaccented类字符替代 accented 类字符。   (Sven Duzont via Erik Hatcher) <br />
29. 新增类：KeywordAnalyzer。"Tokenizes" 整个流作为一个单独的token。这个类对于 邮政编码，序列号，和产品名称等比较有用。 <br />
(Erik Hatcher) <br />
30. 把 LengthFilter 类从 contrib 放到了 core 代码里。从 stream 中去掉太长和太短的单词。   (David Spencer via Otis and Daniel) <br />
31. 增加了 getPositionIncrementGap 方法到 Analyzer 中。这样用户自定义的 analyzer
可以在相同字段名的实例之间增加间隙 gaps，用来防止 phrase 和 span 查询超出边界。默认的 gap 是 0 。 (Erik
Hatcher, with advice from Yonik) <br />
32. StopFilter 增加了对处理stop words 的忽略大小写处理。   (Grant Ingersoll via Yonik, LUCENE-248) <br />
33. 增加了 TopDocCollector 和 TopFieldDocCollector。用来简化实现hit 集合针对 top-scoring 和 top-sorting hits的处理。 <br />
API 的改变： <br />
1. 几个方法和字段已经被废弃。在API 文档中包含了建议替换的内容。在这些建议中，这些不建议使用的方法和字段将会在Lucene2.0中被删除。 <br />
(Daniel Naber) <br />
2. Russian 和 German 的 analyzers 被移到了 contrib/analyzers 。   <br />
同样 WordlistLoader 类也被放到了 org.apache.lucene.analysis.WordlistLoader 下   (Daniel Naber) <br />
3. API 包含抛出 IOException 异常的声明，但是实际上不会抛出。 These declarations have been removed. If <br />
your code tries to catch these exceptions you might need to remove <br />
those catch clauses to avoid compile errors.(Daniel Naber) <br />
4. 为BooleanClause 类的enum 标准参数增加序列化的参数类。   (Christoph) <br />
5. 为 SpanQuery 的子类嵌套其他SpanQuery 增加了 rewrite方法。 <br />
Lucene 的源代码管理器也从cvs 换到了svn：   <a href="http://svn.apache.org/repos/asf/lucene/java/trunk" target="_blank"><font color="#bc694c">http://svn.apache.org/repos/asf/lucene/java/trunk</font></a> <br />
参考资料：<a href="http://blog.csdn.net/accesine960/archive/2006/02/28/612622.aspx" target="_blank"><font color="#bc694c">http://blog.csdn.net/accesine960/archive/2006/02/28/612622.aspx</font></a> <br />
原文地址：<a href="http://svn.apache.org/viewcvs.cgi/*checkout*/lucene/java/branches/lucene_1_9/CHANGES.txt?rev=379190" target="_blank"><font color="#bc694c">http://svn.apache.org/viewcvs.cgi/*checkout*/lucene/java/branches/lucene_1_9/CHANGES.txt?rev=379190</font></a>
<img src ="http://www.blogjava.net/super2/aggbug/237282.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 09:41 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237282.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]lucene学习笔记一 记录开始</title><link>http://www.blogjava.net/super2/archive/2008/10/29/237276.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Wed, 29 Oct 2008 01:16:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/29/237276.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237276.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/29/237276.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237276.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237276.html</trackback:ping><description><![CDATA[这个东西在2006年初,我就开始在项目中使用.我对它也有了一些了解. 但因为主要开发还是小兵们在做. 所以仅仅了解了一些皮毛. 下面我将以知识点的形式, 列出来. 以笔记的形式连载. 也方便大家一起学习. 每一个点, 我都会写一个知识点. <br />
<br />
1, 2005年的时候, 听说了lucene. 是一个开源的搜索引擎开发包. 而不是一个搜索引擎,请切记. <br />
2, 如果开始学习它, 就需要至少知道,它所包含的包. 目前lucene已经到了2.2版本. 当然你需要时刻关注他的最新版本. 目前包:
lucene-core-2.2.0.jar . 下载可以到apache的网站上下载. 这一个就够了.不用下别的. <br />
3, 下面问题会接踵而至, 我挨着写,你挨着看即可. <br />
分词. 第一个要涉及的问题, 分词就是将一句话中的关键词汇分离出来, 然后才可以建立索引. 例如 中华人民共和国 --&gt; 中华,
中华人民 华人,人民, 共和国,等. lucene缺省带了一个标准分词的类: StandardAnalyzer 这个按字来分的.
从网上发现了很多程序员写的开源的分词的类.
当然都是继承了lucene的org.apache.lucene.analysis.Analyze类. 以实现更好更快的分词效果.
可以搜索获取更多, 一般分词的类,都提供了可检测分词效果的方法. 输入一个长句, 然后执行,看看分词效果和执行时间. <br />
<br />
4, ThesaurusAnalyzer是一个哥们开发的,网上有源码可以下载. 从这个源码里面对分词可以有更深入的了解:
包括那些是词汇,那些不是词汇. 都在文本文件里面以行分割开来. 由此可以知道: 分词是需要词库的. 因为词库可以不断的扩充
.但每次构造分词对象时,是建立在当前词库基础上的. 如果词库动态增加了新的词汇, 需要重新构建分词对象. 当然, 也可以读取数据库. <br />
<br />
5, 上面的分词, 也仅仅是分词! 网上有人提出的问题是: 索引中,加入了"东北大学". "北大" . 要搜索 北大 ,
显然我们没有找到东北大学的意思. 但最后还是找到了. 因为东北大学四个字里面有北大两个字. 分词时这个词被确认是个词, 就加入了索引.
这种情况, 涉及到汉语语义的问题 .暂时不好解决. 所以不提. <br />
<br />
选择较好的分析器 <br />
这个优化主要是对磁盘空间的优化，可以将索引文件减小将近一半，相同测试数据下由600M减少到380M。但是对时间并没有什么帮助，甚至会需要更长时
间，因为较好的分析器需要匹配词库，会消耗更多cpu，测试数据用StandardAnalyzer耗时133分钟；用MMAnalyzer耗时150分
钟。 <br />
<br />
<br />
6, 分词的缺失: 就似乎同义词. 为了减少用户搜索的次数, 增加搜索效果. 如果用户搜 "北京 饭店" 能不能把" 首都 饭店"也列出来呢.
这个分词器无能为力. 我也考虑到这个问题, 在北京托尔四公司的TRS的搜索产品文档中人家也考虑到了这个问题. 就似乎如果搜索 锐器,
系统会自动把匕首,尖刀等词汇一并加入搜索结果. 所以这个问题 ,就只能是在分词之前,我们再加一层:同义词返回模块. 这个思路很不错,
也比较简单. 很容易实现. 关键是词库的建立. 这个就说到这里. <br />
<br />
7, 说到这里,你可能想要做个例子来实践一下. 做个例子很容易. 网上很多. 我只做简单的叙述: lucene是用目录或者内存来存储数据的.
可以设定.
但是实践证明RAMDirectory和FSDirectory速度差不多，当数据量很小时两者都非常快，当数据量较大时（索引文件
400M）RAMDirectory甚至比FSDirectory还要慢一点，这确实让人出乎意料。 <br />
而且lucene的搜索非常耗内存，即使将400M的索引文件载入内存，在运行一段时间后都会out of memory，所以个人认为载入内存的作用并不大。 <br />
我们用目录: <br />
如下: <br />
//构建一个 IndexWriter 用来写如索引 <br />
File indexDir = new File( <br />
"E:""javasource""LuceneTest""index"); <br />
<br />
IndexWriter indexWriter = new IndexWriter(indexDir, <br />
new ThesaurusAnalyzer(), false); <br />
Document doc = Document(new Article("name"+i, "北京老张")); <br />
indexWriter.addDocument(doc); <br />
indexWrite.close(); <br />
<br />
由上可以看出, lucene将在这个目录下进行操作. 上面代码中的你不要抄袭当例子, 因为还有一个Article类和Document方法.里面也有一些东西. 现在仅仅先理解上面的意思即可. 操作前,你可能不知道他会在目录里干什么. <br />
<br />
8, 目录下的东西 . 如果测试成功, 目录下有三个文件. <br />
segments.gen segments_a08, 还有一个类似 _uw.cfs名字的东西. 当然,不一定都一样, 但肯定是这三个. 如果出现了很多文件.不要着急, 看下面的 9 . <br />
<br />
9, 如果lucene的索引目录下出现了很多文件, 肯定是有问题的. 几个方面.首先lucene在执行写操作时,
会先在目录下写如一个write.lock的文件锁定这个目录,以避免别的索引再操作这个路径. 否则那样肯定会乱. 锁定之后, 开始写索引,
写索引时lucene建了几个或者几十个临时片段文件, 都似乎又短又乱的字符.cfs的文件. 当索引建立完毕后,没有执行
indexWriter.optimize();方法, 他就不会合并那些乱七八糟的文件. 所以,索引建完后, 一定要执行 上面的优化方法,
保持目录下保留3个文件即可. 也就是很多临时文件会合并到一个文件中去. 切不可大意删除. 但当数据很多时, 另行考虑策略. <br />
<br />
10, lucene在写入索引时, 用在索引目录下建write.lock文件来标识锁定. 而只有在执行close()方法后, 才会删除这个锁文件. 只要这个文件存在, 其他的写索引的程序都会报错: <br />
caught a class org.apache.lucene.store.LockObtainFailedException <br />
with message: Lock obtain timed out: SimpleFSLock@E:"javasource"LuceneTest"index"write.lock <br />
<br />
所以,需要注意, 一定要注意关闭indexWrite. 包括异常下,用finally关闭.否则会导致下一次写索引失败. <br />
<br />
11, 批量增加索引, 如果要成批的用循环加入索引,该怎么办呢. 首先请注意: IndexWriter indexWriter = new IndexWriter(indexDir, <br />
new ThesaurusAnalyzer(), false); 最后一个参数为false表示持续想索引增加数据. 如果为true, 则每次会删除全部, 重新开始. <br />
<br />
12, 在批量增加索引时, 程序可以一直执行 <br />
indexWriter.addDocument(doc); 但不能一直执行优化:indexWriter.optimize();
因为优化方法比较耗时, 特别是当索引很大时, 更要注意. 因为优化, 也仅仅似乎优化会消耗很多时间和cpu.
所以这个时候.多几个文件也没关系. 网上有个人问了这样的问题, 我摘录如下, 用等号分割开我的内容: <br />
引自: <br />
<a href="http://www.javaeye.com/topic/107818?page=3" target="_blank"><font color="#bc694c">http://www.javaeye.com/topic/107818?page=3</font></a> <br />
================================================ <br />
我不知道是不是理解错了增量索引的概念 <br />
我搜索的网页不会重复,不是对所有的网页都不停的搜,而是我搜索特定的网站.这里面不会出现重复现象.每次爬到的网页肯定是index里没有的 <br />
<br />
问一个问题 <br />
如果有10个网页需要建立index <br />
是 <br />
IndexWriter iw=new IndexWriter(...); <br />
for(int i=0;i&lt;10;i++){ <br />
iw.addDocuemnt(doc<em>); <br />
} <br />
iw.close(); <br />
<br />
还是 <br />
for(int i=0;i&lt;10;i++){ <br />
IndexWriter iw=new IndexWriter(...); <br />
iw.addDocuemnt(doc); <br />
iw.close(); <br />
} <br />
<br />
还有，如果index量有10G，做一次optimize需要多长时间？ <br />
建议多长时间Optimize一次？ <br />
对一个刚刚做过Optimize的index目录做Optimize，会不会很快就结束，还是也需要很长时间？ <br />
optimize结束后是不是只剩下3个文件？如果有其他文件，是不是意味着有问题呢？（没有Reader或者Searcher在使用这个index的时候） <br />
<br />
<br />
<br />
返回顶端 最后更新: 2007-08-10 11:02 (0) (0) 正在投票中... <br />
<br />
<br />
amigobot 等级: 初级会员 <br />
<br />
文章: 28 <br />
积分: 14 <br />
<br />
时间: 2007-08-12 14:15 引用 收藏 <br />
<br />
-------------------------------------------------------------------------------- <br />
<br />
没有必要6分钟一次。 每次optimize都会重新做索引， 光拷贝10G文件就得多少分钟？如果不是频繁删除的话， 一天， 甚至一礼拜一趟都可以。 选择系统负载少的时候就行。 <br />
<br />
<br />
<br />
返回顶端 最后更新: 2007-08-12 14:15 (0) (0) 正在投票中... <br />
<br />
<br />
licco1 等级: 初级会员 <br />
<br />
文章: 22 <br />
积分: 0 <br />
<br />
时间: 2007-09-06 09:43 引用 收藏 <br />
<br />
-------------------------------------------------------------------------------- <br />
<br />
1:当search动作太频繁,或者访问的人很多,在optimize时会出现这个message <br />
java.io.IOException: Cannot delete E:"index"_nir.f2; <br />
注意检查下是不是每次查询完都把indexReader给close了。你可以测试下，频繁的开search，如果还有这个异常，估计就是没把
indexReader给close（千万不要以为close the indexSearcher
就ok了，要注意新建indexSearcher时传的参数是什么，是Direcitory,还是indexReader，还是字符串文件路径，这影响是
否close indexReader） <br />
<br />
<br />
<br />
返回顶端 最后更新: 2007-09-06 09:43 (0) (0) 正在投票中... <br />
<br />
<br />
fool_leave 等级: 初级会员 <br />
<br />
性别: <br />
文章: 21 <br />
积分: 0 <br />
来自: 上海 <br />
<br />
时间: 2007-09-07 09:44 引用 收藏 <br />
<br />
-------------------------------------------------------------------------------- <br />
<br />
新建indexReader时传入的是index file path，而且在search完毕后都在finally里面做了close动作。 <br />
<br />
BTW：我把optimize动作去掉后，也就是说无论它运行多久都不让他optimze，结果index很正常，文件数量不会增加很多，search也okay。 <br />
<br />
问题是总不能老这样呀，一直不optimize也不行呀。我做一次optimize，就要n分钟，index文件太大，没办法。 <br />
<br />
而且我的index动作是针对不同的网页，比如<a href="http://xxx.xxx.xxx/1.html" target="_blank"><font color="#bc694c">http://xxx.xxx.xxx/1.html</font></a>被index后，以后遇到这个页面就不会再做index动作。换句话说，每次index的内容都是新的，不会覆盖以前的东西。这样的需求是不是不用optimize呀。 <br />
<br />
<br />
<br />
返回顶端 最后更新: 2007-09-07 09:44 (0) (0) 正在投票中... <br />
<br />
<br />
licco1 等级: 初级会员 <br />
<br />
文章: 22 <br />
积分: 0 <br />
<br />
时间: 2007-09-07 10:09 引用 收藏 <br />
<br />
-------------------------------------------------------------------------------- <br />
<br />
fool_leave，你用的lucene版本是多少？如果是2.2的话，可以用indexwriter；以前用2.0，我用indexReader执行
删除操作也出现过类似的情况（怀疑是indexreader只将被删除的documents设置了下删除的标志，在close的时候没真正执行删除动作，
也许是我少执行了一个步骤，=会去看看reader的删除操作）。如果因为文件太大导致优化(optimze，它的作用是重新整理段，把document
的id重新设置，这个对搜索效率很有帮助，和document里term的内容没关系)的时间很长，那就得重新考虑下你的架构了(10g太大了)。这个得
请教下imjl. <br />
<br />
<br />
<br />
返回顶端 最后更新: 2007-09-07 10:12 (0) (0) 正在投票中... <br />
<br />
<br />
dwangel 等级: <br />
<br />
文章: 500 <br />
积分: 650 <br />
圈子: TODOtree-ruby <br />
<br />
时间: 2007-09-07 12:38 引用 收藏 <br />
<br />
-------------------------------------------------------------------------------- <br />
<br />
建议设置时间任务，凌晨2点启动indexWriter进行optimise。 <br />
启动前前台页面切换到显示维护的状态，然后等待所有的reader,searcher关闭，然后进行optimise。（当然只有一个writer在跑） <br />
<br />
In environments with frequent updates, optimize is best done during low volume times, if at all. <br />
摘自lucene的文档 <br />
<a href="http://lucene.zones.apache.org:8080/hudson/job/Lucene-Nightly/javadoc/org/apache/lucene/index/IndexWriter.html#optimize" target="_blank"><font color="#bc694c">http://lucene.zones.apache.org:8080/hudson/job/Lucene-Nightly/javadoc/org/apache/lucene/index/IndexWriter.html#optimize</font></a>() <br />
<br />
It is best not to re-open readers while optimize is running. <br />
这句话我不是很明白，我觉得应该是说不要在optimize运行时打开新的reader。但是用的re-open，难道是说 <br />
不要在optimize时，重置reader。的状态？ <br />
<br />
<br />
<br />
返回顶端 最后更新: 2007-09-07 12:48 (0) (0) 正在投票中... <br />
<br />
<br />
licco1 等级: 初级会员 <br />
<br />
文章: 22 <br />
积分: 0 <br />
<br />
时间: 2007-09-07 17:29 引用 收藏 <br />
<br />
-------------------------------------------------------------------------------- <br />
<br />
因为if some but not all readers re-open while the optimize is underway,
this will cause &gt; 2X temporary space to be consumed as those new
readers will then hold open the partially optimized segments at that
time.所以It is best not to re-open readers while optimize is
running.在进行优化的时候最好不要新开readers(2.2里好像没有reopen这个方法吧，2.3里估计会出)，因为新的readers同
时会打开部分优化过的段，索引耗损的临时空间会大于两倍索引大小(翻译错了楼下的一定要指出来哦)。 <br />
<br />
我觉得在做优化时，不会对searcher有影响，不必关闭搜索功能。 <br />
<br />
<br />
<br />
返回顶端 最后更新: 2007-09-07 17:31 (0) (0) 正在投票中... <br />
<br />
<br />
fool_leave 等级: 初级会员 <br />
<br />
性别: <br />
文章: 21 <br />
积分: 0 <br />
来自: 上海 <br />
<br />
时间: 2007-09-10 09:56 引用 收藏 <br />
<br />
-------------------------------------------------------------------------------- <br />
<br />
thanks <br />
无论是不是reopen,optimize都会耗用更多的space来存储临时文件.但这些都是临时文件,在动作结束后会被释放掉.所以如果硬盘空间足够，这些多余的耗用应该不是大问题。 <br />
<br />
但我的index目录总共有3G（我把旧的document删除了）。不过每次optimize一样要花费很长时间。我不知道应该如何重新设置document的id.我的lucene version是2.0的。 <br />
<br />
lucene的optimize的结果除了将index的文件数变成3个，还有什么好处呢？到现在我看来只有在delete索引节点后有必要通过
optimize真正的把这些节点删除，其他的优势似乎非常不明显。（因为我每次写入index的索引内容都是新的，不会有重复或追加现象）。我现在彻底
把optimize从程序里去掉了，运行到现在已经1个月了，每分钟都有新内容加进去，但index目录依然很正常，文件数24个，从文件的修改时间上来
看也很正常。search动作也很正常。 <br />
<br />
如果一次optimize需要花费5分钟以上的时间，而这个操作又是不可中断的，一旦在optimize过程中终止了程序，就会出现lucene自身无法恢复问题。这样对于程序要求太高了。对于服务器管理也要求太高了。 <br />
<br />
========================================= <br />
</em>上面的内容有些多, 不过也对大家有益. 他说最后他把执行优化的代码去掉了,运行很好. 对于大数据量的来说, 这是个经验. 除非采用冗余的机制, 而不能对正在使用的数据进行优化操作. 会造成用户访问阻塞. <br />
<br />
由上面可见的, 我就不说了. <br />
13,
索引过程中的任意时刻、任意进程都能对索引文件进行优化，而且这样做也不会损坏索引文件或使其不能被搜索，但是在索引过程中对索引进行优化的做法并不值得
提倡。优化操作的最佳时机是在索引过程结束之后，且当你确认在此后的一段时间内不会对索引文件进行更改的时候。在索引过程中进行优化只会使优化操作耗费更
多的时间。(请大家汲取这个思想) <br />
<br />
<br />
<br />
14, 还是优化, 些人问: 我用lucene做了一个Search Engine <br />
程序运行也很正常，但如果连续运行几个月，有时会出现磁盘空间不足的情况 . <br />
通过iw.addDocument(doc)写入index <br />
当list里的东西全部被写入完毕后，通过optimze来优化索引, <br />
可这个东西运行不是很稳定，有的时候很正常，运行几个月都okay，有时1个月就出现问题了。会在index的目录里出现很多文件。这些文件似乎是应该被
optimize掉的。 一个索引只能有一个indexreader, 在optimize的时候可以有多个indexsearcher在工作。 <br />
你得确保 <br />
--&gt;optimize确实调用了 <br />
--&gt;optimize的时候， 得有双倍的磁盘空间. 可见优化的代价. <br />
<br />
<br />
<br />
15 ,面的lucene都是在一个目录里面的, 大家也都看到了. 也就是如果这个文件一直很大怎么办. 首先碰到的第一个问题是就是文件大小限制. 首先面临的是一个大目录问题. <br />
<br />
16, lucene的性能测试: <br />
下面给出一些测试数据，如果你觉得可以接受，那么可以选择。 <br />
测试一：250万记录，300M左右文本，生成索引380M左右，800线程下平均处理时间300ms。 <br />
测试二：37000记录，索引数据库中的两个varchar字段，索引文件2.6M，800线程下平均处理时间1.5ms。 <br />
<br />
<br />
17 . 分布搜索 <br />
<br />
我们可以使用 MultiReader 或 MultiSearcher 搜索多个索引库。 <br />
<br />
MultiReader reader = new MultiReader(new IndexReader[] {
IndexReader.Open(@"c:"index"), IndexReader.Open(@"""server"index") }); <br />
IndexSearcher searcher = new IndexSearcher(reader); <br />
Hits hits = searcher.Search(query); <br />
<br />
或 <br />
<br />
IndexSearcher searcher1 = new IndexSearcher(reader1); <br />
IndexSearcher searcher2 = new IndexSearcher(reader2); <br />
MultiSearcher searcher = new MultiSearcher(new Searchable[] { searcher1, searcher2 }); <br />
Hits hits = searcher.Search(query); <br />
<br />
还可以使用 ParallelMultiSearcher 进行多线程并行搜索。 <br />
<br />
18. 合并索引库 <br />
<br />
将 directory1 合并到 directory2 中。 <br />
Directory directory1 = FSDirectory.GetDirectory("index1", false); <br />
Directory directory2 = FSDirectory.GetDirectory("index2", false); <br />
<br />
IndexWriter writer = new IndexWriter(directory2, analyzer, false); <br />
writer.AddIndexes(new Directory[] { directory }); <br />
Console.WriteLine(writer.DocCount()); <br />
writer.Close(); <br />
<br />
19. 显示搜索语法字符串 <br />
<br />
我们组合了很多种搜索条件，或许想看看与其对等的搜索语法串是什么样的。 <br />
BooleanQuery query = new BooleanQuery(); <br />
query.Add(query1, true, false); <br />
query.Add(query2, true, false); <br />
//... <br />
<br />
Console.WriteLine("Syntax: {0}", query.ToString()); <br />
<br />
输出： <br />
Syntax: +(name:name* value:name*) +number:[0000000000000000b TO 0000000000000000d] <br />
<br />
呵呵，就这么简单。 <br />
<br />
20. 操作索引库 <br />
<br />
删除 (软删除，仅添加了删除标记。调用 IndexWriter.Optimize() 后真正删除。) <br />
IndexReader reader = IndexReader.Open(directory); <br />
<br />
// 删除指定序号(DocId)的 Document。 <br />
reader.Delete(123); <br />
<br />
// 删除包含指定 Term 的 Document。 <br />
reader.Delete(new Term(FieldValue, "Hello")); <br />
<br />
// 恢复软删除。 <br />
reader.UndeleteAll(); <br />
<br />
reader.Close(); <br />
<br />
增量更新 (只需将 create 参数设为 false，即可往现有索引库添加新数据。) <br />
Directory directory = FSDirectory.GetDirectory("index", false); <br />
IndexWriter writer = new IndexWriter(directory, analyzer, false); <br />
writer.AddDocument(doc1); <br />
writer.AddDocument(doc2); <br />
writer.Optimize(); <br />
writer.Close(); <br />
<br />
21. 优化 <br />
<br />
批量向 FSDirectory 增加索引时，增大合并因子(mergeFactor )和最小文档合并数(minMergeDocs)有助于提高性能，减少索引时间。 <br />
<br />
IndexWriter writer = new IndexWriter(directory, analyzer, true); <br />
<br />
writer.maxFieldLength = 1000; // 字段最大长度 <br />
writer.mergeFactor = 1000; <br />
writer.minMergeDocs = 1000; <br />
<br />
for (int i = 0; i &lt; 10000; i++) <br />
{ <br />
// Add Documentes... <br />
} <br />
<br />
writer.Optimize(); <br />
writer.Close(); <br />
<br />
相关参数说明 <br />
<br />
<br />
转自《深入 Lucene 索引机制》 <br />
<br />
利用
Lucene，在创建索引的工程中你可以充分利用机器的硬件资源来提高索引的效率。当你需要索引大量的文件时，你会注意到索引过程的瓶颈是在往磁盘上写索
引文件的过程中。为了解决这个问题, Lucene 在内存中持有一块缓冲区。但我们如何控制 Lucene 的缓冲区呢？幸运的是，Lucene
的类 IndexWriter 提供了三个参数用来调整缓冲区的大小以及往磁盘上写索引文件的频率。 <br />
<br />
22．合并因子 (mergeFactor) <br />
<br />
这个参数决定了在 Lucene 的一个索引块中可以存放多少文档以及把磁盘上的索引块合并成一个大的索引块的频率。比如，如果合并因子的值是
10，那么当内存中的文档数达到 10 的时候所有的文档都必须写到磁盘上的一个新的索引块中。并且，如果磁盘上的索引块的隔数达到 10 的话，这
10 个索引块会被合并成一个新的索引块。这个参数的默认值是
10，如果需要索引的文档数非常多的话这个值将是非常不合适的。对批处理的索引来讲，为这个参数赋一个比较大的值会得到比较好的索引效果。 <br />
<br />
23．最小合并文档数 (minMergeDocs) <br />
<br />
这个参数也会影响索引的性能。它决定了内存中的文档数至少达到多少才能将它们写回磁盘。这个参数的默认值是10，如果你有足够的内存，那么将这个值尽量设的比较大一些将会显著的提高索引性能。 <br />
<br />
24．最大合并文档数 (maxMergeDocs) <br />
<br />
这个参数决定了一个索引块中的最大的文档数。它的默认值是 Integer.MAX_VALUE，将这个参数设置为比较大的值可以提高索引效率和检索速度，由于该参数的默认值是整型的最大值，所以我们一般不需要改动这个参数。 <br />
<br />
25 , 根据官方文档:从中可以分析出，如果在optimize索引的时候，也同时使用Searcher。索引空间的使用情况如下： <br />
1. 原始索引 <br />
2. 由IndexWriter使用的索引，用于optimize <br />
3. 由IndexSearcher使用的索引，用于搜索。 <br />
<br />
所以要三倍的正常空间. <br />
<br />
为什么需要优化？ <br />
尽管未经优化的索引在大多数应用程序中都能够很好地进行工作，但在那些处理大批量索引的应用程序中，使用优化过的索引会给应用程序带来更多的好处。特别是
在搜索操作需要长时间打开多个索引文件的情况下，更能体现出索引被优化后的优势，因为使用优化过的索引可以减少需要打开的文件描述符的个数 <br />
<br />
优化所需的磁盘空间 <br />
值得指出的是，Lucene对一个索引的优化操作是通过把已存在的段合并成一个全新的段来完成的，这些已存在段的内容最终会在新的段中表示出来。因而在进
行优化时，使用的磁盘空间会有明显的增加。在新段创建完成时，Lucene删除并移除这些旧段。因此，在旧的段还没有被删除之前，索引占用的磁盘空间会变
成原来的两倍，因为此时新段和旧段都会存储在索引中。在优化完成后，所占用的磁盘空间会降回到优化前的状态。请记住，索引优化的对象可以是多文件索引或复
合索引。 <br />
<br />
<br />
<br />
26 , 索引文件有大小限制吗？(翻译) <br />
<br />
某些 32 位操作系统限制每个文件不能大于 2GB。 <br />
<br />
解决方法： <br />
1. 使用 IndexWriter.setMaxMergeDocs() 减小 MaxMergeDocs 数值。 <br />
2. 使用多个索引库。使用复合索引. <br />
<br />
<br />
27, IndexWriter.SetUseCompoundFile(true) 有什么用？ <br />
<br />
在创建索引库时，会合并多个 Segments 文件到一个 .cfs 中。此方式有助于减少索引文件数量，减少同时打开的文件数量。原因： <br />
某些操作系统会限制同时打开的文件数量。 <br />
<br />
解决方法： <br />
1. 使用 IndexWriter's setUseCompoundFile(true) 创建复合文件，减少索引文件数量。 <br />
2. 不要将 IndexWriter's mergeFactor 的值设置过大。尽管这能加快索引速度，但会增加同时打开的文件数量。 <br />
3. 如果在搜索时发生该错误，那么你最好调用 IndexWriter.Optimize() 优化你的索引库。 <br />
4. 确认你仅创建了一个 IndexSearcher 实例，并且在所有的搜索线程中共用。(原文："Make sure you only
open one IndexSearcher, and share it among all of the threads that are
doing searches -- this is safe, and it will minimize the number of
files that are open concurently. " 晕~~~，究竟要怎么做？ ) <br />
<br />
28, 为什么搜索不到结果？(翻译) <br />
<br />
可能原因： <br />
. 搜索字段没有被索引。 <br />
. 索引库中的字段没有分词存储，无法和搜索词语进行局部匹配。 <br />
. 搜索字段不存在。 <br />
. 搜索字段名错误，注意字段名称区分大小写。建议对字段名进行常量定义。 <br />
. 要搜索的词语是忽略词(StopWords)。 <br />
. 索引(IndexWriter)和搜索(IndexSearcher)所使用的 Analyzer 不同。 <br />
. 你所使用的 Analyzer 区分大小写。比如它使用了 LowerCaseFilter，而你输入的查询词和目标大小写不同。 <br />
. 你索引的文档(Document)太大。Lucene 为避免造成内存不足(OutOfMemory)，缺省仅索引前10000个词语(Term)。可以使用 IndexWriter.setMaxFieldLength() 调整。 <br />
. 确认在搜索前，目标文档已经被添加到索引库。 <br />
. 如果你使用了 QueryParser，它可能并没有按照你所设想的去分析 BooleanQuerySyntax。 <br />
<br />
如果还不行，那么： <br />
<br />
. 使用 Query.ToString() 查看究竟搜索了些什么。 <br />
. 使用 Luke 看看你的索引库究竟有什么。 <br />
<br />
29, 上面的luke是查看索引库的, 我下载了一个版本, 居然总提示我给他的索引路径不对.无奈. . <br />
<br />
30 , <br />
<br />
QueryParser 是线程安全的吗？ <br />
<br />
不是。 <br />
<br />
31, 说说分布式数据存储. 支持lucene的分布式搜索就是 hadoop. 这个也是apache下的属于lucene的开源项目.
但目前的我看只支持linux的分布机器. 网上很多这个方面的. 据说开发hadoop的人已经去了yahoo.
让hadoop支撑雅虎的分布式搜索. 所以按说功能强大.2006年的一月份Nutch和Lucene的缔造者Doug
Cutting加入了Yahoo公司，从那时起，Yahoo就开始进行Hadoop的部署与研究. 但网上有人说, 这个分布式效率不高. <br />
<br />
参数如下: <br />
<br />
经测试，Hadoop并不是万用灵丹，很取决于文件的大小和数量，处理的复杂度以及群集机器的数量，相连的带宽，当以上四者并不大时，hadoop优势并不明显。 <br />
比如，不用hadoop用java写的简单grep函数处理100M的log文件只要4秒，用了hadoop local的方式运行是14秒，用了hadoop单机集群的方式是30秒，用双机集群10M网口的话更慢，慢到不好意思说出来的地步。 <br />
<br />
评: 怎么评价上面的哥们测试结果呢. 但愿他说的不对. 因为如果这样, yahoo不就死了.. <br />
<br />
32, MaxDoc() 和 DocCount()、NumDocs() 有什么不同？ <br />
<br />
MaxDocs() 表示索引库中最大的 Document ID 号，由于中间的某些 Document 可能被删除，因此不能使用
MaxDocs() 来表示 Document
数量。IndexWriter.DocCount()、IndexReader.NumDocs()、
IndexSearcher.Reader.NumDocs() 都表示索引库中 Document 数量。 <br />
<br />
33, 为什么同时进行搜索和更新会引发 FileNotFoundException 异常？(翻译) <br />
<br />
可能原因： <br />
1. 某个搜索或更新对象禁用了锁。 <br />
2. 搜索和更新使用了不同的 lockDir。 <br />
3. 索引库被存放在 NFS (or Samba) 文件系统上。 <br />
<br />
尽管搜索是只读操作，但 IndexSeacher 为了获取索引文件列表，也必须打开时锁定索引库。如果锁没有正确设置，那么它将取回一个错误的文件列表(此时 IndexWriter 可能正在添加或优化索引)，从而导致该异常发生。 <br />
<br />
34, write.lock 有什么用？哪些类会用到它？(翻译) <br />
<br />
write.lock 用来协调索引库的并发修改处理。 <br />
当 IndexWriter 打开索引库，或者 IndexReader 删除文档时都将创建该锁。 <br />
<br />
35. commit.lock 文件有什么用？哪些类会用到它？(翻译) <br />
<br />
commit.lock 在调整索引库 segments 文件内容时使用。 IndexReader 和 IndexWriter 都会使用到它。 <br />
<br />
36, 如何更新已经索引的文档？ (翻译) <br />
<br />
你只能先删除，然后添加更新后的文档。 <br />
<br />
使用 IndexWriter.addIndexes(IndexReader[]) 和 IndexWriter.addIndexes(Directory[]) 合并索引库有什么不同？ (翻译) <br />
<br />
使用 Directory[] 参数所需的文件句柄和内存较小，索引文件仅需打开一次，而使用 IndexReader[] 参数则需要打开所有的索引库。
<img src ="http://www.blogjava.net/super2/aggbug/237276.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-29 09:16 <a href="http://www.blogjava.net/super2/archive/2008/10/29/237276.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《Lucene in action》中推荐的Lucene分页方式</title><link>http://www.blogjava.net/super2/archive/2008/10/28/237109.html</link><dc:creator>淘声依旧</dc:creator><author>淘声依旧</author><pubDate>Tue, 28 Oct 2008 06:36:00 GMT</pubDate><guid>http://www.blogjava.net/super2/archive/2008/10/28/237109.html</guid><wfw:comment>http://www.blogjava.net/super2/comments/237109.html</wfw:comment><comments>http://www.blogjava.net/super2/archive/2008/10/28/237109.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/super2/comments/commentRss/237109.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/super2/services/trackbacks/237109.html</trackback:ping><description><![CDATA[<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);">&nbsp;List&nbsp;processHits(Hits&nbsp;hits,</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;startIndex,</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;endIndex)</span><span style="color: rgb(0, 0, 255);">throws</span><span style="color: rgb(0, 0, 0);">&nbsp;Exception{<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(endIndex</span><span style="color: rgb(0, 0, 0);">&gt;=</span><span style="color: rgb(0, 0, 0);">hits.length())<br />
&nbsp;&nbsp;&nbsp;endIndex</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">hits.length()</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">;<br />
&nbsp;&nbsp;List&nbsp;docs</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;ArrayList();<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">&nbsp;i</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">startIndex;i</span><span style="color: rgb(0, 0, 0);">&lt;=</span><span style="color: rgb(0, 0, 0);">endIndex;i</span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">){<br />
&nbsp;&nbsp;&nbsp;Document&nbsp;doc</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">hits.doc(i);<br />
&nbsp;&nbsp;&nbsp;Map&nbsp;docMap</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;HashMap();<br />
&nbsp;&nbsp;&nbsp;docMap.put(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">id</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,doc.getField(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">id</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).stringValue());<br />
&nbsp;&nbsp;&nbsp;docMap.put(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">name</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,doc.getField(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">name</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).stringValue());<br />
&nbsp;&nbsp;&nbsp;docMap.put(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">price</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">,doc.getField(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">price</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">).stringValue());<br />
&nbsp;&nbsp;&nbsp;docs.add(docMap);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;docs;<br />
&nbsp;}<br />
<br />
</span></div>
<img src ="http://www.blogjava.net/super2/aggbug/237109.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/super2/" target="_blank">淘声依旧</a> 2008-10-28 14:36 <a href="http://www.blogjava.net/super2/archive/2008/10/28/237109.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>