快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

和记娱棒h88285:在应用中加入全文检索功能基于Java的全文索引引擎Lucene简介



在利用中加入全文检索功能

??基于Java的全文索引引擎Lucene简介

作者: 车东 chedong@bigfoot.com

着末更新: 02/13/2003 12:48:05

版权声明:可以随意率性转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本声明

http://www.chedong.com/tech/lucene.html

关键词:Lucene java full-text search engine Chinese word segment

内容择要:

Lucene是一个基于Java的全文索引对象包。

基于Java的全文索引引擎Lucene简介:关于作者和Lucene的历史

全文检索的实现:Luene全文索引和数据库索引的对照

中文切分词机制简介:基于词库和自动切分词算法的对照

详细的安装和应用简介:系统布局先容和演示

Hacking Lucene:简化的查询阐发器,删除的实现,定制的排序,利用接口的扩展

从Lucene我们还可以学到什么

基于Java的全文索引/检索引擎??Lucene

Lucene不是一个完备的全文索引利用,而是是一个用Java写的全文索引引擎对象包,它可以方便的嵌入到各类利用中实现针对利用的全文索引/检索功能。

Lucene的作者:Lucene的供献者Doug Cutting是一位资深全文索引/检索专家,曾经是V-Twin搜索引擎(Apple的Copland操作系统的成绩之一)的主要开拓者,后在Excite担负高档系统架构设计师,今朝从事于一些INTERNET底层架构的钻研。他供献出的Lucene的目标是为各类中小型利用法度榜样加入全文检索功能。

Lucene的成长过程:起初宣布在作者自己的www.lucene.com,后来宣布在SourceForge,2001年事尾成为APACHE基金会jakarta的一个子项目:http://jakarta.apache.org/lucene/

已经有很多Java项目都应用了Lucene作为其后台的全文索引引擎,对照闻名的有:

Jive:WEB论坛系统;

Eyebrows:邮件列表HTML归档/浏览/查询系统,本文的主要参考文档“The Lucene search engine: Powerful, flexible, and free”作者便是EyeBrows系统的主要开拓者之一,而EyeBrows已经成为今朝APACHE和记娱棒h88285项目的主要邮件列表归档系统。

Cocoon: 基于XML的web宣布框架,全文检索部分应用了Lucene

Eclipse: 基于Java的开摊开拓平台,赞助部分的全文索引应用了Lucene

对付中文用户来说,最关心的问题是其是否支持中文的全文检索。但经由过程后面对付Lucene的布局的先容,你会懂得到因为Lucene优越架构设计,对中文的支持只需对其说话词法阐发接口进行扩展就能实现对中文检索的支持。

全文检索的实现机制

Lucene的API接口设计的对照通用,输入输出布局都很像数据库的表==>记录==>字段,以是很多传统的利用的文件、数据库等都可以对照方便的映射到Lucene的存储布局/接口中。总体上看:可以先把Lucene当成一个支持全文索引的数据库系统。

对照一下Lucene和数据库:

Lucene 数据库

索引数据源: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...))

Document:一个必要进行索引的“单元”

一个Document由多个字段组成 Record:记录,包孕多个字段

Field:字段 Field:字段

Hits:查询结果集,由匹配的Document组成 RecordSet:查询结果集,由多个Record组成

全文检索 ≠ like "%keyword%"

平日对照厚的册本后面经常附关键词索引表(比如:北京:12, 34页, 上海:3, 77页……),它能够赞助读者对照快地找到相关内容的页码。而数据库索引能够大年夜大年夜前进查询的速率道理也是一样,想像一下经由过程书后面的索引查找的速率要比一页一页地翻内容高若干倍……而索引之以是效率高,别的一个缘故原由是它是排好序的。对付检索系统来说核心是一个排序问题。

因为数据库索引不是为全文索引设计的,是以,应用like "%keyword%"时,数据库索引是不起感化的,在应用like查询时,搜索历程又变成类似于一页页翻书的遍历历程了,以是对付含有隐隐查询的数据库办事来说,LIKE对机能的迫害是极大年夜的。假如是必要对多个关键词进行隐隐匹配:like "%keyword1%" and like "%keyword2%" ...其效率也就可想而知了。

以是建立一个高效检索系统的关键是建立一个类似于科技索引一样的反向索引机制,将数据源(比如多篇文章)排序顺序存储的同时,有别的一个排好序的关键词列表,用于存储关键词==>文章映射关系,使用这样的映射关系索引:[关键词==>呈现关键词的文章编号,呈现次数(以致包括位置:肇端偏移量,停止偏移量),呈现频率],检索历程便是把隐隐查询变成多个可以使用索引的正确查询的逻辑组合的历程。从而大年夜大年夜前进了多关键词查询的效率,以是,全文检索问题归结到着末是一个排序问题。

由此可以看出隐隐查询相对数据库的正确查询是一个异常不确定的问题,这也是大年夜部分数据库对全文检索支持有限的缘故原由。Lucene最核心的特性是经由过程特殊的索引布局实现了传统数据库不长于的全文索引机制,并供给了扩展接口,以方便针对不合利用的定制。

可以经由过程一下表格比较一下数据库的隐隐查询:

Lucene全文索引引擎 数据库

索引 将数据源中的数据都经由过程全文索引逐一建立反向索引 对付LIKE 查询来说,数据传统的索引是根本用不上的。数据必要逐个便利记录进行GREP式的隐隐匹配,比有索引的搜索速率要有多个数量级的下降。

匹配效果 经由过程词元(term)进行匹配,经由过程说话阐发接口的实现,可以实现对中文等非英语的支持。 应用:like "%net%" 会把netherlands也匹配出来,

多个关键词的隐隐匹配:应用like "%com%net%":就不能匹配词序倒置的xxx.net..xxx.com

匹配度 有匹配度算法,将匹配程度(相似度)对照高的结果排在前面。 没有匹配程度的节制:比如有记录中net呈现5词和呈现1次的,结果是一样的。

结果输出 经由过程特其余算法,将最匹配度最高的头100条结果输出,结果集是缓冲式的小批量读取的。 返回所有的结果集,在匹配条款异常多的时刻(比如上万条)必要大年夜量的内存寄放这些临时结果集。

可定制性 经由过程不合的说话阐发接口实现,可以方便的定制出相符利用必要的索引规则(包括对中文的支持) 没有接口或接口繁杂,无法定制

结论 高负载的隐隐查询利用,必要认真的隐隐查询的规则,索引的资料量对照大年夜 应用率低,隐隐匹配规则简单或者必要隐隐查询的资料量少

全文检索和数据库利用最大年夜的不合在于:让最相关的头100条结果满意98%以上用户的需求

Lucene的立异之处:

大年夜部分的搜索(数据库)引擎都是用B树布局来掩护索引,索引的更新会导致大年夜量的IO操作,Lucene在实现中,对此轻细有所改进:不是掩护一个索引文件,而是在扩展索引的时刻赓续创建新的索引文件,然后按期的把这些新的小索引文件合并到本来的大年夜索引中(针对不合的更新策略,批次的大年夜小可以调剂),这样在不影响检索的效率的条件下,前进了索引的效率。

Lucene和其他一些全文检索系统/利用的对照:

Lucene 其他开源全文检索系统

增量索引和批量索引 可以进行增量的索引(Append),可以对付大年夜量数据进行批量索引,并且接口设计用于优化批量索引和小批量的增量索引。 很多系统只支持批量的索引,无意偶尔数据源有一点增添也必要重修索引。

数据源 Lucene没有定义详细的数据源,而是一个文档的布局,是以可以异常机动的适应各类利用(只要前端有相宜的转换器把数据源转换成响应布局), 很多系统只针对网页,短缺其他款式文档的机动性。

索引内容抓取 Lucene的文档是由多个字段组成的,以致可以节制那些字段必要进行索引,那些字段不必要索引,近一步索引的字段也分为必要分词和不必要分词的类型:

必要进行分词的索引,比如:标题,文章内容字段

不必要进行分词的索引,比如:作者/日期字段 短缺通用性,每每将文档全部索引了

说话阐发 经由过程说话阐发器的不合扩展实现:

可以过滤掉落不必要的词:an the of 等,

西文语法阐发:将jumps jumped jumper都归结成jump进行索引/检索

非英文支持:对亚洲说话,阿拉伯说话的索引支持 短缺通用接口实现

查询阐发 经由过程查询阐发接口的实现,可以定制自己的查询语律例则:

比如: 多个关键词之间的 + - and or关系等

并发造访和记娱棒h88285 能够支持多用户的应用

关于亚洲说话的的切分词问题(Word Segment)

对付中文来说,全文索引首先还要办理一个说话阐发的问题,对付英文来说,语句中单词之间是天然经由过程空格分开的,但亚洲说话的中日韩文语句中的字是一个字挨一个,所有,首先要把语句中按“词”进行索引的话,这个词若何切分出来便是一个很大年夜的问题。

首先,肯定不能用单个字符作(si-gram)为索引单元,否则查“上海&和记娱棒h88285rdquo;时,不能让含有“海上”也匹配。

但一句话:“北京天安门”,谋略机若何按照中文的说话习气进行切分呢?

“北京 天安门” 照样“北 京 天安门”?让谋略性能够按照说话习气进行切分,每每必要机械有一个对照和记娱棒h88285富厚的词库才能够对照准确的识别出语句中的单词。

别的一个办理的法子是采纳自动切分算法:将单词按照2元语法(bigram)要领切分出来,比如:

"北京天安门" ==> "北京 京天 天安 安门"。

这样,在查询的时刻,无论是查询"北京" 照样查询"天安门",将查询词组按同样的规则进行切分:"北京","天安安门",多个关键词之间按与"and"的关系组合,同样能够精确地映射到响应的索引中。这种要领对付其他亚洲说话:韩文,日文都是通用的。

基于自动切分的最大年夜优点是没有词表掩护资源,实现简单,毛病是索引效率低,但对付中小型利用来说,基于2元语法的切分照样够用的。基于2元切分后的索引一样平常大年夜小和源文件差不多,而对付英文,索引文件一样平常只有原文件的30%-40%不合,

自动切分 词表切分

实现 实现异常简单 实现繁杂

查询 增添了查询阐发的繁杂程度, 适于实现对照繁杂的查询语律例则

存储效率 索引冗余大年夜,索引险些和原文一样大年夜 索引效率高,为原文大年夜小的30%阁下

掩护资源 无词表掩护资源 词表掩护资源异常高:中日韩等说话必要分手掩护。

还必要包括词频统计等内容

适用领域 嵌入式系统:运行情况资本有限

散播式系统:无词表同步问题

多说话情况:无词表掩护资源 对查询和存储效率要求高的专业搜索引擎

今朝对照大年夜的搜索引擎的说话阐发算法一样平常是基于以上2个机制的结合。关于中文的说话阐发算法,大年夜家可以在Google查关键词"word segment search"能找到更多相关的资料。

安装和应用

下载:http://jakarta.apache.org/lucene/

留意:Lucene中的一些对照繁杂的词法阐发是用JavaCC天生的(JavaCC:Java Compiler Compiler,纯Java的词法阐产天生器),以是假如从源代码编译或必要改动此中的QueryParser、定制自己的词法阐发器,还必要从http://www.webgain.com/products/java_cc/下载javacc。

lucene的组成布局:对付外部利用来说索引模块(index)和检索模块(search)是主要的外部利用进口

org.apache.Lucene.search/ 搜索进口

org.apache.Lucene.index/ 索引进口

org.apache.Lucene.analysis/ 说话阐发器

org.apache.Lucene.queryParser/ 查询阐发器

org.apache.Lucene.document/ 存储布局

org.apache.Lucene.store/ 底层IO/存储布局

org.apache.Lucene.util/ 一些公用的数据布局

简单的例子演示一下Lucene的应用措施:

索引历程:从敕令行读取文件名(多个),将文件分路径(path字段)和内容(body字段)2个字段进行存储,并对内容进行全文索引:索引的单位是Document工具,每个Document工具包孕多个字段Field工具,针对不合的字段属性和数据输出的需求,对字段还可以选择不合的索引/存储字段规则,列表如下: 措施 切词 索引 存储 用途

Field.Text(String name, String value) Yes Yes Yes 切分词索引并存储,比如:标题,内容字段

Field.Text(String name, Reader value) Yes Yes No 切分词索引不存储,比如:META信息,

不用于返回显示,但必要进行检索内容

Field.Keyword(String name, String value) No Yes Yes 不切分索引并存储,比如:日期字段

Field.UnIndexed(String name, String value) No No Yes 不索引,只存储,比如:文件路径

Field.UnStored(String name, String value) Yes Yes No 只全文索引,不存储

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; iField中的内容。

假设根据body字段进行全文检索,可以将查询结果的path字段和响应查询的匹配度(score)打印出来,

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 ":"] (| "(和记娱棒h88285" Query ")" )

中心的逻辑包括:and or + - && ||等符号,而且还有"短语查询"和针对西文的前缀/隐隐查询等,小我感到对付一样平常利用来说,这些功能有一些华而不实,着实能够实现今朝类似于Google的查询语句阐发功能着实对付大年夜多半用户来说已经够了。以是,Lucene早期版本的QueryParser仍是对照好的选择。

添加改动删除指定记录(Document)

Lucene供给了索引的扩展机制,是以索引的动态扩展应该是没有问题的,而指定记录的改动也彷佛只能经由过程记录的删除,然后从新加入实现。若何删除指定的记录呢?删除的措施也很简单,只是必要在索引时根据数据源中的记录ID专门另建索引,然后使用IndexReader.delete(Term term)措施经由过程这个记录ID删除响应的Document。

根据某个字段值的排序功能

lucene缺省是按照自己的相关度算法(score)进行结果排序的,但能够根据其他字段进行结果排序是一个在LUCENE的开拓邮件列表中常常提到的问题,很多本来基于数据库利用都必要除了基于匹配度(score)以外的排序功能。而从全文检索的道理我们可以懂得到,任何不基于索引的搜索历程效率都邑导致效率异常的低,假如基于其他字段的排序必要在搜索历程中造访存储字段,速率回大年夜大年夜低落,是以异常是弗成取的。

但这里也有一个折中的办理措施:在搜索历程中能够影响排序结果的只有索引中已经存储的docID和score这2个参数,以是,基于score以外的排序,着实可以经由过程将数据源预先排好序,然后根据docID进行排序来实现。这样就避免了在LUCENE搜索结果外对结果再次进行排序和在搜索历程中造访不在索引中的某个字段值。

这里必要改动的是IndexSearcher中的HitCollector历程:

... scorer.score(new HitCollector() { private float minScore = 0.0f; public final void collect(int doc, float score) { if (score > 0.0f && // ignore zeroed buckets (bits==null || bits.get(doc))) { // skip docs not in bits totalHits[0]++; if (score >= 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() > nDocs) { // if hit queue overfull hq.pop(); // remove lowest in hit queue minScore = ((ScoreDoc)hq.top()).score; // reset minScore } } } } }, reader.maxDoc());

更通用的输入输出接口

虽然lucene没有定义一个确定的输入文档款式,但越来越多的人想到应用一个标准的中心款式作为Lucene的数据导入接口,然后其他数据,比如PDF只必要经由过程解析器转换成标准的中心款式就可以进行数据索引了。这其中心款式主要以XML为主,类似实现已经不下4,5个:

数据源: WORD PDF HTML DB other | | | / XML中心款式 | Lucene INDEX

索引历程优化

索引一样平常分2种环境,一种是小批量的索引扩展,一种是大年夜批量的索引重修。在索引历程中,并不是每次新的DOC加入进去索引都从新进行一次索引文件的写入操作(文件I/O是一件异常耗损资本的工作)。

Lucene先在内存中进行索引操作,并根据必然的批量进行文件的写入。这个批次的距离越大年夜,文件的写入次数越少,但占用内存会很多。反之占用内存少,但文件IO操作频繁,索引速率会很慢。在IndexWriter中有一个MERGE_FACTOR参数可以赞助你在构造索引器后根据利用情况的环境充分使用内存削减文件的操作。根据我的应用履历:缺省Indexer是每20笔记录索引后写入一次,每将MERGE_FACTOR增添50倍,索引速率可以前进1倍阁下。

检索缓存优化

Lucene面向全文检索的优化在于首次索引检索后,并不把所有的记录(Document)详细内容读掏出来,而起只将所有结果中匹配度最高的头100条结果(TopDocs)的ID放到结果集缓存中并返回,这里可以对照一下数据库检索:假如是一个10,000条的数据库检索结果集,数据库是必然要把所有记录内容都取得今后再开始返回给利用结果集的。以是纵然检索匹配总数很多,Lucene的结果集占用的内存空间也不会很多。对付一样平常的隐隐检索利用是用不到这么多的结果的,头100条已经可以满意90%以上的检索需求。

假如首批缓存结果数用完后还要读取更后面的结果时Searcher会再次检索并天生一个上次的搜索缓存数大年夜1倍的缓存,并再从新向后抓取。以是假如构造一个Searcher去查1-120条结果,Searcher着实是进行了2次搜索历程:头100条取完后,缓存结果用完,Searcher从新检索再构造一个200条的结果缓存,依此类推,400条缓存,800条缓存。因为每次Searcher工具消掉后,这些缓存也造访那不到了,你有可能想将结果记录缓存下来,缓存数只管即便包管在100以下以充分使用首次的结果缓存,不让Lucene挥霍多次检索,而且可以分级进行结果缓存。

Lucene的别的一个特征是在网络结果的历程中将匹配度低的结果自动过滤掉落了。这也是和数据库利用必要将搜索的结果整个返回不合之处。

我的一些考试测验:

支持中文的Tokenizer:这里有2个版本,一个是经由过程JavaCC天生的,对CJK部分按一个字符一个TOKEN索引,别的一个是从SimpleTokenizer改写的,对英文支持数字和字母TOKEN,对中文按迭代索引。

基于XML数据源的索引器:XMLIndexer,是以所稀有据源只要能够按照DTD转换成指定的XML,就可以用XMLIndxer进行索引了。

根据某个字段排序:按记录索引顺序排序结果的搜索器:IndexOrderSearcher,是以假如必要让搜索结果根据某个字段排序,可以让数据源先按某个字段排好序(比如:PriceField),这样索引后,然后在使用这个按记录的ID顺序检索的搜索器,结果便是相称于是那个字段排序的结果了。

从Lucene学到更多

Luene切实着实是一个面对工具设计的典范

所有的问题都经由过程一个额外抽象层来方便今后的扩展和重用:你可以经由过程从新实现来达到自己的目的,而对其他模块而不必要;

简单的利用进口Searcher, Indexer,并调用底层一系列组件协同的完成搜索义务;

所有的工具的义务都异常埋头:比如搜索历程:QueryParser阐发将查询语句转换成一系列的正确查询的组合(Query), 经由过程底层的索引读取布局IndexReader进行索引的读取,并用响应的打分器给搜索结果进行打分/排序等。所有的功能模块原子化程度异常高,是以可以经由过程从新实现而不必要改动其他模块。

除了机动的利用接口设计,Lucene还供给了一些得当大年夜多半利用的说话阐发器实现(SimpleAnalyser, StandardAnalyser),这也是新用户能够很快上手的紧张缘故原由之一。

这些优点都是异常值得在今后的开拓中进修借鉴的。作为一个通用对象包,Lunece切实着实给予了必要将全文检索功能嵌入到利用中的开拓者很多的便利。

此外,经由过程对Lucene的进修和应用,我也更深刻地舆解了为什么很多半据库优化设计中要求,比如:

尽可能对字段进行索引来前进查询速率,但过多的索引会对数据库表的更新操作变慢,而对结果过多的排序前提,实际上每每也是机能的杀手之一。

很多商业数据库对大年夜批量的数据插入操作会供给一些优化参数,这个感化和索引器的merge_factor的感化是类似的,

20%/80%原则:查的结果多并不即是质量好,尤其对付返回结果集很大年夜,若何优化这头几十条结果的质量每每才是最紧张的。

尽可能让利用从数据库中得到对照小的结果集,由于纵然对付大年夜型数据库,对结果集的随机造访也是一个异常耗损资本的操作。

参考资料:

Apache: Lucene Project

http://jakarta.apache.org/lucene/

Lucene邮件列表归档

Lucene-dev@jakarta.apache.org

Lucene-user@jakarta.apache.org

The Lucene search engine: Powerful, flexible, and free

http://www.javaworld.com/javaworld/jw-09-2000/jw-0915-Lucene_p.html

Lucene Tutorial

http://www.darksleep.com/puff/lucene/lucene.html

Notes on distributed searching with Lucene

http://home.clara.net/markharwood/lucene/

中文说话的切分词

http://www.google.com/search?sourceid=navclient&hl=zh-CN&q=chinese+word+segment

搜索引擎对象先容

http://searchtools.com/

搜索引擎行业钻研

http://www.searchenginewatch.com/

Lucene作者Cutting的几篇论文:

http://lucene.sourceforge.net/publications.html

Lucene的.NET实现:

http://sourceforge.net/projects/nlucene

Lucene作者Cutting的别的一个项目:基于Java的索引引擎Nutch

http://www.nutch.org/ http://sourceforge.net/projects/notch/

关于基于词表和N-Gram的切分词对照

http://china.nikkeibp.co.jp/cgi-bin/china/news/int/int200302100112.html

原文出处:;http://www.chedong.com/tech/lucene.html

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

您可能还会对下面的文章感兴趣: