Lucene 4.X 全套教程
http://www.cnblogs.com/forfuture1978/category/300665.html
摘要: 我们来看最复杂的部分,就是Term Dictionary和Term Index文件,Term Dictionary文件的后缀名为tim,Term Index文件的后缀名是tip,格式如图所示。Term Dictionary文件首先是一个Header,接下来是PostingsHeader,这两个的格式...阅读全文
摘要: 词典的格式设计词典中所保存的信息主要是三部分:Term字符串Term的统计信息,比如文档频率(Document Frequency)倒排表的位置信息其中Term字符串如何保存是一个很大的问题,根据上一章基本原理的表述中,我们知道,写入文件的Term是按照字典顺序排好序的,那么如何将这些排好序的Ter...阅读全文
摘要: Lucene应用开发揭秘华章培训网地址:http://www.hztraining.com/bbs/showtopic-1954.aspxChinaPub地址:http://product.china-pub.com/3502099&ref=xiliegoumai注意事项:由于本人是首次录制此类视频,不完美之处敬请谅解此系列课程主要包涵三大部分,一是搜索引擎的原理,二是lucene的深入解析及高级特性,三是实时搜索分布式搜索的框架解析及代码实现对于搜索引擎的原理部分,理论讲解比较多,有的部分内容较少,处于完整性的需要,还是作为单独的一节,可能视频时间较短,好在视频是分节销售的,本人已经阅读全文
摘要: 一、总体架构 Zoie是linkedin公司基于Lucene实现的实时搜索引擎系统,按照其官方wiki的描述为: http://snaprojects.jira.com/wiki/display/ZOIE/Overview Zoie is a realtime indexing and search system, and as such needs to have relatively close coupling between the logically distinct Indexing and Searching subsystems: as soon as a document m阅读全文
摘要: 在有关Lucene的问题(7),讨论了使用Lucene内存索引和硬盘索引构建实时索引的问题。 然而有的读者提到,如果涉及到文档的删除及更新,那么如何构建实时的索引呢?本节来讨论这个问题。 1、Lucene删除文档的几种方式 IndexReader.deleteDocument(int docID)是用 IndexReader 按文档号删除。 IndexReader.deleteDocuments(Term term)是用 IndexReader 删除包含此词(Term)的文档。 IndexWriter.deleteDocuments(Term term)是用 IndexWriter 删除包..阅读全文
摘要: Lucene 原理与代码分析系列文章已经基本告一段落,可能问题篇还会有新的更新。完整版pdf可由以下链接下载。Lucene 原理与代码分析完整版目录如下:目录目录第一篇:原理篇第一章:全文检索的基本原理一、总论二、索引里面究竟存些什么三、如何创建索引第一步:一些要索引的原文档(Document)。第二步:将原文档传给分次组件(Tokenizer)。第三步:将得到的词元(Token)传给语言处理组件(Linguistic Processor)。第四步:将得到的词(Term)传给索引组件(Indexer)。1.利用得到的词(Term)创建一个字典。2.对字典按字母顺序进行排序。3.合并相同的词(T阅读全文
摘要: 由于前一章所述的Lucene的事务性,使得Lucene可以增量的添加一个段,我们知道,倒排索引是有一定的格式的,而这个格式一旦写入是非常难以改变的,那么如何能够增量建索引呢?Lucene使用段这个概念解决了这个问题,对于每个已经生成的段,其倒排索引结构不会再改变,而增量添加的文档添加到新的段中,段之间在一定的时刻进行合并,从而形成新的倒排索引结构。 然而也正因为Lucene的事务性,使得Lucene的索引不够实时,如果想Lucene实时,则必须新添加的文档后IndexWriter需要commit,在搜索的时候IndexReader需要重新的打开,然而当索引在硬盘上的时候,尤其是索引非常大的时候阅读全文
摘要: 所谓事务性,本多指数据库的属性,包括ACID四个基本要素:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。 我们这里主要讨论隔离性,Lucene的IndexReader和IndexWriter具有隔离性。 当IndexReader.open打开一个索引的时候,相对于给当前索引进行了一次snapshot,此后的任何修改都不会被看到。 仅当IndexReader.open打开一个索引后,才有可能看到从上次打开后对索引的修改。 当IndexWriter没有调用Commit的时候,其修改的内容是不能够被看到的,哪怕...阅读全文
摘要: 1、抽象类Analyzer 其主要包含两个接口,用于生成TokenStream: TokenStream tokenStream(String fieldName, Reader reader); TokenStream reusableTokenStream(String fieldName, Reader reader) ; 所谓TokenStream,后面我们会讲到,是一个由分词后的Token结果组成的流,能够不断的得到下一个分成的Token。 为了提高性能,使得在同一个线程中无需再生成新的TokenStream对象,老的可以被重用,所以有reusableTokenStream一说...阅读全文
摘要: Lucene学习总结之九:Lucene的查询对象(1)http://www.cnblogs.com/forfuture1978/archive/2010/05/19/1738803.htmlLucene学习总结之九:Lucene的查询对象(2)http://www.cnblogs.com/forfuture1978/archive/2010/05/19/1738804.htmlLucene学习总结之九:Lucene的查询对象(3)http://www.cnblogs.com/forfuture1978/archive/2010/05/19/1738805.html---------------阅读全文
摘要: Lucene除了支持查询语法以外,还可以自己构造查询对象进行搜索。 从上一节的Lucene的语法一章可以知道,能与查询语句对应的查询对象有:BooleanQuery,FuzzyQuery,MatchAllDocsQuery,MultiTermQuery,MultiPhraseQuery,PhraseQuery,PrefixQuery,TermRangeQuery,TermQuery,WildcardQuery。 Lucene还支持一些查询对象并没有查询语句与之对应,但是能够实现相对高级的功能,本节主要讨论这些高级的查询对象。 它们中间最主要的一些层次结构如下,我们将一一解析。 Query B.阅读全文
摘要: 5、SpanQuery 所谓SpanQuery也即在查询过程中需要考虑进Term的位置信息的查询对象。 SpanQuery中最基本的是SpanTermQuery,其只包含一个Term,与TermQuery所不同的是,其提供一个函数来得到位置信息: public Spans getSpans(final IndexReader reader) throws IOException { return new TermSpans(reader.termPositions(term), term); } Spans有以下方法: next() 得到下一篇文档号,不同的SpanQuery此方...阅读全文
摘要: 6、FilteredQuery FilteredQuery包含两个成员变量: Query query:查询对象 Filter filter:其有一个函数DocIdSet getDocIdSet(IndexReader reader) 得到一个文档号集合,结果文档必须出自此文档集合,注此处的过滤器所包含的文档号并不是要过滤掉的文档号,而是过滤后需要的文档号。 FilterQuery所得到的结果集同两者取AND查询相同,只不过打分的时候,FilterQuery只考虑query的部分,不考虑filter的部分。 Filter包含很多种如下: 6.1、TermsFilter 其包含一个成员变量...阅读全文
摘要: 为什么会产生这个异常: 使用Lucene检索过程中如果用到RangeQuery,PrefixQuery,WildcardQuery,FuzzyQuery这四种Query,可能会产生TooManyClauses异常。为什么会产生这个异常呢?举例说明: 以RangeQuery为例,如果日期范围为19990101到20091231,在索引文件中有19990102,19990103等等这些日期词组,那么RangeQuery会被扩展成“19990102 OR 19990103”,成了2个子句。可以想象,如果索引文件里面在这个时间段内的日期有很多,那么就会产生很多子句。 PrefixQuery等也是同样的阅读全文
摘要: 三、解析QueryParser.jj3.1、声明QueryParser类在QueryParser.jj文件中,PARSER_BEGIN(QueryParser)和PARSER_END(QueryParser)之间,定义了QueryParser类。其中最重要的一个函数是public Query parse(String query)函数,也即我们解析Lucene查询语法的时候调用的函数。这是一个纯Java代码定义的函数,会直接拷贝到QueryParser.java文件中。parse函数中,最重要的一行代码是调用Query res = TopLevelQuery(field),而TopLevelQ阅读全文
摘要: 一、Lucene的查询语法Lucene所支持的查询语法可见http://lucene.apache.org/java/3_0_1/queryparsersyntax.html(1) 语法关键字+ - && || ! ( ) { } [ ] ^ " ~ * ? : \如果所要查询的查询词中本身包含关键字,则需要用\进行转义(2) 查询词(Term)Lucene支持两种查询词,一种是单一查询词,如"hello",一种是词组(phrase),如"hello world"。(3) 查询域(Field)在查询语句中,可以指定从哪个域中寻找阅读全文
摘要: 信息检索这个词的含义非常广。仅从钱包中取出信用卡,然后输入信用卡号也属于信息检索的范畴。然而,从学术角度来讲,信息检索定义如下: 信息检索即从大量非结构化文档集中找到满足需要的文档的过程。 按照如上定义,信息检索曾经是仅少数人如图书管理员,律师,专业搜索者参与的活动。而今非昔比,当今成千上万的人每天都会用搜索引擎搜索网页和邮件。信息检索正迅速取代传统的数据库搜索的方式,成为信息获取的主要方式。除此之外,信息检索技术还可以解决其他有关数据和信息的问题。所谓非结构化数据,指的是没有清晰的可被计算机理解的语义结构的数据。与之相对的是结构化数据,例如传统的关系型数据库,被很多公司用来保存产品库存及员工阅读全文
摘要: 本系列文章将详细描述几乎最新版本的Lucene的基本原理和代码分析。其中总体架构和索引文件格式是Lucene 2.9的,索引过程分析是Lucene 3.0的。鉴于索引文件格式没有太大变化,因而原文没有更新,原理和架构的文章中引用了前辈的一些图,可能属于早期的Lucene,但不影响对原理和架构的理解。本系列文章尚在撰写之中,将会有Java CC, 分词器,QueryParser,查询语句与查询对象等章节。Lucene学习总结之七:Lucene搜索过程解析(1) http://www.cnblogs.com/forfuture1978/archive/2010/04/04/1704242.html阅读全文
摘要: 2.4、搜索查询对象 2.4.4、收集文档结果集合及计算打分 在函数IndexSearcher.search(Weight, Filter, int) 中,有如下代码: TopScoreDocCollector collector = TopScoreDocCollector.create(nDocs, !weight.scoresDocsOutOfOrder()); search(weight, filter, collector); return collector.topDocs(); 2.4.4.1、创建结果文档收集器 TopScoreDocCollector collector...阅读全文
摘要: 2.4、搜索查询对象 2.4.3、进行倒排表合并 在得到了Scorer对象树以及SumScorer对象树后,便是倒排表的合并以及打分计算的过程。 合并倒排表在此节中进行分析,而Scorer对象树来进行打分的计算则在下一节分析。 BooleanScorer2.score(Collector) 代码如下: public void score(Collector collector) throws IOException { collector.setScorer(this); while ((doc = countingSumScorer.nextDoc()) != NO_MORE...阅读全文
摘要: 2.4、搜索查询对象 2.4.1.2、创建Weight对象树 BooleanQuery.createWeight(Searcher) 最终返回return new BooleanWeight(searcher),BooleanWeight构造函数的具体实现如下: public BooleanWeight(Searcher searcher) { this.similarity = getSimilarity(searcher); weights = new ArrayList<Weight>(clauses.size()); //也是一个递归的过程,沿着新的Query对象树一...阅读全文
摘要: 2.3、QueryParser解析查询语句生成查询对象代码为:QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, "contents", new StandardAnalyzer(Version.LUCENE_CURRENT)); Query query = parser.parse("+(+apple* -boy) (cat* dog) -(eat~ foods)");此过程相对复杂,涉及JavaCC,QueryParser,分词器,查询语法等,本章不会详细论述,会在后面的章节中一一阅读全文
摘要: 二、Lucene搜索详细过程 为了解析Lucene对索引文件搜索的过程,预先写入索引了如下几个文件: file01.txt: apple apples cat dog file02.txt: apple boy cat category file03.txt: apply dog eat etc file04.txt: apply cat foods 2.1、打开IndexReader指向索引文件夹 代码为: IndexReader reader = IndexReader.open(FSDirectory.open(indexDir)); 其实是调用了DirectoryReader.open阅读全文
摘要: 一、Lucene搜索过程总论 搜索的过程总的来说就是将词典及倒排表信息从索引中读出来,根据用户输入的查询语句合并倒排表,得到结果文档集并对文档进行打分的过程。 其可用如下图示: 总共包括以下几个过程: IndexReader打开索引文件,读取并打开指向索引文件的流。 用户输入查询语句 将查询语句转换为查询对象Query对象树 构造Weight对象树,用于计算词的权重Term Weight,也即计算打分公式中与仅与搜索语句相关与文档无关的部分(红色部分)。 构造Scorer对象树,用于计算打分(TermScorer.score())。 在构造Scorer对象树的过程中,其叶子节点...阅读全文
摘要: 在进行Lucene的搜索过程解析之前,有必要单独的一张把Lucene score公式的推导,各部分的意义阐述一下。因为Lucene的搜索过程,很重要的一个步骤就是逐步的计算各部分的分数。 Lucene的打分公式非常复杂,如下: 在推导之前,先逐个介绍每部分的意义: t:Term,这里的Term是指包含域信息的Term,也即title:hello和content:hello是不同的Term coord(q,d):一次搜索可能包含多个搜索词,而一篇文档中也可能包含多个搜索词,此项表示,当一篇文档中包含的搜索词越多,则此文档则打分越高。 queryNorm(q):计算每个查询条目的方差和,...阅读全文
摘要: 一、段合并过程总论 IndexWriter中与段合并有关的成员变量有: HashSet<SegmentInfo> mergingSegments = new HashSet<SegmentInfo>(); //保存正在合并的段,以防止合并期间再次选中被合并。 MergePolicy mergePolicy = new LogByteSizeMergePolicy(this);//合并策略,也即选取哪些段来进行合并。 MergeScheduler mergeScheduler = new ConcurrentMergeScheduler();//段合并器,背后有一个线程负阅读全文
摘要: 本系列文章将详细描述几乎最新版本的Lucene的基本原理和代码分析。其中总体架构和索引文件格式是Lucene 2.9的,索引过程分析是Lucene 3.0的。鉴于索引文件格式没有太大变化,因而原文没有更新,原理和架构的文章中引用了前辈的一些图,可能属于早期的Lucene,但不影响对原理和架构的理解。本系列文章尚在撰写之中,将会有分词器,段合并,QueryParser,查询语句与查询对象,搜索过程,打分公式的推导等章节。提前给大家分享,希望大家批评指正。Lucene学习总结之一:全文检索的基本原理http://www.cnblogs.com/forfuture1978/archive/2009/阅读全文
摘要: 在索引阶段设置Document Boost和Field Boost,存储在(.nrm)文件中。 如果希望某些文档和某些域比其他的域更重要,如果此文档和此域包含所要查询的词则应该得分较高,则可以在索引阶段设定文档的boost和域的boost值。 这些值是在索引阶段就写入索引文件的,存储在标准化因子(.nrm)文件中,一旦设定,除非删除此文档,否则无法改变。 如果不进行设定,则Document Boost和Field Boost默认为1。 Document Boost及FieldBoost的设定方式如下: Document doc = new Document(); Field f = n...阅读全文
摘要: 问题: 在你的文章中提到了: 于是我们把所有此文档中词(term)的权重(term weight) 看作一个向量。 Document = {term1, term2, …… ,term N} Document Vector = {weight1, weight2, …… ,weight N} 同样我们把查询语句看作一个简单的文档,也用向量来表示。 Query = {term1, term 2, …… , term N} Query Vector = {weight1, weight2, …… , weight N} 于是我们把所有此文档中词(term)的权重(term weight...阅读全文
摘要: 问题: 我试验了一下文章中提到的 stemming 和 lemmatization 将单词缩减为词根形式,如“cars”到“car”等。这种操作称为:stemming。 将单词转变为词根形式,如“drove”到“drive”等。这种操作称为:lemmatization。 试验没有成功 代码如下: public class TestNorms { public void createIndex() throws IOException { Directory d = new SimpleFSDirectory(new File("d:/falconTest/lucene3/...阅读全文
摘要: 问题: 使用中科院的中文分词对“中华人民共和国” 进行索引,它被分词为"中华", "人民", "共和国",用“人民共和国”进行搜索,可以搜到,而搜索"中华共和国"却搜索不到,用“中华 AND 共和国”却可以搜出来,为什么? 回答: 我下载了http://ictclas.org/Download.html中科院的词做了简单的分析,如果索引的时候“中华人民共和国”被分成了“中华”“人民”“共和国”,而搜索的时候,搜“中华共和国”,则被分为了“中华 共和国”,然而构建Query Parser构建Query Object的阅读全文
摘要: 6、关闭IndexWriter对象 代码: writer.close(); --> IndexWriter.closeInternal(boolean) --> (1) 将索引信息由内存写入磁盘: flush(waitForMerges, true, true); --> (2) 进行段合并: mergeScheduler.merge(this); 对段的合并将在后面的章节进行讨论,此处仅仅讨论将索引信息由写入磁盘的过程。 代码: IndexWriter.flush(boolean triggerMerge, boolean flushDocStores, boole...阅读全文
摘要: 5、DocumentsWriter对CharBlockPool,ByteBlockPool,IntBlockPool的缓存管理 在索引的过程中,DocumentsWriter将词信息(term)存储在CharBlockPool中,将文档号(doc ID),词频(freq)和位置(prox)信息存储在ByteBlockPool中。 在ByteBlockPool中,缓存是分块(slice)分配的,块(slice)是分层次的,层次越高,此层的块越大,每一层的块大小事相同的。 nextLevelArray表示的是当前层的下一层是第几层,可见第9层的下一层还是第9层,也就是说最高有9层。 le...阅读全文
摘要: 3、将文档加入IndexWriter 代码: writer.addDocument(doc); -->IndexWriter.addDocument(Document doc, Analyzer analyzer) -->doFlush = docWriter.addDocument(doc, analyzer); --> DocumentsWriter.updateDocument(Document, Analyzer, Term) 注:--> 代表一级函数调用 IndexWriter继而调用DocumentsWriter.addDocument,其又调用Docume阅读全文
摘要: 对于Lucene的索引过程,除了将词(Term)写入倒排表并最终写入Lucene的索引文件外,还包括分词(Analyzer)和合并段(merge segments)的过程,本次不包括这两部分,将在以后的文章中进行分析。 Lucene的索引过程,很多的博客,文章都有介绍,推荐大家上网搜一篇文章:《Annotated Lucene》,好像中文名称叫《Lucene源码剖析》是很不错的。 想要真正了解Lucene索引文件过程,最好的办法是跟进代码调试,对着文章看代码,这样不但能够最详细准确的掌握索引过程(描述都是有偏差的,而代码是不会骗你的),而且还能够学习Lucene的一些优秀的实现,能够在以后的工阅读全文
摘要: 四、具体格式 4.2. 反向信息 反向信息是索引文件的核心,也即反向索引。 反向索引包括两部分,左面是词典(Term Dictionary),右面是倒排表(Posting List)。 在Lucene中,这两部分是分文件存储的,词典是存储在tii,tis中的,倒排表又包括两部分,一部分是文档号及词频,保存在frq中,一部分是词的位置信息,保存在prx中。 Term Dictionary (tii, tis) –> Frequencies (.frq) –> Positions (.prx) 4.2.1. 词典(tis)及词典索引(tii)信息 在词典中,所有的词是按照字典顺序...阅读全文
摘要: 四、具体格式 上面曾经交代过,Lucene保存了从Index到Segment到Document到Field一直到Term的正向信息,也包括了从Term到Document映射的反向信息,还有其他一些Lucene特有的信息。下面对这三种信息一一介绍。 4.1. 正向信息 Index –> Segments (segments.gen, segments_N) –> Field(fnm, fdx, fdt) –> Term (tvx, tvd, tvf) 上面的层次结构不是十分的准确,因为segments.gen和segments_N保存的是段(segment)的元数据信息(met阅读全文
摘要: Lucene的索引里面存了些什么,如何存放的,也即Lucene的索引文件格式,是读懂Lucene源代码的一把钥匙。 当我们真正进入到Lucene源代码之中的时候,我们会发现: Lucene的索引过程,就是按照全文检索的基本过程,将倒排表写成此文件格式的过程。 Lucene的搜索过程,就是按照此文件格式将索引进去的信息读出来,然后计算每篇文档打分(score)的过程。 本文详细解读了Apache Lucene - Index File Formats(http://lucene.apache.org/java/2_9_0/fileformats.html) 这篇文章。 一、基本概念 下图...阅读全文
摘要: Lucene总的来说是: 一个高效的,可扩展的,全文检索库。 全部用Java实现,无须配置。 仅支持纯文本文件的索引(Indexing)和搜索(Search)。 不负责由其他格式的文件抽取纯文本文件,或从网络中抓取文件的过程。 在Lucene in action中,Lucene 的构架和过程如下图, 说明Lucene是有索引和搜索的两个过程,包含索引创建,索引,搜索三个要点。 让我们更细一些看Lucene的各组件: 被索引的文档用Document对象表示。 IndexWriter通过函数addDocument将文档添加到索引中,实现创建索引的过程。 Lucene的...阅读全文
摘要: 全文检索大体分两个过程,索引创建(Indexing)和搜索索引(Search)。 * 索引创建:将现实世界中所有的结构化和非结构化数据提取信息,创建索引的过程。 * 搜索索引:就是得到用户的查询请求,搜索创建的索引,然后返回结果的过程。 于是全文检索就存在三个重要问题: 1. 索引里面究竟存些什么?(Index) 2. 如何创建索引?(Indexing) 3. 如何对索引进行搜索?(Search)阅读全文
www.jeesite.net国产优秀开源框架 国际化标准 安全可靠 品质卓越 不断创新
主要用于政府、银行、Web互联网平台、中小型企业管理后台