??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲精品自在在线观看,亚洲婷婷在线视频,亚洲中文字幕久久精品无码Ahttp://www.tkk7.com/szhswl/category/27889.html宋针q的个hI间zh-cnThu, 20 Dec 2007 16:42:34 GMTThu, 20 Dec 2007 16:42:34 GMT60LUCENE学习W记3(转蝲)http://www.tkk7.com/szhswl/articles/168305.html宋针q?/dc:creator>宋针q?/author>Mon, 17 Dec 2007 11:36:00 GMThttp://www.tkk7.com/szhswl/articles/168305.htmlhttp://www.tkk7.com/szhswl/comments/168305.htmlhttp://www.tkk7.com/szhswl/articles/168305.html#Feedback0http://www.tkk7.com/szhswl/comments/commentRss/168305.htmlhttp://www.tkk7.com/szhswl/services/trackbacks/168305.html 在创建烦引的时候,可以同时创徏多个IndexWriterQ将一个DocumentҎ需要拆分成多个包含部分Field的DocumentQƈ这些Document分别dC同的索引?
而在搜烦Ӟ则必d助ParallelReadercL整合?
Directory dir1=FSDirectory.getDirectory(new File(INDEX_DIR1),false);
Directory dir2=FSDirectory.getDirectory(new File(INDEX_DIR2),false);
ParallelReader preader=new ParallelReader();
preader.add(IndexReader.open(dir1));
preader.add(IndexReader.open(dir2));

IndexSearcher searcher=new IndexSearcher(preader);
之后的操作和一般的搜烦相同?

2, Query的子c? 下面的几个搜索在各种不同要求的场?都会用到. 需要大家仔l研?

Query query1 = new TermQuery(new Term(FieldValue, "name1")); // 词语搜烦
Query query2 = new WildcardQuery(new Term(FieldName, "name*")); // 通配W?
Query query3 = new PrefixQuery(new Term(FieldName, "name1")); // 字段搜烦 Field:KeywordQ自动在l尾d *
Query query4 = new RangeQuery(new Term(FieldNumber, NumberTools.LongToString(11L)), new Term(FieldNumber, NumberTools.LongToString(13L)), true); // 范围搜烦
Query query5 = new FilteredQuery(query, filter); // 带过滤条件的搜烦
Query query6 =new MatchAllDocsQuery(... // 用来匚w所有文?
Query query7 = new FuzzyQuery (...模糊搜烦
Query query8 = new RegexQuery (..   正则搜烦
Query query9 = new SpanRegexQuery(...)?同上, 正则表达式的查询Q?
Query query9 = new SpanQuery 的子cd套其他SpanQuery 增加?rewriteҎ
Query query10 =new DisjunctionMaxQuery () ..c,提供了针Ҏ个短语的最大score。这一点对多字D늚搜烦非常有用
Query query11 = new ConstantScoreQuery cd包装了一?filter produces a score
equal to the query boost for every matching document.

BooleanQuery query12= new BooleanQuery();
booleanQuery.add(termQuery 1, BooleanClause.Occur.SHOULD);
booleanQuery.add(termQuery 2, BooleanClause.Occur.SHOULD);
  //q个是ؓ了联合多个查询而做的Queryc? BooleanQuery增加了最的匚w短语。见QBooleanQuery.setMinimumNumberShouldMatch().


PhraseQuery
你可能对中日关系比较感兴,x?#8216;?#8217;?#8216;?#8217;挨得比较q(5个字的距dQ的文章Q超q这个距ȝ不予考虑Q你可以Q?

PhraseQuery query 13= new PhraseQuery();
query.setSlop(5);
query.add(new Term("content ", “?#8221;));
query.add(new Term(“content”, “?#8221;));

PhraseQuery对于短语的顺序是不管?q点在查询时除了提高命中率外,也会Ҏ能产生很大的媄? 利用SpanNearQuery可以对短语的序q行控制,提高性能

BooleanQuery query12=   new SpanNearQuery 可以对短语的序q行控制,提高性能

3, 索引文本文g
如果你想把纯文本文g索引hQ而不惌己将它们d字符串创建fieldQ你可以用下面的代码创徏fieldQ?

Field field = new Field("content", new FileReader(file));

q里的file是该文本文件。该构造函数实际上是读L件内容,q对其进行烦引,但不存储


4, 如何删除索引
lucene提供了两U从索引中删除document的方法,一U是

void deleteDocument(int docNum)

q种Ҏ是根据document在烦引中的编h删除Q每个document加进索引后都会有个唯一~号Q所以根据编号删除是一U精删除,但是q个~号是烦引的内部l构Q一般我们不会知道某个文件的~号到底是几Q所以用处不大。另一U是

void deleteDocuments(Term term)

q种Ҏ实际上是首先Ҏ参数term执行一个搜索操作,然后把搜索到的结果批量删除了。我们可以通过q个Ҏ提供一个严格的查询条gQ达到删除指定document的目的?
下面l出一个例子:

Directory dir = FSDirectory.getDirectory(PATH, false);
IndexReader reader = IndexReader.open(dir);
Term term = new Term(field, key);
reader.deleteDocuments(term);
reader.close();



5, 如何更新索引
luceneq没有提供专门的索引更新ҎQ我们需要先相应的document删除Q然后再新的document加入索引。例如:

Directory dir = FSDirectory.getDirectory(PATH, false);
IndexReader reader = IndexReader.open(dir);
Term term = new Term(“title”, “lucene introduction”);
reader.deleteDocuments(term);
reader.close();

IndexWriter writer = new IndexWriter(dir, new StandardAnalyzer(), true);
Document doc = new Document();
doc.add(new Field("title", "lucene introduction", Field.Store.YES, Field.Index.TOKENIZED));
doc.add(new Field("content", "lucene is funny", Field.Store.YES, Field.Index.TOKENIZED));
writer.addDocument(doc);
writer.optimize();
writer.close();


但是?.9RC1中说?
新增c: org.apache.lucene.index.IndexModifier Q它合ƈ?  IndexWriter ?IndexReaderQ好处是我们可以增加和删除文档的时候不同担?synchronisation/locking 的问题了? 

6, filerc?使用 Filter Ҏ索结果进行过滤,可以获得更小范围内更_的结果?有h? 注意它执行的是预处理Q而不是对查询l果q行qoQ所以用filter的代h很大的,它可能会使一ơ查询耗时提高一癑ր?


ISOLatin1AccentFilter ,?ISO Latin 1 字符集中的unaccentedcdW替?accented cdW?
DateFilter   日期qo?
RangeFileter ,?DateFilter 更加通用Q实?
LengthFilter c? 已经?contrib 攑ֈ?core 代码里。从 stream 中去掉太长和太短的单?  StopFilter c? 增加了对处理stop words 的忽略大写处理


7,本条是一个用过滤的说明:

qo

使用 Filter Ҏ索结果进行过滤,可以获得更小范围内更_的结果?

举个例子Q我们搜索上架时间在 2005-10-1 ?2005-10-30 之间的商品?
对于日期旉Q我们需要{换一下才能添加到索引库,同时q必L索引字段?
// index
document.Add(FieldDate, DateField.DateToString(date), Field.Store.YES, Field.Index.UN_TOKENIZED);

//...

// search
Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-1"), DateTime.Parse("2005-10-30"));
Hits hits = searcher.Search(query, filter);

除了日期旉Q还可以使用整数。比如搜索h格在 100 ~ 200 之间的商品?
Lucene.Net NumberTools 对于数字q行了补位处理,如果需要用QҎ可以自己参考源码进行?
// index
document.Add(new Field(FieldNumber, NumberTools.LongToString((long)price), Field.Store.YES, Field.Index.UN_TOKENIZED));

//...

// search
Filter filter = new RangeFilter(FieldNumber, NumberTools.LongToString(100L), NumberTools.LongToString(200L), true, true);
Hits hits = searcher.Search(query, filter);

使用 Query 作ؓqo条g?
QueryFilter filter = new QueryFilter(QueryParser.Parse("name2", FieldValue, analyzer));

我们q可以?FilteredQuery q行多条件过滤?

Filter filter = new DateFilter(FieldDate, DateTime.Parse("2005-10-10"), DateTime.Parse("2005-10-15"));
Filter filter2 = new RangeFilter(FieldNumber, NumberTools.LongToString(11L), NumberTools.LongToString(13L), true, true);

Query query = QueryParser.Parse("name*", FieldName, analyzer);
query = new FilteredQuery(query, filter);
query = new FilteredQuery(query, filter2);

IndexSearcher searcher = new IndexSearcher(reader);
Hits hits = searcher.Search(query);



8, Sort
有时你想要一个排好序的结果集Q就像SQL语句?#8220;order by”Qlucene能做刎ͼ通过Sort?
Sort sort = new Sort(“time”); //相当于SQL?#8220;order by time”
Sort sort = new Sort(“time”, true); // 相当于SQL?#8220;order by time desc”
下面是一个完整的例子Q?

Directory dir = FSDirectory.getDirectory(PATH, false);
IndexSearcher is = new IndexSearcher(dir);
QueryParser parser = new QueryParser("content", new StandardAnalyzer());
Query query = parser.parse("title:lucene content:lucene";
RangeFilter filter = new RangeFilter("time", "20060101", "20060230", true, true);
Sort sort = new Sort(“time”);
Hits hits = is.search(query, filter, sort);
for (int i = 0; i < hits.length(); i++)
{
Document doc = hits.doc(i);
System.out.println(doc.get("title");
}
is.close();

9,   性能优化
一直到q里Q我们还是在讨论怎么样lucene跑v来,完成指定d。利用前面说的也实能完成大部分功能。但是测试表明lucene的性能q不是很好,在大数据量大q发的条件下甚至会有半分钟返回的情况。另外大数据量的数据初始化徏立烦引也是一个十分耗时的过E。那么如何提高lucene的性能呢?下面从优化创建烦引性能和优化搜索性能两方面介l?

9.1 优化创徏索引性能
q方面的优化途径比较有限QIndexWriter提供了一些接口可以控制徏立烦引的操作Q另外我们可以先烦引写入RAMDirectoryQ再扚w写入FSDirectoryQ不怎样Q目的都是尽量少的文件IOQ因为创建烦引的最大瓶颈在于磁盘IO。另外选择一个较好的分析器也能提高一些性能?

9.1.1 通过讄IndexWriter的参C化烦引徏?
setMaxBufferedDocs(int maxBufferedDocs)
控制写入一个新的segment前内存中保存的document的数目,讄较大的数目可以加快徏索引速度Q默认ؓ10?
setMaxMergeDocs(int maxMergeDocs)
控制一个segment中可以保存的最大document数目QD有利于q加索引的速度Q默认Integer.MAX_VALUEQ无需修改?
setMergeFactor(int mergeFactor)
控制多个segment合ƈ的频率,D大时建立索引速度较快Q默认是10Q可以在建立索引时设|ؓ100?

9.1.2 通过RAMDirectory~写提高性能
我们可以先把索引写入RAMDirectoryQ达C定数量时再批量写qFSDirectoryQ减磁盘IOơ数?

FSDirectory fsDir = FSDirectory.getDirectory("/data/index", true);
RAMDirectory ramDir = new RAMDirectory();
IndexWriter fsWriter = new IndexWriter(fsDir, new StandardAnalyzer(), true);
IndexWriter ramWriter = new IndexWriter(ramDir, new StandardAnalyzer(), true);
while (there are documents to index)
{
... create Document ...
ramWriter.addDocument(doc);
if (condition for flushing memory to disk has been met)
{
fsWriter.addIndexes(new Directory[] { ramDir });
ramWriter.close();
ramWriter = new IndexWriter(ramDir, new StandardAnalyzer(), true);
}
}

9.1.3 选择较好的分析器
q个优化主要是对盘I间的优化,可以烦引文件减将q一半,相同试数据下由600M减少?80M。但是对旉q没有什么帮助,甚至会需要更长时_因ؓ较好的分析器需要匹配词库,会消耗更多cpuQ测试数据用StandardAnalyzer耗时133分钟Q用MMAnalyzer耗时150分钟?

9.2 优化搜烦性能
虽然建立索引的操作非常耗时Q但是那毕竟只在最初创建时才需要,qx只是量的维护操作,更何况这些可以放C个后台进E处理,q不影响用户搜烦。我们创建烦引的目的是l用h索,所以搜索的性能才是我们最兛_的。下面就来探讨一下如何提高搜索性能?

9.2.1 烦引放入内?
q是一个最直观的想法,因ؓ内存比磁盘快很多。Lucene提供了RAMDirectory可以在内存中容纳索引Q?

Directory fsDir = FSDirectory.getDirectory(“/data/index/”, false);
Directory ramDir = new RAMDirectory(fsDir);
Searcher searcher = new IndexSearcher(ramDir);

但是实践证明RAMDirectory和FSDirectory速度差不多,当数据量很小时两者都非常快,当数据量较大Ӟ索引文g400MQRAMDirectory甚至比FSDirectoryq要慢一点,q确实让人出乎意料?
而且lucene的搜索非常耗内存,即ɞ?00M的烦引文件蝲入内存,在运行一D|间后都会out of memoryQ所以个入内存的作用q不大?

9.2.2 优化旉范围限制
既然载入内存q不能提高效率,一定有其它瓉Q经q测试发现最大的瓉居然是时间范围限Ӟ那么我们可以怎样使时间范围限制的代h最呢Q?
当需要搜索指定时间范围内的结果时Q可以:
1、用RangeQueryQ设|范_但是RangeQuery的实现实际上是将旉范围内的旉点展开Q组成一个个BooleanClause加入到BooleanQuery中查询, 因此旉范围不可能设|太大,l测试,范围过一个月׃抛BooleanQuery.TooManyClausesQ可以通过讄BooleanQuery.setMaxClauseCount(int maxClauseCount)扩大Q但是扩大也是有限的Qƈ且随着maxClauseCount扩大Q占用内存也扩大
2、用RangeFilter代替RangeQueryQ经试速度不会比RangeQuery慢,但是仍然有性能瓉Q查询的90%以上旉耗费在RangeFilterQ研I其源码发现RangeFilter实际上是首先遍历所有烦引,生成一个BitSetQ标记每个documentQ在旉范围内的标记为trueQ不在的标记为falseQ然后将l果传递给Searcher查找Q这是十分耗时的?
3、进一步提高性能Q这个又有两个思\Q?
a、缓存Filterl果。既然RangeFilter的执行是在搜索之前,那么它的输入都是一定的Q就是IndexReaderQ而IndexReader是由Directory军_的,所以可以认为RangeFilter的结果是p围的上下限决定的Q也是由具体的RangeFilter对象军_Q所以我们只要以RangeFilter对象为键Q将filterl果BitSet~存h卛_。lucene API已经提供了一个CachingWrapperFiltercd装了Filter及其l果Q所以具体实施v来我们可以cache CachingWrapperFilter对象Q需要注意的是,不要被CachingWrapperFilter的名字及其说明误|CachingWrapperFilter看v来是有缓存功能,但的~存是针对同一个filter的,也就是在你用同一个filterqo不同IndexReaderӞ它可以帮你缓存不同IndexReader的结果,而我们的需求恰恰相反,我们是用不同filterqo同一个IndexReaderQ所以只能把它作Z个封装类?
b、降低时间精度。研IFilter的工作原理可以看出,它每ơ工作都是遍历整个烦引的Q所以时间粒度越大,Ҏ快Q搜索时间越短,在不影响功能的情况下Q时间精度越低越好,有时甚至牺牲一点精度也值得Q当然最好的情况是根本不作时间限制?
下面针对上面的两个思\演示一下优化结果(都采?00U程随机关键词随x间范_Q?
W一l,旉_ֺ为秒Q?
方式 直接用RangeFilter 使用cache 不用filter
q_每个U程耗时 10s 1s 300ms

W二l,旉_ֺ为天
方式 直接用RangeFilter 使用cache 不用filter
q_每个U程耗时 900ms 360ms 300ms

׃上数据可以得出结论:
1?量降低旉_ֺQ将_ֺq换成天带来的性能提高甚至比用cacheq好Q最好不使用filter?
2?在不能降低时间精度的情况下,使用cache能带?0倍左右的性能提高?

9.2.3 使用更好的分析器
q个跟创建烦引优化道理差不多Q烦引文件小了搜索自然会加快。当然这个提高也是有限的。较好的分析器相对于最差的分析器对性能的提升在20%以下?

10 一些经?

10.1关键词区分大写
or AND TO{关键词是区分大写的,lucene只认大写的,写的当做普通单词?/strong>

10.2 d互斥?
同一时刻只能有一个对索引的写操作Q在写的同时可以q行搜烦

10.3 文g?
在写索引的过E中退出将在tmp目录留下一个lock文gQ以后的写操作无法q行Q可以将其手工删?

10.4 旉格式
lucene只支持一U时间格式yyMMddHHmmssQ所以你传一个yy-MM-dd HH:mm:ss的时间给lucene它是不会当作旉来处理的

10.5 讄boost
有些时候在搜烦时某个字D늚权重需要大一些,例如你可能认为标题中出现关键词的文章比正文中出现关键词的文章更有价|你可以把标题的boost讄的更大,那么搜烦l果会优先显C标题中出现关键词的文章Q没有用排序的前题下)。用方法:
Field. setBoost(float boost);默认值是1.0Q也是说要增加权重的需要设|得?大?

上面q篇关于性能的讲解是很深? 请学?

本文转自Qhttp://zhangxinzhou.blog.ccidnet.com/blog-htm-do-showone-uid-36421-type-blog-itemid-213713.html


]]>
用Lucene加速Web搜烦应用E序的开?/title><link>http://www.tkk7.com/szhswl/articles/168301.html</link><dc:creator>宋针q?/dc:creator><author>宋针q?/author><pubDate>Mon, 17 Dec 2007 11:17:00 GMT</pubDate><guid>http://www.tkk7.com/szhswl/articles/168301.html</guid><wfw:comment>http://www.tkk7.com/szhswl/comments/168301.html</wfw:comment><comments>http://www.tkk7.com/szhswl/articles/168301.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/szhswl/comments/commentRss/168301.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/szhswl/services/trackbacks/168301.html</trackback:ping><description><![CDATA[<blockquote>Lucene 是基?Java 的全文信息检索包Q它目前?Apache Jakarta 家族下面的一个开源项目。在q篇文章中,我们首先来看如何利用Lucene 实现高搜烦功能Q然后学习如何利?Lucene 来创Z个健壮的 Web 搜烦应用E序?/blockquote><!--start RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--end RESERVED FOR FUTURE USE INCLUDE FILES--> <p>在本文章中Q你会学习到如何利用 Lucene 实现高搜烦功能以及如何利用 Lucene 来创?Web 搜烦应用E序。通过q些学习Q你可以利?Lucene 来创q搜烦应用E序?/p> <p><a name="N10064"><span id="fbp1lx9" class="atitle">架构概览</span></a></p> <p>通常一?Web 搜烦引擎的架构分为前端和后端两部分,像下图中所C。在前端程中,用户在搜索引擎提供的界面中输入要搜烦的关键词Q这里提到的用户界面一般是一个带有输入框?Web 面Q然后应用程序将搜烦的关键词解析成搜索引擎可以理解的形式Qƈ在烦引文件上q行搜烦操作。在排序后,搜烦引擎q回搜烦l果l用戗在后端程中,|络爬虫或者机器h从因特网上获?Web 面Q然后烦引子pȝ解析q些 Web 面q存入烦引文件中。如果你惛_?Lucene 来创Z?Web 搜烦应用E序Q那么它的架构也和上面所描述的类|如下图中所C?/p> <br /> <a name="figure1"><strong>Figure 1. Web 搜烦引擎架构</strong></a><br /> <img height="380" alt="Web搜烦引擎架构" src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure1.gif" width="449" /> <br /> <p><a name="N10085"><span id="tfzv7lb" class="atitle">利用 Lucene 实现高搜烦</span></a></p> <p>Lucene 支持多种形式的高U搜索,我们在这一部分中会q行探讨Q然后我会?Lucene ?API 来演C如何实现这些高U搜索功能?/p> <p><a name="N1008E"><span id="jrlv13h" class="smalltitle">布尔操作W?/span></a></p> <p>大多数的搜烦引擎都会提供布尔操作W让用户可以l合查询Q典型的布尔操作W有 AND, OR, NOT。Lucene 支持 5 U布操作符Q分别是 AND, OR, NOT, ?+), ?-)。接下来我会讲述每个操作W的用法?</p> <ul> <li><strong>OR</strong>: 如果你要搜烦含有字符 A 或?B 的文档,那么需要?OR 操作W。需要记住的是,如果你只是简单的用空格将两个关键词分割开Q其实在搜烦的时候搜索引擎会自动在两个关键词之间加上 OR 操作W。例如,“Java OR Lucene” ?“Java Lucene” 都是搜烦含有 Java 或者含?Lucene 的文档? <li><strong>AND</strong>: 如果你需要搜索包含一个以上关键词的文档,那么需要?AND 操作W。例如,“Java AND Lucene” q回所有既包含 Java 又包?Lucene 的文档? <li><strong>NOT</strong>: Not 操作W得包含紧跟在 NOT 后面的关键词的文档不会被q回。例如,如果你想搜烦所有含?Java 但不含有 Lucene 的文档,你可以用查询语?“Java NOT Lucene”。但是你不能只对一个搜索词使用q个操作W,比如Q查询语?“NOT Java” 不会q回Ml果? <li><strong>加号Q?Q?/strong>: q个操作W的作用?AND 差不多,但它只对紧跟着它的一个搜索词起作用。例如,如果你想搜烦一定包?JavaQ但不一定包?Lucene 的文档,可以用查询语?#8220;+Java Lucene”? <li><strong>减号Q?Q?/strong>: q个操作W的功能?NOT 一P查询语句 “Java -Lucene” q回所有包?Java 但不包含 Lucene 的文档?</li> </ul> <p>接下来我们看一下如何利?Lucene 提供?API 来实现布查询。下面代?昄了如果利用布操作符q行查询的过E?/p> <br /> <a name="Listing1"><strong>清单1Q用布操作符</strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode"> //Test boolean operator public void testOperator(String indexDirectory) throws Exception{ Directory dir = FSDirectory.getDirectory(indexDirectory,false); IndexSearcher indexSearcher = new IndexSearcher(dir); String[] searchWords = {"Java AND Lucene", "Java NOT Lucene", "Java OR Lucene", "+Java +Lucene", "+Java -Lucene"}; Analyzer language = new StandardAnalyzer(); Query query; for(int i = 0; i < searchWords.length; i++){ query = QueryParser.parse(searchWords[i], "title", language); Hits results = indexSearcher.search(query); System.out.println(results.length() + "search results for query " + searchWords[i]); } } </pre> </td> </tr> </tbody> </table> <br /> <p><a name="N100C4"><span id="btldpjn" class="smalltitle">域搜?Field Search)</span></a></p> <p>Lucene 支持域搜索,你可以指定一ơ查询是在哪些域(Field)上进行。例如,如果索引的文档包含两个域Q?code>Title</code> ?<code>Content</code>Q你可以用查?“Title: Lucene AND Content: Java” 来返回所有在 Title 域上包含 Lucene q且?Content 域上包含 Java 的文档。下面代?昄了如何利?Lucene ?API 来实现域搜烦?</p> <br /> <a name="Listing2"><strong>清单2Q实现域搜烦</strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">//Test field search public void testFieldSearch(String indexDirectory) throws Exception{ Directory dir = FSDirectory.getDirectory(indexDirectory,false); IndexSearcher indexSearcher = new IndexSearcher(dir); String searchWords = "title:Lucene AND content:Java"; Analyzer language = new StandardAnalyzer(); Query query = QueryParser.parse(searchWords, "title", language); Hits results = indexSearcher.search(query); System.out.println(results.length() + "search results for query " + searchWords); } </pre> </td> </tr> </tbody> </table> <br /> <p><a name="N100E3"><span id="hlltdvt" class="smalltitle">通配W搜?Wildcard Search)</span></a></p> <p>Lucene 支持两种通配W:问号Q?Q和星号Q?Q。你可以使用问号Q?Q来q行单字W的通配W查询,或者利用星P*Q进行多字符的通配W查询。例如,如果你想搜烦 tiny 或?tonyQ你可以用查询语?“t?ny”Q如果你x?Teach, Teacher ?TeachingQ你可以用查询语?“Teach*”。下面代?昄了通配W查询的q程?</p> <br /> <a name="Listing3"><strong>清单3Q进行通配W查?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">//Test wildcard search public void testWildcardSearch(String indexDirectory)throws Exception{ Directory dir = FSDirectory.getDirectory(indexDirectory,false); IndexSearcher indexSearcher = new IndexSearcher(dir); String[] searchWords = {"tex*", "tex?", "?ex*"}; Query query; for(int i = 0; i < searchWords.length; i++){ query = new WildcardQuery(new Term("title",searchWords[i])); Hits results = indexSearcher.search(query); System.out.println(results.length() + "search results for query " + searchWords[i]); } } </pre> </td> </tr> </tbody> </table> <br /> <p><a name="N100FA"><span id="5j9j9r3" class="smalltitle">模糊查询</span></a></p> <p>Lucene 提供的模p查询基于编辑距ȝ?Edit distance algorithm)。你可以在搜索词的尾部加上字W?~ 来进行模p查询。例如,查询语句 “think~” q回所有包含和 think cM的关键词的文档。下面代码显CZ如果利用 Lucene ?API q行模糊查询的代码?</p> <br /> <a name="Listing4"><strong>清单4Q实现模p查?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">//Test fuzzy search public void testFuzzySearch(String indexDirectory)throws Exception{ Directory dir = FSDirectory.getDirectory(indexDirectory,false); IndexSearcher indexSearcher = new IndexSearcher(dir); String[] searchWords = {"text", "funny"}; Query query; for(int i = 0; i < searchWords.length; i++){ query = new FuzzyQuery(new Term("title",searchWords[i])); Hits results = indexSearcher.search(query); System.out.println(results.length() + "search results for query " + searchWords[i]); } } </pre> </td> </tr> </tbody> </table> <br /> <p><a name="N10111"><span id="9fhxpfp" class="smalltitle">范围搜烦(Range Search)</span></a></p> <p>范围搜烦匚w某个域上的值在一定范围的文档。例如,查询 “age:[18 TO 35]” q回所?age 域上的值在 18 ?35 之间的文档。下面代码显CZ利用 Lucene ?API q行q回搜烦的过E?</p> <br /> <a name="Listing5"><strong>清单5Q测试范围搜?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">//Test range search public void testRangeSearch(String indexDirectory)throws Exception{ Directory dir = FSDirectory.getDirectory(indexDirectory,false); IndexSearcher indexSearcher = new IndexSearcher(dir); Term begin = new Term("birthDay","20000101"); Term end = new Term("birthDay","20060606"); Query query = new RangeQuery(begin,end,true); Hits results = indexSearcher.search(query); System.out.println(results.length() + "search results is returned"); } </pre> </td> </tr> </tbody> </table> <br /> <p><a name="N10128"><span id="hp1tdln" class="atitle">?Web 应用E序中集?Lucene</span></a></p> <p>接下来我们开发一?Web 应用E序利用 Lucene 来检索存攑֜文g服务器上?HTML 文档。在开始之前,需要准备如下环境:</p> <ol> <li>Eclipse 集成开发环? <li>Tomcat 5.0 <li>Lucene Library <li>JDK 1.5 </li> </ol> <p>q个例子使用 Eclipse q行 Web 应用E序的开发,最l这?Web 应用E序跑在 Tomcat 5.0 上面。在准备好开发所必需的环境之后,我们接下来进?Web 应用E序的开发?</p> <p><a name="N10143"><span id="djzf9t7" class="smalltitle">1、创Z个动?Web 目</span></a></p> <ol> <li>?Eclipse 里面Q选择 <strong>File > New > Project</strong>Q然后再弹出的窗口中选择<strong>动?Web 目</strong>Q如下图所C?</li> </ol> <br /> <a name="figure2"><strong>图二Q创建动态Web目</strong></a><br /> <img height="473" alt="创徏动态Web目" src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure2.jpg" width="496" /> <br /> <ol start="2"> <li>在创建好动?Web 目之后Q你会看到创建好的项目的l构Q如下图所C,目的名UCؓ sample.dw.paper.lucene?</li> </ol> <br /> <a name="figure3"><strong>图三Q动?Web 目的结?/strong></a><br /> <img height="338" alt="动?Web 目的结? src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure3.jpg" width="329" /> <br /> <p><a name="N10182"><span id="tddtnh3" class="smalltitle">2. 设计 Web 目的架?/span></a></p> <p>在我们的设计中,把该pȝ分成如下四个子系l:</p> <ol> <li><strong>用户接口</strong>: q个子系l提供用L面用户可以?Web 应用E序服务器提交搜索请求,然后搜烦l果通过用户接口来显C出来。我们用一个名?search.jsp 的页面来实现该子pȝ? <li><strong>h理?/strong>: q个子系l管理从客户端发送过来的搜烦hq把搜烦h分发到搜索子pȝ中。最后搜索结果从搜烦子系l返回ƈ最l发送到用户接口子系l。我们用一?Servlet 来实现这个子pȝ? <li><strong>搜烦子系l?/strong>: q个子系l负责在索引文g上进行搜索ƈ把搜索结构传递给h理器。我们?Lucene 提供?API 来实现该子系l? <li><strong>索引子系l?/strong>: q个子系l用来ؓ HTML 面来创建烦引。我们?Lucene ?API 以及 Lucene 提供的一?HTML 解析器来创徏该子pȝ?</li> </ol> <p>下图昄了我们设计的详细信息Q我们将用户接口子系l放?webContent 目录下面。你会看C个名?search.jsp 的页面在q个文g多w面。请求管理子pȝ在包 <code>sample.dw.paper.lucene.servlet</code> 下面Q类 <code>SearchController</code> 负责功能的实现。搜索子pȝ攑֜?<code>sample.dw.paper.lucene.search</code> 当中Q它包含了两个类Q?code>SearchManager</code> ?<code>SearchResultBean</code>Q第一个类用来实现搜烦功能Q第二个cȝ来描q搜索结果的l构。烦引子pȝ攑֜?<code>sample.dw.paper.lucene.index</code> 当中。类 <code>IndexManager</code> 负责?HTML 文g创徏索引。该子系l利用包 <code>sample.dw.paper.lucene.util</code> 里面的类 <code>HTMLDocParser</code> 提供的方?<code>getTitle</code> ?<code>getContent</code> 来对 HTML 面q行解析?</p> <br /> <a name="figure4"><strong>囑֛Q项目的架构设计</strong></a><br /> <img height="324" alt="目的架构设? src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure4.jpg" width="384" /> <br /> <p><a name="N101E4"><span id="7jb7vhp" class="smalltitle">3. 子系l的实现</span></a></p> <p>在分析了pȝ的架构设计之后,我们接下来看pȝ实现的详l信息?</p> <ol> <li><strong>用户接口</strong>: q个子系l有一个名?search.jsp ?JSP 文g来实玎ͼq个 JSP 面包含两个部分。第一部分提供了一个用h口去?Web 应用E序服务器提交搜索请求,如下图所C。注意到q里的搜索请求发送到了一个名?SearchController ?Servlet 上面。Servlet 的名字和具体实现的类的对应关pd web.xml 里面指定?</li> </ol> <br /> <a name="figure5"><strong>?Q向Web服务器提交搜索请?/strong></a><br /> <img height="207" alt="向Web服务器提交搜索请? src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure5.jpg" width="532" /> <br /> <p>q个JSP的第二部分负责显C搜索结果给用户Q如图下图所C: </p> <br /> <a name="figure6"><strong>?Q显C搜索结?/strong></a><br /> <img height="360" alt="昄搜烦l果" src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure6.jpg" width="572" /> <br /> <ol start="2"> <li><strong>h理?/strong>: 一个名?<code>SearchController</code> ?servlet 用来实现该子pȝ。下面代码给Zq个cȝ源代码?</li> </ol> <br /> <a name="Listing6"><strong>清单Q:h理器的实现</strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">            package sample.dw.paper.lucene.servlet; import java.io.IOException; import java.util.List; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import sample.dw.paper.lucene.search.SearchManager; /** * This servlet is used to deal with the search request * and return the search results to the client */ public class SearchController extends HttpServlet{ private static final long serialVersionUID = 1L; public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ String searchWord = request.getParameter("searchWord"); SearchManager searchManager = new SearchManager(searchWord); List searchResult = null; searchResult = searchManager.search(); RequestDispatcher dispatcher = request.getRequestDispatcher("search.jsp"); request.setAttribute("searchResult",searchResult); dispatcher.forward(request, response); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{ doPost(request, response); } } </pre> </td> </tr> </tbody> </table> <br /> <p>在代码中Q?code>doPost</code> Ҏ从客L获取搜烦词ƈ创徏c?<code>SearchManager</code> 的一个实例,其中c?<code>SearchManager</code> 在搜索子pȝ中进行了定义。然后,<code>SearchManager</code> 的方?search 会被调用。最后搜索结果被q回到客L?</p> <ol start="3"> <li><strong>搜烦子系l?/strong>: 在这个子pȝ中,我们定义了两个类Q?code>SearchManager</code> ?<code>SearchResultBean</code>。第一个类用来实现搜烦功能Q第二个cL个JavaBeanQ用来描q搜索结果的l构。下面代码给Zc?<code>SearchManager</code> 的源代码?</li> </ol> <br /> <a name="Listing7"><strong>清单7Q搜索功能的实现</strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">            package sample.dw.paper.lucene.search; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.queryParser.ParseException; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Hits; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import sample.dw.paper.lucene.index.IndexManager; /** * This class is used to search the * Lucene index and return search results */ public class SearchManager { private String searchWord; private IndexManager indexManager; private Analyzer analyzer; public SearchManager(String searchWord){ this.searchWord = searchWord; this.indexManager = new IndexManager(); this.analyzer = new StandardAnalyzer(); } /** * do search */ public List search(){ List searchResult = new ArrayList(); if(false == indexManager.ifIndexExist()){ try { if(false == indexManager.createIndex()){ return searchResult; } } catch (IOException e) { e.printStackTrace(); return searchResult; } } IndexSearcher indexSearcher = null; try{ indexSearcher = new IndexSearcher(indexManager.getIndexDir()); }catch(IOException ioe){ ioe.printStackTrace(); } QueryParser queryParser = new QueryParser("content",analyzer); Query query = null; try { query = queryParser.parse(searchWord); } catch (ParseException e) { e.printStackTrace(); } if(null != query >> null != indexSearcher){ try { Hits hits = indexSearcher.search(query); for(int i = 0; i < hits.length(); i ++){ SearchResultBean resultBean = new SearchResultBean(); resultBean.setHtmlPath(hits.doc(i).get("path")); resultBean.setHtmlTitle(hits.doc(i).get("title")); searchResult.add(resultBean); } } catch (IOException e) { e.printStackTrace(); } } return searchResult; } } </pre> </td> </tr> </tbody> </table> <br /> <p>在上面代码,注意到在q个c里面有三个U有属性。第一个是 <code>searchWord</code>Q代表了来自客户端的搜烦词。第二个?<code>indexManager</code>Q代表了在烦引子pȝ中定义的c?<code>IndexManager</code> 的一个实例。第三个?<code>analyzer</code>Q代表了用来解析搜烦词的解析器。现在我们把注意力放在方?<code>search</code> 上面。这个方法首先检查烦引文件是否已l存在,如果已经存在Q那么就在已l存在的索引上进行检索,如果不存在,那么首先调用c?<code>IndexManager</code> 提供的方法来创徏索引Q然后在新创建的索引上进行检索。搜索结果返回后Q这个方法从搜烦l果中提取出需要的属性ƈ为每个搜索结果生成类 <code>SearchResultBean</code> 的一个实例。最后这?<code>SearchResultBean</code> 的实例被攑ֈ一个列表里面ƈq回l请求管理器?/p> <p>在类 <code>SearchResultBean</code> 中,含有两个属性,分别?<code>htmlPath</code> ?<code>htmlTitle</code>Q以及这个两个属性的 get ?set Ҏ。这也意味着我们的搜索结果包含两个属性:<code>htmlPath</code> ?<code>htmlTitle</code>Q其?<code>htmlPath</code> 代表?HTML 文g的\径,<code>htmlTitle</code> 代表?HTML 文g的标题?</p> <ol start="4"> <li><strong>索引子系l?/strong>: c?<code>IndexManager</code> 用来实现q个子系l?下面代码l出了这个类的源代码?</li> </ol> <br /> <a name="Listing8"><strong>清单8Q烦引子pȝ的实?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">            package sample.dw.paper.lucene.index; import java.io.File; import java.io.IOException; import java.io.Reader; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import sample.dw.paper.lucene.util.HTMLDocParser; /** * This class is used to create an index for HTML files * */ public class IndexManager { //the directory that stores HTML files private final String dataDir = "c:\\dataDir"; //the directory that is used to store a Lucene index private final String indexDir = "c:\\indexDir"; /** * create index */ public boolean createIndex() throws IOException{ if(true == ifIndexExist()){ return true; } File dir = new File(dataDir); if(!dir.exists()){ return false; } File[] htmls = dir.listFiles(); Directory fsDirectory = FSDirectory.getDirectory(indexDir, true); Analyzer analyzer = new StandardAnalyzer(); IndexWriter indexWriter = new IndexWriter(fsDirectory, analyzer, true); for(int i = 0; i < htmls.length; i++){ String htmlPath = htmls[i].getAbsolutePath(); if(htmlPath.endsWith(".html") || htmlPath.endsWith(".htm")){ addDocument(htmlPath, indexWriter); } } indexWriter.optimize(); indexWriter.close(); return true; } /** * Add one document to the Lucene index */ public void addDocument(String htmlPath, IndexWriter indexWriter){ HTMLDocParser htmlParser = new HTMLDocParser(htmlPath); String path = htmlParser.getPath(); String title = htmlParser.getTitle(); Reader content = htmlParser.getContent(); Document document = new Document(); document.add(new Field("path",path,Field.Store.YES,Field.Index.NO)); document.add(new Field("title",title,Field.Store.YES,Field.Index.TOKENIZED)); document.add(new Field("content",content)); try { indexWriter.addDocument(document); } catch (IOException e) { e.printStackTrace(); } } /** * judge if the index exists already */ public boolean ifIndexExist(){ File directory = new File(indexDir); if(0 < directory.listFiles().length){ return true; }else{ return false; } } public String getDataDir(){ return this.dataDir; } public String getIndexDir(){ return this.indexDir; } } </pre> </td> </tr> </tbody> </table> <br /> <p>q个cd含两个私有属性,分别?<code>dataDir</code> ?<code>indexDir</code>?code>dataDir</code> 代表存放{待q行索引?HTML 面的\径,<code>indexDir</code> 代表了存?Lucene 索引文g的\径。类 <code>IndexManager</code> 提供了三个方法,分别?<code>createIndex</code>, <code>addDocument</code> ?<code>ifIndexExist</code>。如果烦引不存在的话Q你可以使用Ҏ <code>createIndex</code> dZ个新的烦引,用方?<code>addDocument</code> d一个烦引上d文档。在我们的场景中Q一个文档就是一?HTML 面。方?<code>addDocument</code> 会调用由c?<code>HTMLDocParser</code> 提供的方法对 HTML 文档q行解析。你可以使用最后一个方?<code>ifIndexExist</code> 来判?Lucene 的烦引是否已l存在?</p> <p>现在我们来看一下放在包 <code>sample.dw.paper.lucene.util</code> 里面的类 <code>HTMLDocParser</code>。这个类用来?HTML 文g中提取出文本信息。这个类包含三个ҎQ分别是 <code>getContent</code>Q?code>getTitle</code> ?<code>getPath</code>。第一个方法返回去除了 HTML 标记的文本内容,W二个方法返?HTML 文g的标题,最后一个方法返?HTML 文g的\径。下面代码给Zq个cȝ源代码?</p> <br /> <a name="Listing9"><strong>清单9QHTML 解析?/strong></a><br /> <table cellspacing="0" cellpadding="0" width="100%" border="0"> <tbody> <tr> <td class="code-outline"> <pre class="displaycode">package sample.dw.paper.lucene.util; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; import org.apache.lucene.demo.html.HTMLParser; public class HTMLDocParser { private String htmlPath; private HTMLParser htmlParser; public HTMLDocParser(String htmlPath){ this.htmlPath = htmlPath; initHtmlParser(); } private void initHtmlParser(){ InputStream inputStream = null; try { inputStream = new FileInputStream(htmlPath); } catch (FileNotFoundException e) { e.printStackTrace(); } if(null != inputStream){ try { htmlParser = new HTMLParser(new InputStreamReader(inputStream, "utf-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } public String getTitle(){ if(null != htmlParser){ try { return htmlParser.getTitle(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } return ""; } public Reader getContent(){ if(null != htmlParser){ try { return htmlParser.getReader(); } catch (IOException e) { e.printStackTrace(); } } return null; } public String getPath(){ return this.htmlPath; } } </pre> </td> </tr> </tbody> </table> <br /> <p><a name="N10330"><span id="nzhl9hj" class="smalltitle">5Q在 Tomcat 5.0 上运行应用程?/span></a></p> <p>现在我们可以?Tomcat 5.0 上运行开发好的应用程序?</p> <ol> <li>右键单击 <strong>search.jsp</strong>Q然后选择 <strong>Run as > Run on Server</strong>Q如下图所C?</li> </ol> <br /> <a name="figure7"><strong>?Q配|?Tomcat 5.0</strong></a><br /> <img height="434" alt="配置 Tomcat 5.0" src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure7.jpg" width="478" /> <br /> <ol start="2"> <li>在弹出的H口中,选择 <strong>Tomcat v5.0 Server</strong> 作ؓ目标 Web 应用E序服务器,然后点击 <strong>Next</strong>Q如下图所C: </li> </ol> <br /> <a name="figure8"><strong>?Q选择 Tomcat 5.0</strong></a><br /> <img height="433" alt="选择 Tomcat 5.0" src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure8.jpg" width="467" /> <br /> <ol start="3"> <li>现在需要指定用来运?Web 应用E序?Apache Tomcat 5.0 以及 JRE 的\径。这里你所选择?JRE 的版本必d你用来编?Java 文g?JRE 的版本一致。配|好之后Q点?<strong>Finish</strong>。如下图 所C?</li> </ol> <br /> <a name="figure9"><strong>?Q完成Tomcat 5.0的配|?/strong></a><br /> <img height="436" alt="完成Tomcat 5.0的配|? src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure9.jpg" width="468" /> <br /> <ol start="4"> <li>配置好之后,Tomcat 会自动运行,q且会对 search.jsp q行~译q显C给用户。如下图 所C?</li> </ol> <br /> <a name="figure10"><strong>?0Q用L?/strong></a><br /> <img height="403" alt="用户界面" src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure10.jpg" width="521" /> <br /> <ol start="5"> <li>在输入框中输入关键词 “information” 然后单击 <strong>Search</strong> 按钮。然后这个页面上会显C出搜烦l果来,如下图所C?</li> </ol> <br /> <a name="figure11"><strong>?1Q搜索结?/strong></a><br /> <img height="416" alt="搜烦l果" src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure11.jpg" width="526" /> <br /> <ol start="6"> <li>单击搜烦l果的第一个链接,面上就会显C出所链接到的面的内宏V如下图所C? </li> </ol> <br /> <a name="figure12"><strong>?2Q详l信?/strong></a><br /> <img height="419" alt="详细信息" src="http://www.ibm.com/developerworks/cn/web/wa-lucene2/figure12.jpg" width="525" /> <br /> <p>现在我们已经成功的完成了CZ目的开发,q成功的用Lucene实现了搜索和索引功能。你可以下蝲q个目的源代码Q?a title="下蝲" href="http://www.tkk7.com/Files/szhswl/wa-lucene2_source_code.zip">下蝲</a>Q?</p> <br /> <p><a name="N103ED"><span id="93hrdrj" class="atitle">ȝ</span></a></p> <p>Lucene 提供了灵zȝ接口使我们更加方便的设计我们?Web 搜烦应用E序。如果你惛_你的应用E序中加入搜索功能,那么 Lucene 是一个很好的选择。在设计你的下一个带有搜索功能的应用E序的时候可以考虑使用 Lucene 来提供搜索功能?br /> <br /> 本文摘自Qhttp://www.ibm.com/developerworks/cn/web/wa-lucene2/</p> <img src ="http://www.tkk7.com/szhswl/aggbug/168301.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/szhswl/" target="_blank">宋针q?/a> 2007-12-17 19:17 <a href="http://www.tkk7.com/szhswl/articles/168301.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>lCompass搜烦d高亮(highlight)http://www.tkk7.com/szhswl/articles/167326.html宋针q?/dc:creator>宋针q?/author>Wed, 12 Dec 2007 12:39:00 GMThttp://www.tkk7.com/szhswl/articles/167326.htmlhttp://www.tkk7.com/szhswl/comments/167326.htmlhttp://www.tkk7.com/szhswl/articles/167326.html#Feedback0http://www.tkk7.com/szhswl/comments/commentRss/167326.htmlhttp://www.tkk7.com/szhswl/services/trackbacks/167326.html
 1         if (searchHelper == null) {
 2             searchHelper = new CompassSearchHelper(getCompass(), getPageSize());
 3         }
 4         CompassSearchCommand searchCommand = new CompassSearchCommand();
 5         searchCommand.setPage(new Integer(currentPage-1));
 6         searchCommand.setQuery(query);
 7         ModelAndView mv = new ModelAndView();
 8         mv.addObject("query", query);
 9         mv.addObject("p", currentPage);
10         List<String> errors = new ArrayList<String>();
11         try{
12             CompassSearchResults searchResults = searchHelper.search(searchCommand);
13             mv.addObject(getSearchResultsName(), searchResults);
14         }catch (SearchEngineQueryParseException ex){
15             errors.add(TextUtil.escapeHTML(ex.getMessage()));
16             mv.addObject("errors", errors);
17         } 
18 
本来打算按照springside里面的封装方法?br /> http://svn.javascud.org/svn/springside/springside2/trunk/core/src/java/org/springside/components/compass/
q里有两个类AdvancedSearchCommand.java,CompassSearchService.javaQCompassSearchService里面实现了高亮和排序Q后来发现CompassSearchService和CompassSearchHelper长得很像Q而且CompassSearchHelper也提供了两个抽象的方法给用户提供一个添加功能的Z?br />
 1     /**
 2      * An option to perform any type of processing before the hits are detached.
 3      */
 4     protected void doProcessBeforeDetach(CompassSearchCommand searchCommand, CompassSession session, CompassHits hits,
 5                                          int from, int size) {
 6 
 7     }
 8 
 9     /**
10      * An option to perform any type of processing after the hits are detached.
11      */
12     protected void doProcessAfterDetach(CompassSearchCommand searchCommand, CompassSession session,
13                                         CompassDetachedHits hits) {
14 
15     } 
16 
所以我们只要实C个自qCompassSearchHelper覆盖q两个方法就可以辑ֈ实现高亮的目的了?br />
 1 /**
 2  * @author <a href="mailto:rory.cn@gmail.com">somebody</a>
 3  * @since Aug 23, 2007 2:04:19 PM
 4  * @version $Id AdvanceCompassSearchHelper.java$
 5  */
 6 public class AdvanceCompassSearchHelper extends CompassSearchHelper {
 7 
 8     private String[] highlightFields;
 9 
10     public String[] getHighlightFields() {
11         return highlightFields;
12     }
13 
14     public void setHighlightFields(String[] highlightFields) {
15         this.highlightFields = highlightFields;
16     }
17 
18     /**
19      * @param compass
20      */
21     public AdvanceCompassSearchHelper(Compass compass) {
22         super(compass);
23     }
24     
25 
26     /* (non-Javadoc)
27      * @see org.compass.core.support.search.CompassSearchHelper#doProcessBeforeDetach(org.compass.core.support.search.CompassSearchCommand, org.compass.core.CompassSession, org.compass.core.CompassHits, int, int)
28      */
29     @Override
30     protected void doProcessBeforeDetach(CompassSearchCommand searchCommand,
31             CompassSession session, CompassHits hits, int from, int size) {
32         if (from < 0) {
33             from = 0;
34             size = hits.getLength();
35         }
36 
37         if (highlightFields == null) {
38             return;
39         }
40         // highlight fields
41         for (int i = from; i < size; i++) {
42             for (String highlightField : highlightFields) {
43                 hits.highlighter(i).fragment(highlightField);
44             }
45         }
46     } 
47 
okQ这样就可以实现高亮了。修改一下SearchController的配|?br />
 1     <bean id="advanceCompassSearchHelper" class="com.jdkcn.compass.AdvanceCompassSearchHelper">
 2         <property name="highlightFields">
 3             <list>
 4                 <value>content</value>
 5             </list>
 6         </property>
 7         <property name="pageSize"><value>10</value></property>
 8         <constructor-arg ref="compass"/>
 9     </bean>
10      
11     <bean id="searchController" class="com.jdkcn.web.SearchController" parent="baseController">
12         <property name="compass"><ref bean="compass"/></property>
13         <property name="searchView"><value>search</value></property>
14         <property name="searchResultsView"><value>search</value></property>
15         <property name="pageSize"><value>10</value></property>
16         <property name="searchHelper"><ref local="advanceCompassSearchHelper"/></property>
17     </bean> 
18 
q不要忘了修改一下compass settings 修改一下高亮的样式Q修改一下高亮的颜色?br />
 1     <bean id="compass" class="org.compass.spring.LocalCompassBean">
 2         <property name="resourceDirectoryLocations">
 3             <list>
 4                 <value>classpath:com/jdkcn/compass</value>
 5             </list>
 6         </property>
 7         <property name="connection">
 8             <value>/lucene/indexes</value>
 9         </property>
10         <property name="compassSettings">
11             <props>
12                 <prop key="compass.transaction.factory">
13                     org.compass.spring.transaction.SpringSyncTransactionFactory
14                 </prop>
15                 <prop key="compass.engine.highlighter.default.formatter.simple.pre">
16                     <![CDATA[<font color="red"><b>]]>
17                 </prop>
18                 <prop key="compass.engine.highlighter.default.formatter.simple.post">
19                     <![CDATA[</b></font>]]>
20                 </prop>
21             </props>
22         </property>
23         <property name="transactionManager">
24             <ref bean="transactionManager" />
25         </property>
26     </bean> 
27 
ok了,面上输Z下就能看到最l效果了${hit.highlightedText['content']?if_exists}

本文转自:http://jdkcn.com/entry/howto-add-highlight-in-compass.html



]]>
Compass: 在你的应用中集成搜烦功能http://www.tkk7.com/szhswl/articles/167242.html宋针q?/dc:creator>宋针q?/author>Wed, 12 Dec 2007 07:20:00 GMThttp://www.tkk7.com/szhswl/articles/167242.htmlhttp://www.tkk7.com/szhswl/comments/167242.htmlhttp://www.tkk7.com/szhswl/articles/167242.html#Feedback0http://www.tkk7.com/szhswl/comments/commentRss/167242.htmlhttp://www.tkk7.com/szhswl/services/trackbacks/167242.html
现实中,对于可用性的角度来说Q这两种Ҏ都不是最佳的。浏览的方式会在有许多分支的时候变得缓慢而笨重。而且Q用户通常_地知道他们要用到那个应用Q然而却不情愿要览整个pȝ来找C要的应用。检索表单的方式同样被检索条件个数的多少限制住了。这p在设|够的索域q是索表单的复杂性上作出权衡?br />
从可用性的角度来说Q解册个问题的{案是提供一个单一的、Google样式的检索框Q用户可以输入Q何符合实例字D늚内容。他们可以检索和表示W合q些内容的结果。表单中的这个检索框可以自动填充、Google模式的输入框Q或者是q回表格式结果的正则表达式搜索。不怎样Q这U解x案的_N是UI是简单的Q用户可以输入Q何他们选择的条Ӟ然后由搜索引擎去做这些复杂的工作。现在唯一的问题时Q如何实现这L搜烦?br />
当面对实Cl的多输入域的表单的时候,大部分应用程序都选择了SQL。典型的情况是,索的字段都与列名相匹配,q且使用SQL的LIKE语句。然而,因ؓ复杂的SQL要去匚w太多的字D,q且很多情况下由于这些字D늚文本长度问题Q造成实现的性能l常是非常差的。第二个问题是,Ҏ索结果没有排名ƈ且返回的提示q没有反应出与查询的内容有多大相x,只是单地q回l果|了。第三,Ҏ索结果相兌的关键字没有高亮表示?br />
很快Q大家意识到大部分应用程序需要搜索引擎。所有实体的字段可以像只有一个文仉栯索引Qƈ且是正则文本搜烦可以匚w的实体。现在非常流行的搜烦引擎之一是Luence。Lucene是相当不错的搜烦引擎Q在很多目中应用成功。它提供了底层的搜烦引擎APIQ能够用Lucene数据l构QDocument/FieldQ去索引数据Q能供用查询API或搜索引擎在索引上检索。它已经在多U编E语a上实C全部功能Q包括Java、C#?C++{?br />
如果我们分析一个典型的Web应用E序Q一般都有个一个共通的架构和特炏V通常Q应用与后端的关pL据库一起工作。这个应用用领域模型表C个系l中的实体,q用ORM框架把领域模型映到数据库上。一般情况下Q用一个服务层框架ȝ理事务、协作,有时也包括业务逻辑和Web框架。问题就在于怎么把Lucene集成到这L应用E序中去?br />
当你试图去集成Lucene的时候,刚刚把第一个简单的E序跑v来的时候,马上׃遇到一q串的挑战。第一个问题就是烦引应用数据。在之前很长一D|_相当多的h式代码热衷于把领域模型映到Lucene数据模型上去。Lucene文档Q是Lucene主要的数据结构,它是一个扁q的cMMap 的,只包含字W串的数据结构——所以许多无意义的代码热衷于“植入”?#8220;植出”领域模型。另外一个问题是~少对Lucene的事务控Ӟ把领域模型数据存储到数据库和搜烦引擎是有问题的。而且q有几个其他的很有名的实践和模式要在Lucene中实玎ͼ比如~存、隐式的搜烦、ؓ支持Google样式的搜索而创集的属性和为合适的语义保持可识别的Document对象Q等{?br /> Compass?br />
Compass的设计目标是化企业在集成搜烦功能时的p。Compass是在Lucene之上Q用了设计很好的搜索引擎的抽象。Compass扩展了核心LuceneQ增加了事务控制功能和快速更斎ͼ也包括在数据库存储烦引的功能。当Ӟ它没有去隐藏Lucene的特性——所有Lucene的功能都能通过Compass实现?br /> Compass核心API

Compass提供l了我们单的q且熟悉的API。说Compass提供了让人熟悉的API是因为它模仿了当前流行的ORM框架的API来降低学习曲UѝCompass以下面一些主要的接口作ؓ主要内容Q?br />
    * CompassConfigurationQ用来在一些设|参数、配|文件和映射定义上配|Compass。通常用来创徏Compass接口?br />     * CompassQؓ单线E用,创徏U程安全的实例来打开Compass Seesion。同栯提供了一些搜索引擎烦引别的操作?br />     * CompassSesssionQ用来执行像保存、删除、查找、装载这L搜烦操作。很轻量但是q不是线E安全的?br />     * CompassTransactionQ管理Compass事务的接口。用它q不需要事务管理环境(像Spring、JTAQ?br />
下面是用这些API的一个简单的例子Q?br />
// 在程序中配置和创建Compass
CompassConfiguration conf =
     new CompassConfiguration().setConnection("/tmp/index").addClass(Author.class);
Compass compass = conf.buildCompass();

  // 一个请求操?br /> CompassSession session = compass.openSession();
CompassTransaction tx = null;
try {
     tx = session.beginTransaction();
     ...
     session.save(author);
     CompassHits hits = session.find("jack london");
     Author a = (Author) hits.data(0);
     Resource r = hits.resource(0);
     ...
     tx.commit();
} catch (CompassException ce) {
     if (tx != null) tx.rollback();
} finally {
     session.close();
}

Z化事务管理代码,Compass提供了好几种选择Q首先是使用CompassTemplateQ它使用行的设计模式来抽象事务理。第二个选择是在和事务管理环境下Q这PCompass与JTA与Springq样的事务管理器集成q在一个已l存在的事务中执行。这个情况下Q当一?Session执行的时候,CompassSession 可被用做一个自动加入事务处理的代理。这个代理的创徏可以是编E式的,也可使用Spring IOCQSpring 2 中支持@CompassContextQ?br />
Compass支持原子性的事务q算Q与不同的事务管理策略集成,包括本地事务理、JTA同步、XA for JTA的集成,Spring同步的集成?br />
Compass的配|基?#8220;键—?#8221;的一一对应的设|。Compass可以使用~程式的配置Q基于XML DTD的配|(定义映射和设|)Q基于XML Schema的配|。基于XML Schema的配|得CSpring2新的ZSchema配置文g的支持?br /> 搜烦引擎映射

Compass的主要功能之一是从应用程序模型到搜烦引擎的声明式映射。Compass搜烦引擎的领域模型由资源QLucene DocumentQ和属性(一个Lucene FieldQ组成。这是用来烦引可搜烦内容的抽象数据对象?br /> RSEM

W一个映是RSEMQResource/SearchEngine MappingQ。这是一个低U别从Compass资源和属性到搜烦引擎抽象到搜索引擎的映射。下面是个对作者资源的RSEM的示例:

<resource alias="author">
    <resource-id name="id"/>
    <resource-property name="firstName"/>
    <resource-property name="lastName" store="yes" index="tokenized"/>
    <resource-property name="birthdate" converter="mydate"/>
  </resource>
  

上面的例子中Q我们定义了一个映了作者别名的资源。这个资源的映射包括标识资源的ID和几个附加的属性。定义属性是可选的Q尽他们允许声明式的控制不同属性的特征Q包括和一个{换器兌。下面的CZ代码填充了一个资源ƈ索引它?br />
Resource r = session.createResource("author");
  r.addProperty("id", "1")
    .addProperty("firstName", "jack")
    .addProperty("lastName", "london")
    .addProperty("birthdate", new Date());
  session.save(r);
  

上面的代码显CZ一些Compass的特性。第一Q由于一个资源是可识别的QCompass在这个资源已l存在的情况下更新它。第二,可以声明式的分配一个{换器l这个资源,可以使用Compass内置的许多{换器。下面是上面CZ代码的Compass配置Q包括对mydate转换器的配置Q:

<compass-core-config xmlns="http://www.opensymphony.com/compass/schema/core-config"
      xsi:schemaLocation="http://www.opensymphony.com/compass/schema/core-config
      http://www.opensymphony.com/comp ... ass-core-config.xsd">
    <compass name="default">
      <connection>
            <file path="index" />
      </connection>
      <converters>
        <converter name="mydate" type="org.compass.core.converter.basic.DateConverter">
          <setting name="format" value="yyyy-MM-dd" />
        </converter>
      </converters>
      <mappings>
        <resource location="sample/author.cpm.xml" />
      </mappings>
    </compass>
  </compass-core-config>
  

OSEM

OSEM(Object/Search Engine Mapping)是第二个支持的映方案。它允许把应用对象的领域模型映射到搜索引擎。下面是Authorc,使用注释对它q行了OSEM定义Q?br />
@Searchable
public class Author {

    @SearchableId
   private Long id;

    @SearchableComponent
   private String Name;

    @SearchableReference
   private List books;

    @SearchableProperty(format = "yyyy-MM-dd")
   private Date birthdate;
}

  // ...

@Searchable
public class Name {

    @SearchableProperty
   private String firstName;

    @SearchableProperty
   private String lastName;
}

OSEM支持“植入”?#8220;植出”一个对象的分层l构q入一个资源。当存储一个Author对象QCompass׃“植入”q一个资源,NamecM?#8220;植入”q相同的资源来表C个作者(׃lg的映)Q也包括一个这个作者书c列表里的每一本书Q存储在其他的资源里Q的引用。这个最后得到的资源会存储或者烦引在搜烦引擎中?br />
Compass提供了非常灵zȝ机制来把领域模型映射到搜索引擎中。上面的例子只是一个很单的例子。OSEM允许制定不同的{换器Q一个类属性对应多个元数据Q从资源到属性的映射Q、分析器和所有参与的字段Q等{?br />
下面是authorcL样使用的例子:

// ...
Author author = new Author(1, new Name("jack", "london"), new Date());
session.save(author);
// ...
author = (Author) session.load(Author.class, 1);

XSEM

最后,Compass支持的搜索引擎映是XSEM(Xml/Search Engine Mapping)。这U映允许基于XML映射的定义(用XPath实现Q,把XML数据l构直接映射到搜索引擎。XSEM的处理同L通过对资?#8220;植入”?#8220;植出”的处理。Compass提供了一个XML包装对象叫做XmlObjectQ它定义了不同的实现(dom4j, W3C Document)Q这些实现允许XPath表达式来求倹{如果我们给Z面的XML数据l构Q?br />
<xml-fragment>
    <author id="1">
      <firstName>Jack</firstName>
      <lastName>London</lastName>
    </author>
  </xml-fragment>
  

下面是个XSEM的实玎ͼ

<compass-core-mapping>
    <xml-object alias="author" xpath="/xml-fragment/author">
      <xml-id name="id" xpath="@id" />
      <xml-property xpath="firstName" />
      <xml-property xpath="lastName" />
      <xml-content name="content" />
    </xml-object>
  </compass-core-mapping>
  

从XML数据l构到搜索引擎的映射是用XPath表达式来完成。XML内容映射可以在搜索引擎中存储为XMLl构Q这样就可以加蝲和搜索数据?Compass支持多种XML DOM框架QؓXML内容作映)Q包括JSE5Q?dom4jQSAX 和XPPQ,当然定制的实C很好做。下面是个不错的例子Q?br />
Reader reader = // construct an xml reader over raw xml content
AliasedXmlObject xmlObj = RawAliasedXmlObject("author", reader);
session.save(xmlObj);
// ...
Resource resource = session.loadResource("author", 1);
// since we have xml-content, we can do the following as well
XmlObject xmlObj = session.load("author", 1);

Compass Gps

Compass Gps 是Compass的一个组Ӟ用来把不同的数据源与Compass集成。大部分常用的数据源是Compass与ORM工具的集成。Compass支持JPA、Hibernate、OJB、JDO和iBatis?br />
拿Hibernate作ؓ例子QCompassl出了两个主要的操作Q烦引与镜像。拥有这两个映射的对象可以通过使用Hibernate API注册旉监听Q进行自动的镜像操作到搜索引擎。下面的例子l出了怎样使用Compass Gps集成HibernateQ?br />
SessionFactory sessionFactory = // Hibernate Session Factory
Compass compass = // set up a Compass instance
CompassGps gps = new SingleCompassGps(compass);
CompassGpsDevice device = new Hibernate3GpsDevice("hibernate", sessionFactory);
gps.addDevice(device);
// start the gps, mirroring any changes made through Hibernate API
// to be mirrored to the search engine
gps.start();

  // ....

  // this will cause the database to be indexed
gps.index();
  // this will cause Hibernate to store the author in the database
  // and also index the author object through Compass
hibernateSess.save(new Author(1, new Name("jack", "london"), new Date()));


ȝ

q篇文章对Compass的主要功能的做了介绍Q但只是覆盖了怎样使用Compass的基本功能(其QCompassq有个与Spring集成的扩展组Ӟq个q没介绍Q。在使用搜烦引擎的时候,Compass同样也有很多现在行功能和有一些细微的差别功能Q还有配|扩展功能。Compass的主要目标,像刚才提到的Q是化集成搜索到Mcd的应用程序中Q这文章只是介l了怎么使用的基本信息?br />
个h收藏资料Q本文严重抄袭:http://bbs.51cto.com/thread-442091-1-1.html

]]>
lunece查询http://www.tkk7.com/szhswl/articles/166776.html宋针q?/dc:creator>宋针q?/author>Mon, 10 Dec 2007 11:51:00 GMThttp://www.tkk7.com/szhswl/articles/166776.htmlhttp://www.tkk7.com/szhswl/comments/166776.htmlhttp://www.tkk7.com/szhswl/articles/166776.html#Feedback0http://www.tkk7.com/szhswl/comments/commentRss/166776.htmlhttp://www.tkk7.com/szhswl/services/trackbacks/166776.html IndexSearcher search = new IndexSearcher(path);
//构徏Term
Term term = new Term(fieldName,value);
//构徏Query对象
Query q = new TermQuery(term);
//?br /> Hits hits = search.search(q);
//昄查询l果
for(int i=0; i<hits.length(); i++)
{
 System.out.println(hits.doc(i));
}

IndexSearcher的常用方法有
search(Query q);
search(Query q,Filter filter);
search(Query q,Sort sort);
search(Query q,Filter filter,Sort sort);

Hits的常用方法有
doc(i); //得到Wi个Document
id(i);  //得到Wi个Document在lucene文g中的id?br /> length(); //l果集的数量
score(i); //Wi个Doucment的文档得分,默认昄方式为scoreD高,排得前。score取?-1之间
如果x高score的倹{可以有建立索引时设|,用Field.setBoost(Float f)Ҏ
Field f = new Field(fieldname,value,store,tokenized);
f.setBoost(5f);

在lucene中,document ID 小Q查询时所需旉短Q因为Hits的内部缓存机制?/p>

Lunece的常用搜?/p>

一、TermQuery 词条搜烦
Query query = new TermQuery(new Term(fieldname,value));

二、BooleanQuery 布尔搜烦
建立二个TermQuery
Query q1 = new TermQuery(new Term(fieldname1,value1));
Query q2 = new TermQuery(new Term(fieldname2,value2));
建立BooleanQuery对象
BooleanQuery query = new BooleanQuery();
query.add(q1,BooleanClause.Occue.MUST);
query.add(q2,BooleanClause.Occue.MUST);
BooleanClause.Occue 有三个静态?br /> MUSTQMUST_NOTQSHOULD
must&&must = (AnB)
must&&must_not = (A-(AnB))
should&&should = (AuB)

三、RangeQuery 范围搜烦
RangeQuery query = new RangeQuery(begin,end,false);
begin = new Term(fieldname,value);
end = new Term(fieldname,value);
false 表示开区间 不包?(begin,end) true 表示闭区?包括 [begin,end]

四、PrefixQuery 前缀搜烦
PrefixQuery query = new PrefixQuery(new Term(fieldname,value));

五、PhraseQuery 短语搜烦
PhraseQuery query = new PhraseQuery();
query.add(new Term(fieldname,value));
query.add(new Term(fieldname,value));
q可以设|坡度,query.setSlop(int n),默认?如查?#8220;钢铁”Q可以用
query.add(new Term(fieldname,”?#8221;));
query.add(new Term(fieldname,”?#8221;));
如想?#8220;钢和?#8221;Q?#8220;钢与?#8221;也查询出来。可以加上query.setSlop(1);

六、MultiPhraseQuery 多短语搜?br /> MultiPhraseQuery query = new MultiPharseQuery();
//加入短语的前~
query.add(new Term(fieldname,value));
//加入短语的后~
query.add(new Term[] {new Term(fieldname,value), new Term(fieldname,value)});

七、FuzzyQuery 模糊搜烦
FuzzyQuery query = new FuzzyQuery(new Term(filed,value));
它的三个构造函?br /> FuzzyQuery(Term t);
FuzzyQuery(Term t,float 0.5f); 怼度?-1之间
FuzzyQuery(Term t,float 0.5f,int prefixLength);前缀必须相同的长?br />
本文转自:http://job5156.xicp.net/?p=72



]]>
Lucene的工作原?转蝲)http://www.tkk7.com/szhswl/articles/165817.html宋针q?/dc:creator>宋针q?/author>Thu, 06 Dec 2007 07:57:00 GMThttp://www.tkk7.com/szhswl/articles/165817.htmlhttp://www.tkk7.com/szhswl/comments/165817.htmlhttp://www.tkk7.com/szhswl/articles/165817.html#Feedback0http://www.tkk7.com/szhswl/comments/commentRss/165817.htmlhttp://www.tkk7.com/szhswl/services/trackbacks/165817.htmlLucene的概qͼ

  Lucene(发音?['lusen] )是一个非怼U的开源的全文搜烦引擎,我们可以在它的上面开发出各种全文搜烦的应用来。Lucene在国外有很高的知名度Q现在已l是Apache的顶U项目,在国内,Lucene的应用也来多?/p>

Lucene的算法原理:

  Lucene是一个高性能的java全文索工具包Q它使用的是倒排文g索引l构。该l构及相应的生成法如下Q?

 0Q设有两文??
   文章1的内容ؓQTom lives in Guangzhou,I live in Guangzhou too.
   文章2的内容ؓQHe once lived in Shanghai.

 1)全文分析Q由于lucene是基于关键词索引和查询的Q首先我们要取得q两文章的关键词,通常我们需要如下处理措?
  a.我们现在有的是文章内容,即一个字W串Q我们先要找出字W串中的所有单词,卛_词。英文单词由于用I格分隔Q比较好处理。中文单词间是连在一L需要特D的分词处理?
  b.文章中的”in”, “once” “too”{词没有什么实际意义,中文中的“?#8221;“?#8221;{字通常也无具体含义Q这些不代表概念的词可以qo?
  c.用户通常希望?#8220;He”时能把含“he”Q?#8220;HE”的文章也扑և来,所以所有单词需要统一大小写?
  d.用户通常希望?#8220;live”时能把含“lives”Q?#8220;lived”的文章也扑և来,所以需要把“lives”Q?#8220;lived”q原?#8220;live”
  e.文章中的标点W号通常不表C某U概念,也可以过滤掉
 在lucene中以上措施由Analyzercd?/font>

 l过上面处理?
  文章1的所有关键词为:[tom] [live] [guangzhou] [i] [live] [guangzhou]
  文章2的所有关键词为:[he] [live] [shanghai]

 2) 倒排索引Q有了关键词后,我们可以徏立倒排索引了。上面的对应关系是:“文章?#8221;?#8220;文章中所有关键词”。倒排索引把这个关pd过来,变成Q?#8220;关键?#8221;?#8220;拥有该关键词的所有文章号”?/font>文章1Q?l过倒排后变?
关键?文章?
  guangzhou 1
  he 2
  i 1
  live 1,2
  shanghai 2
  tom 1

  通常仅知道关键词在哪些文章中出现q不够,我们q需要知道关键词在文章中出现ơ数和出现的位置Q通常有两U位|:a)字符位置Q即记录该词是文章中W几个字W(优点是关键词亮显时定位快Q;b)关键词位|,卌录该词是文章中第几个关键词(优点是节U烦引空间、词l(phaseQ查询快Q,lucene中记录的是q种位置?

加上“出现频率”?#8220;出现位置”信息后,我们的烦引结构变为: 

 

 

 关键?/td>  文章?/td>  [出现频率]  出现位置
 guangzhou  1  [2]  3Q?
 he  2  [1]  1
 i  1  [1]  4
 live  1  [2]  2Q?
   2  [1]  2
 shanghai  2  [1]  3
 tom  1  [1]  1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  以live q行Z我们说明一下该l构Qlive在文?中出C2ơ,文章2中出C一ơ,它的出现位置?#8220;2,5,2”q表CZ么呢Q我们需要结合文章号和出现频率来分析Q文?中出C2ơ,那么“2,5”pClive在文?中出现的两个位置Q文?中出C一ơ,剩下?#8220;2”pClive是文?中第 2个关键字?
  以上是lucene索引l构中最核心的部分。我们注意到关键字是按字W顺序排列的Qlucene没有使用B树结构)Q?/font>因此lucene可以?font color="#008080">二元搜烦法快速定位关键词?
  实现?lucene上面三列分别作?font color="#800000">词典文g
QTerm DictionaryQ?font color="#800000">频率文g
(frequencies)?font color="#800000">位置文g (positions)保存。其?font color="#008080">词典文g不仅保存有每个关键词Q还保留了指向频率文件和位置文g的指针,通过指针可以扑ֈ该关键字的频率信息和位置信息?

  Lucene中用了field的概念,用于表达信息所在位|(如标题中Q文章中Qurl中)Q?/font>在徏索引中,?font color="#008080">field信息也记录在词典文g?/font>Q每个关键词都有一个field信息(因ؓ每个关键字一定属于一个或多个field)?
  Z减小索引文g的大,Lucene对烦引还使用?font color="#800000">压羃技?/font>。首先,对词典文件中的关键词q行了压~,关键词压~ؓ<前缀长度Q后~>Q例如:当前词ؓ“阿拉伯语”Q上一个词?#8220;阿拉?#8221;Q那?#8220;阿拉伯语”压羃?lt;3Q语>。其ơ大量用到的是对数字的压~,数字只保存与上一个值的差|q样可以减小数字的长度,q而减保存该数字需要的字节敎ͼ。例如当前文章号?6389Q不压羃要用3个字节保存)Q上一文章h16382Q压~后保存7Q只用一个字节)?注意?#8220;上一个词”。由于词典是按顺序排列的Q这U压~方法的效果会非常显著?/font>

  下面我们可以通过对该索引的查询来解释一下ؓ什么要建立索引?
假设要查询单?“live”Qlucene先对词典二元查找、找到该词,通过指向频率文g的指针读出所有文章号Q然后返回结果。词兔R常非常,因而,整个q程的时间是毫秒U的?
而用普通的序匚w法Q不建烦引,而是Ҏ有文章的内容q行字符串匹配,q个q程会相当~慢Q当文章数目很大Ӟ旉往往是无法忍受的?/p>

全文索框架的实现机制Q?/strong>

  Lucene的API接口设计的比较通用Q输入输出结构都很像数据库的?=>记录==>字段Q所以很多传l的应用的文件、数据库{都可以比较方便的映到Lucene的存储结?接口中。M上看Q可以先把Lucene当成一个支持全文烦引的数据库系l?/p>

比较一下Lucene和数据库Q?/p>

 

 Lucene  数据?/td>

 索引数据源:doc(field1,field2...) doc(field1,field2...) 

            \  indexer /
        _____________
        | Lucene Index |
            --------------
           / searcher \

l果输出QHits(doc(field1,field2) doc(field1...))

 索引数据源:record(field1,field2...) record(field1..)  

            \  SQL: insert/ 
          _____________
           |   DB  Index   |
               ------------- 
            / SQL: select \

l果输出Qresults(record(field1,field2..) record(field1...))

 DocumentQ一个需要进行烦引的“单元,一个Document由多个字D늻?

 RecordQ记录,包含多个字段

FieldQ字D?/p>

FieldQ字D?/td>

HitsQ查询结果集Q由匚w的Documentl成

 RecordSetQ查询结果集Q由多个Recordl成

全文?≠ like "%keyword%"

  ׃数据库烦引不是ؓ全文索引设计的,因此Q用like "%keyword%"Ӟ数据库烦引是不v作用的,在用like查询Ӟ搜烦q程又变成类g一页M的遍历过E了Q所以对于含有模p查询的数据库服务来_LIKEҎ能的危x极大的。如果是需要对多个关键词进行模p匹配:like"%keyword1%" and like "%keyword2%" ...其效率也可惌知了?/p>

  通常比较厚的书籍后面常常附关键词索引表(比如Q北京:12, 34,上vQ?,77?#8230;…Q,它能够帮助读者比较快地找到相兛_容的늠。而数据库索引能够大大提高查询的速度原理也是一P惛_一下通过书后面的索引查找的速度要比一一地d定w多少?#8230;…而烦引之所以效率高Q另外一个原因是它是排好序的。对于检索系l来说核心是一个排序问题?/p>

  所以徏立一个高效检索系l的关键是徏立一个类gU技索引一L反向索引机制Q将数据源(比如多篇文章Q排序顺序存储的同时Q有另外一个排好序的关键词列表Q用于存储关键词==>文章映射关系Q利用这L映射关系索引Q[关键?=>出现关键词的文章~号Q出现次敎ͼ甚至包括位置Qv始偏U量Q结束偏U量Q,出现频率]Q检索过E就是把模糊查询变成多个可以利用索引的精查询的逻辑l合的过E。从而大大提高了多关键词查询的效率,所以,全文索问题归l到最后是一个排序问题?/p>

  由此可以看出模糊查询相对数据库的_查询是一个非怸定的问题,q也是大部分数据库对全文索支持有限的原因。Lucene最核心的特征是通过Ҏ的烦引结构实C传统数据库不擅长的全文烦引机Ӟq提供了扩展接口Q以方便针对不同应用的定制?/p>

  可以通过一下表格对比一下数据库的模p查询:

 

   Lucene全文索引引擎  数据?/td>
 索引  数据源中的数据都通过全文索引一一建立反向索引  对于LIKE查询来说Q数据传l的索引是根本用不上的。数据需要逐个便利记录q行GREP式的模糊匚wQ比有烦引的搜烦速度要有多个数量U的下降?/td>
 匚w效果  通过词元(term)q行匚wQ通过语言分析接口的实玎ͼ可以实现对中文等非英语的支持?/td>  使用Qlike "%net%" 会把netherlands也匹配出来,
多个关键词的模糊匚wQ用like "%com%net%"Q就不能匚w词序颠倒的xxx.net..xxx.com
 匚w?/td>  有匹配度法Q将匚wE度Q相似度Q比较高的结果排在前面?/td>  没有匚wE度的控Ӟ比如有记录中net出现5词和出现1ơ的Q结果是一L
 l果输出  通过特别的算法,最匚w度最高的?00条结果输出,l果集是~冲式的批量读取的?/td>  q回所有的l果集,在匹配条目非常多的时候(比如上万条)需要大量的内存存放q些临时l果集?/td>
 可定制?/td>  通过不同的语a分析接口实现Q可以方便的定制出符合应用需要的索引规则Q包括对中文的支持)  没有接口或接口复杂,无法定制
 l论  高负载的模糊查询应用Q需要负责的模糊查询的规则,索引的资料量比较?/td>  使用率低Q模p匹配规则简单或者需要模p查询的资料量少

全文索和数据库应用最大的不同在于Q让最相关?/span> ?00条结果满?8%以上用户的需求?/font>
Lucene的创C处:

  大部分的搜烦Q数据库Q引擎都是用B树结构来l护索引Q烦引的更新会导致大量的IO操作QLucene在实CQ对此稍微有所改进Q不是维护一个烦引文Ӟ而是在扩展烦引的时候不断创建新的烦引文Ӟ然后定期的把q些新的烦引文件合q到原先的大索引中(针对不同的更新策略,Ҏ的大可以调_Q这样在不媄响检索的效率的前提下Q提高了索引的效率?/p>

Lucene和其他一些全文检索系l?应用的比较:

 

   Lucene  其他开源全文检索系l?/td>
 增量索引和批量烦?/td>  可以q行增量的烦?Append)Q可以对于大量数据进行批量烦引,q且接口设计用于优化扚w索引和小扚w的增量烦引?/td>  很多pȝ只支持批量的索引Q有时数据源有一点增加也需要重建烦引?/td>
 数据?/td>  Lucene没有定义具体的数据源Q而是一个文档的l构Q因此可以非常灵zȝ适应各种应用Q只要前端有合适的转换器把数据源{换成相应l构Q?/td>  很多pȝ只针对网,~Z其他格式文档的灵zL?/td>
 索引内容抓取  Lucene的文档是由多个字D늻成的Q甚臛_以控刉些字D需要进行烦引,那些字段不需要烦引,q一步烦引的字段也分为需要分词和不需要分词的cdQ?br />    需要进行分词的索引Q比如:标题Q文章内容字D?br />    不需要进行分词的索引Q比如:作?日期字段  ~Z通用性,往往文档整个烦引了
 语言分析  通过语言分析器的不同扩展实现Q?br /> 可以qo掉不需要的词:an the of {,
西文语法分析Q将jumps jumped jumper都归l成jumpq行索引/?br /> 非英文支持:对亚z语aQ阿拉伯语言的烦引支?/td>
 ~Z通用接口实现
 查询分析  通过查询分析接口的实玎ͼ可以定制自己的查询语法规则:
比如Q?多个关键词之间的 + - and or关系{?/td>
 功能较强?/td>
 q发讉K  能够支持多用L使用  功能较强?/td>

关于亚洲语言的的切分词问?Word Segment)
  对于中文来说Q全文烦引首先还要解决一个语a分析的问题,对于英文来说Q语句中单词之间是天焉过I格分开的,但亚z语a的中日韩文语句中的字是一个字挨一个,所有,首先要把语句中按“?#8221;q行索引的话Q这个词如何切分出来是一个很大的问题?br />   首先Q肯定不能用单个字符?si-gram)为烦引单元,否则?#8220;上v”Ӟ不能让含?#8220;上”也匹配?br /> 但一句话Q?#8220;北京天安?#8221;Q计机如何按照中文的语a习惯q行切分呢?
  “北京 天安?#8221; q是“??天安?#8221;Q让计算够按照语a习惯q行切分Q往往需要机器有一个比较丰富的词库才能够比较准的识别句中的单词?br />   另外一个解决的办法是采用自动切分算法:单词按?元语?bigram)方式切分出来Q比如:
    "北京天安? ==> "北京 京天 天安 安门"?br /> q样Q在查询的时候,无论是查?北京" q是查询"天安?Q将查询词组按同L规则q行切分Q?北京"Q?天安安门"Q多个关键词之间按与"and"的关pȝ合,同样能够正确地映到相应的烦引中。这U方式对于其他亚z语aQ韩文,日文都是通用的?br />   Z自动切分的最大优Ҏ没有词表l护成本Q实现简单,~点是烦引效率低Q但对于中小型应用来_Z2元语法的切分q是够用的。基?元切分后的烦引一般大和源文件差不多Q而对于英文,索引文g一般只有原文g?0%-40%不同?

   自动切分  词表切分
 实现  实现非常?/td>  实现复杂
 查询  增加了查询分析的复杂E度  适于实现比较复杂的查询语法规?/td>
 存储效率  索引冗余大,索引几乎和原文一样大  索引效率高,为原文大的30Q左?/td>
 l护成本  无词表维护成?/td>  词表l护成本非常高:中日韩等语言需要分别维护?br /> q需要包括词频统计等内容
 适用领域  嵌入式系l:q行环境资源有限
分布式系l:无词表同步问?br /> 多语a环境Q无词表l护成本
 Ҏ询和存储效率要求高的专业搜烦引擎

目前比较大的搜烦引擎的语a分析法一般是Z以上2个机制的l合。关于中文的语言分析法Q大家可以在Google查关键词"wordsegment search"能找到更多相关的资料?/p>

Lucene的结构框Ӟ
  注意QLucene中的一些比较复杂的词法分析是用JavaCC生成的(JavaCCQJavaCompilerCompilerQ纯Java的词法分析生成器Q,所以如果从源代码编译或需要修改其中的QueryParser、定制自q词法分析器,q需要从https://javacc.dev.java.net/下蝲javacc?br />   lucene的组成结构:对于外部应用来说索引模块(index)和检索模?search)是主要的外部应用入口?

 org.apache.Lucene.search/  搜烦入口
 org.apache.Lucene.index/  索引入口
 org.apache.Lucene.analysis/  语言分析?/td>
 org.apache.Lucene.queryParser/ 查询分析?/td>
 org.apache.Lucene.document/  存储l构
 org.apache.Lucene.store/   底层IO/存储l构
 org.apache.Lucene.util/  一些公用的数据l构

从Lucene学到更多Q?/strong>
  Luene的确是一个面对对象设计的典范?/p>

  1. 所有的问题都通过一个额外抽象层来方便以后的扩展和重用:你可以通过重新实现来达到自q目的Q而对其他模块而不需要;
  2. 单的应用入口Searcher, IndexerQƈ调用底层一pdlg协同的完成搜索Q务;
  3. 所有的对象的Q务都非常专一Q比如搜索过E:QueryParser分析查询语句{换成一pd的精查询的l合(Query),通过底层的烦引读取结构IndexReaderq行索引的读取,q用相应的打分器l搜索结果进行打?排序{。所有的功能模块原子化程度非帔RQ因此可以通过重新实现而不需要修改其他模块?nbsp;
  4. 除了灉|的应用接口设计,Luceneq提供了一些适合大多数应用的语言分析器实玎ͼSimpleAnalyser,StandardAnalyserQ,q也是新用户能够很快上手的重要原因之一?


q些优点都是非常值得在以后的开发中学习借鉴的。作Z个通用工具包,Lunece的确l予了需要将全文索功能嵌入到应用中的开发者很多的便利?br />   此外Q通过对Lucene的学习和使用Q我也更深刻地理解了Z么很多数据库优化设计中要求,比如Q?/p>

  1. 可能对字段q行索引来提高查询速度Q但q多的烦引会Ҏ据库表的更新操作变慢Q而对l果q多的排序条Ӟ实际上往往也是性能的杀手之一?
  2. 很多商业数据库对大批量的数据插入操作会提供一些优化参敎ͼq个作用和烦引器的merge_factor的作用是cM的?
  3. 20%/80%原则Q查的结果多q不{于质量好,其对于q回l果集很大,如何优化q头几十条结果的质量往往才是最重要的?
  4. 可能让应用从数据库中获得比较小的结果集Q因为即使对于大型数据库Q对l果集的随机讉K也是一个非常消耗资源的操作?

本文转自Q?a >http://www.chedong.com/tech/lucene.html



]]>
lucene全文索应用示例及代码?/title><link>http://www.tkk7.com/szhswl/articles/165592.html</link><dc:creator>宋针q?/dc:creator><author>宋针q?/author><pubDate>Wed, 05 Dec 2007 09:08:00 GMT</pubDate><guid>http://www.tkk7.com/szhswl/articles/165592.html</guid><wfw:comment>http://www.tkk7.com/szhswl/comments/165592.html</wfw:comment><comments>http://www.tkk7.com/szhswl/articles/165592.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/szhswl/comments/commentRss/165592.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/szhswl/services/trackbacks/165592.html</trackback:ping><description><![CDATA[     摘要: 使用Lucene实现全文索,主要有下面三个步骤:   1、徏立烦引库Q根据网站新M息库中的已有的数据资料徏立Lucene索引文g?  2、通过索引库搜索:有了索引后,卛_使用标准的词法分析器或直接的词法分析器实现进行全文检索?  3、维护烦引库Q网站新M息库中的信息会不断的变动Q包括新增、修改及删除{,q些信息的变动都需要进一步反映到Lucene索引文g中? &nbs...  <a href='http://www.tkk7.com/szhswl/articles/165592.html'>阅读全文</a><img src ="http://www.tkk7.com/szhswl/aggbug/165592.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/szhswl/" target="_blank">宋针q?/a> 2007-12-05 17:08 <a href="http://www.tkk7.com/szhswl/articles/165592.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>LUCENE单实?/title><link>http://www.tkk7.com/szhswl/articles/165589.html</link><dc:creator>宋针q?/dc:creator><author>宋针q?/author><pubDate>Wed, 05 Dec 2007 09:04:00 GMT</pubDate><guid>http://www.tkk7.com/szhswl/articles/165589.html</guid><wfw:comment>http://www.tkk7.com/szhswl/comments/165589.html</wfw:comment><comments>http://www.tkk7.com/szhswl/articles/165589.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/szhswl/comments/commentRss/165589.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/szhswl/services/trackbacks/165589.html</trackback:ping><description><![CDATA[     摘要: lucene的简单实?lt;一> 关键?   lucene     说明一?q一文章的用到的lucene,是用2.0版本?主要在查询的时?.0版本的lucene与以前的版本有了一些区? 其实q一些代码都是早几个月写?自己很懒,所以到今天才写到自q博客?高深的文章自己写不了Q只能记录下一些简单的记录?..  <a href='http://www.tkk7.com/szhswl/articles/165589.html'>阅读全文</a><img src ="http://www.tkk7.com/szhswl/aggbug/165589.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/szhswl/" target="_blank">宋针q?/a> 2007-12-05 17:04 <a href="http://www.tkk7.com/szhswl/articles/165589.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.tkk7.com/" title="亚洲av成人片在线观看">亚洲av成人片在线观看</a> <div class="friend-links"> </div> </div> </footer> վ֩ģ壺 <a href="http://sjkuaixun.com" target="_blank">ëƬëƬַ</a>| <a href="http://6123fa.com" target="_blank">ѹۿƵ</a>| <a href="http://yw5168.com" target="_blank">ۺ</a>| <a href="http://4794d.com" target="_blank">椸ѹۿƵ</a>| <a href="http://zjhmpaper.com" target="_blank">ҹƬ߹ۿ</a>| <a href="http://333uy.com" target="_blank">ŮƵվ</a>| <a href="http://yinyinai155.com" target="_blank">þþþѿaԿ</a>| <a href="http://dazngt.com" target="_blank">޹Ʒþþ</a>| <a href="http://zz1220.com" target="_blank">aѹۿþav</a>| <a href="http://xixidhw.com" target="_blank">AVŷAVվ</a>| <a href="http://yamashida.com" target="_blank">ܳƵѹۿ</a>| <a href="http://44g8.com" target="_blank">ӰԺ</a>| <a href="http://6789311.com" target="_blank">޾Ʒ߹ۿ</a>| <a href="http://ywjh666.com" target="_blank">պ</a>| <a href="http://wwwabxx.com" target="_blank">67194ֻѹۿ</a>| <a href="http://wwwv27.com" target="_blank">þþƷ</a>| <a href="http://pufenghotel.com" target="_blank">ĻmvѸ</a>| <a href="http://www16am8.com" target="_blank">߹ۿ</a>| <a href="http://51wdn.com" target="_blank">ѹۿëƬվ</a>| <a href="http://zddzbp.com" target="_blank">ɫۺϽѹۿ </a>| <a href="http://jhc2go.com" target="_blank">ҹҹҹҹƵ </a>| <a href="http://557265.com" target="_blank">ҹƷ</a>| <a href="http://jhc2go.com" target="_blank">AVƬ߹ۿ</a>| <a href="http://k8h9.com" target="_blank">Ļ߹ۿ</a>| <a href="http://yy1514.com" target="_blank">һػɫƬ߹ۿ</a>| <a href="http://qihongxia.com" target="_blank">ֱƵ</a>| <a href="http://3333kkkk.com" target="_blank">޹Ʒþþþ</a>| <a href="http://hyhtzh.com" target="_blank">½һëƬƵۿi</a>| <a href="http://gz-shunan.com" target="_blank">̱߳ˬƵվ</a>| <a href="http://xxxxnii.com" target="_blank">ɫ޾ƷĻ</a>| <a href="http://ywgj50225.com" target="_blank">Ļݺ</a>| <a href="http://ywzms.com" target="_blank">vaһ</a>| <a href="http://www-33758.com" target="_blank">www޾Ʒþþձ</a>| <a href="http://hkcdk.com" target="_blank">ѿһ</a>| <a href="http://adcaes.com" target="_blank">avƷר߹ۿ </a>| <a href="http://adcacs.com" target="_blank">ޙպ߶</a>| <a href="http://mangaou.com" target="_blank">ÿµavƬ߹ۿ</a>| <a href="http://35633487.com" target="_blank">һҺ</a>| <a href="http://www-01313.com" target="_blank">һƵ߲ </a>| <a href="http://bzzxyp.com" target="_blank">ɫƵѹۿ</a>| <a href="http://139699.com" target="_blank">ҹþþþƷӰԺ</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>