网站的制作流程有哪些步骤,网站服务器租用一般费用,品牌营销策略包括哪些,国外经典手机网站设计Lucene简单介绍#xff08;该部分摘自网络#xff09; Lucene是一个高效的#xff0c;基于Java的全文检索库。 所以在了解Lucene之前要费一番工夫了解一下全文检索。 那么什么叫做全文检索呢#xff1f;这要从我们生活中的数据说起。 我们生活中的数据总体分为两种#xf…Lucene简单介绍该部分摘自网络 Lucene是一个高效的基于Java的全文检索库。 所以在了解Lucene之前要费一番工夫了解一下全文检索。 那么什么叫做全文检索呢这要从我们生活中的数据说起。 我们生活中的数据总体分为两种结构化数据和非结构化数据。 结构化数据指具有固定格式或有限长度的数据如数据库元数据等。非结构化数据指不定长或无固定格式的数据如邮件word文档等。当然有的地方还会提到第三种半结构化数据如XMLHTML等当根据需要可按结构化数据来处理也可抽取出纯文本按非结构化数据来处理。 非结构化数据又一种叫法叫全文数据。 按照数据的分类搜索也分为两种 对结构化数据的搜索如对数据库的搜索用SQL语句。再如对元数据的搜索如利用windows搜索对文件名类型修改时间进行搜索等。对非结构化数据的搜索如利用windows的搜索也可以搜索文件内容Linux下的grep命令再如用Google和百度可以搜索大量内容数据。对非结构化数据也即对全文数据的搜索主要有两种方法 一种是顺序扫描法(Serial Scanning)所谓顺序扫描比如要找内容包含某一个字符串的文件就是一个文档一个文档的看对于每一个文档从头看到尾如果此文档包含此字符串则此文档为我们要找的文件接着看下一个文件直到扫描完所有的文件。如利用windows的搜索也可以搜索文件内容只是相当的慢。如果你有一个80G硬盘如果想在上面找到一个内容包含某字符串的文件不花他几个小时怕是做不到。Linux下的grep命令也是这一种方式。大家可能觉得这种方法比较原始但对于小数据量的文件这种方法还是最直接最方便的。但是对于大量的文件这种方法就很慢了。 有人可能会说对非结构化数据顺序扫描很慢对结构化数据的搜索却相对较快由于结构化数据有一定的结构可以采取一定的搜索算法加快速度那么把我们的非结构化数据想办法弄得有一定结构不就行了吗 这种想法很天然却构成了全文检索的基本思路也即将非结构化数据中的一部分信息提取出来重新组织使其变得有一定结构然后对此有一定结构的数据进行搜索从而达到搜索相对较快的目的。 这部分从非结构化数据中提取出的然后重新组织的信息我们称之索引。 这种说法比较抽象举几个例子就很容易明白比如字典字典的拼音表和部首检字表就相当于字典的索引对每一个字的解释是非结构化的如果字典没有音节表和部首检字表在茫茫辞海中找一个字只能顺序扫描。然而字的某些信息可以提取出来进行结构化处理比如读音就比较结构化分声母和韵母分别只有几种可以一一列举于是将读音拿出来按一定的顺序排列每一项读音都指向此字的详细解释的页数。我们搜索时按结构化的拼音搜到读音然后按其指向的页数便可找到我们的非结构化数据——也即对字的解释。 这种先建立索引再对索引进行搜索的过程就叫全文检索(Full-text Search)。 下面这幅图来自《Lucene in action》但却不仅仅描述了Lucene的检索过程而是描述了全文检索的一般过程。 全文检索大体分两个过程索引创建(Indexing)和搜索索引(Search)。 索引创建将现实世界中所有的结构化和非结构化数据提取信息创建索引的过程。搜索索引就是得到用户的查询请求搜索创建的索引然后返回结果的过程详情可以参考http://forfuture1978.iteye.com/blog/546771 Lucene3.5 建立索引总结 Lucene的索引结构是有层次结构的主要分以下几个层次 索引(Index) 在Lucene中一个索引是放在一个文件夹中的。如上图同一文件夹中的所有的文件构成一个Lucene索引。段(Segment) 一个索引可以包含多个段段与段之间是独立的添加新文档可以生成新的段不同的段可以合并。如上图具有相同前缀文件的属同一个段图中共两个段 _0 和 _1。segments.gen和segments_5是段的元数据文件也即它们保存了段的属性信息。文档(Document) 文档是我们建索引的基本单位不同的文档是保存在不同的段中的一个段可以包含多篇文档。新添加的文档是单独保存在一个新生成的段中随着段的合并不同的文档合并到同一个段中。域(Field) 一篇文档包含不同类型的信息可以分开索引比如标题时间正文作者等都可以保存在不同的域里。不同域的索引方式可以不同在真正解析域的存储的时候我们会详细解读。词(Term) 词是索引的最小单位是经过词法分析和语言处理后的字符串。一Field相当于数据库表的字段 1其中的Field字段或域的构造方法有以下几种 Field(String name, boolean internName, String value, Field.Store store, Field.Index index, Field.TermVector termVector) 常用的 Field(String name, byte[] value) Field(String name, byte[] value, int offset, int length) Field(String name, Reader reader) Field(String name, Reader reader, Field.TermVector termVector) 该Reader当在值是从文件中读取很长的数据时用单身磁盘I/O操作太多效率太低了 Field(String name, String value, Field.Store store, Field.Index index) Field(String name, String value, Field.Store store, Field.Index index, Field.TermVector termVector) Field(String name, TokenStream tokenStream) Field(String name, TokenStream tokenStream, Field.TermVector termVector) l 其中 Field.Store表示是否存储值分别为YES ,NO l Field.Index 表示是否索引允许检索它已经包括了是否分词其值有以下几种 ANALYZED 分词并索引 Index the tokens produced by running the fields value through an Analyzer. ANALYZED_NO_NORMS 分词索引 但是禁用存储规范 Expert: Index the tokens produced by running the fields value through an Analyzer, and also separately disable the storing of norms. NO 不索引当然肯定不会去分词 Do not index the field value. NOT_ANALYZED 索引但不会分词 Index the fields value without using an Analyzer, so it can be searched. NOT_ANALYZED_NO_NORMS 不索引 同时禁用存储规范 l Field.TermVector 表示对Field词条向量是否进行存储具体什么意思我也还没弄明白其值有以下几种 NO 不存储词条向量 Do not store term vectors. WITH_OFFSETS 存储词条和其偏移量 Store the term vector Token offset information WITH_POSITIONS 存储词条和其位置 Store the term vector token position information WITH_POSITIONS_OFFSETS 存储词条和 词条偏移量及其位置 Store the term vector Token position and offset information YES 存储每个document的词条向量 Store the term vectors of each document. 2.document简单的说就像数据库中的一条记录它的每个字段就是Field。注意数据库中你建立了字段所有的记录具有相同记录即数据库是以字段为主导的而Lucene是以document为主导的同一个索引相当于数据库中一张表中不同的document是可以不一样的。下面介绍docuemnt常用几种方法 add(Fieldable field) 将一个Field 加入document,注意Field是实现了Fieldable接口的类 get(String name) 返回当前docuement指定Field名的Field值 getBoost() 返回索引时设置的加权因子具体到底是什么没搞明白 Returns, at indexing time, the boost factor as set by setBoost(float). getFieldable(String name) 看英语吧这个很简单 Returns a field with the given name if any exist in this document, or null. getFieldables(String name) 看英语吧这个很简单只不过返回的是多个 Returns an array of Fieldables with the given name. getFields() Returns a List of all the fields in a document. getFields(String name) Deprecated. use getFieldable(java.lang.String) instead and cast depending on data type. getValues(String name) 返回指定Field名的Field值的数组 Returns an array of values of the field specified as the method parameter. removeField(String name) 移除当前document的指定的Field Removes field with the specified name from the document. removeFields(String name) 移除多个Field Removes all fields with the given name from the document. setBoost(float boost) Sets a boost factor for hits词条 on any field of this document. toString() Prints the fields of a document for human consumption. 三、Analyzer是Lucene的分析工具无论是建立索引还是搜索过程该类是一个抽象类所以网上常用适合Lucene的分词器都是它的继承例如用Lucene自带的StandardAnalyzer如 Analyzer analyzer new StandardAnalyzer(Version.LUCENE_35) 四IndexWriter 他是建立索引的类至于该类如何实现建立索引请参考前面的文章 IndexWriter.setMaxFieldLength(int)表示索引数据时对数据源的最大长度进行现在如设置为100则表示 取数据源前100个长度进行索引分析当然存储是全都存储当然长度不足100的就全都索引。 l 、一个索引可以有多个segment段但一个索引目录里只有一个segments(该文件记录了所有的segmet);一个segment有多个document可以设置最大值同一个segment在磁盘上各种物理的文件的前缀是相同的如图 其中 l .frq 记录的是词条频率信息 l .prx记录的词条的未知信息 l .fnm记录了所有Field的信息 l .fdt/.fdx 域数据文件(fdt): 真正保存存储域(stored field)信息的是fdt文件在一个段(segment)中总共有segment size篇文档所以fdt文件中共有segment size个项每一项保存一篇文档的域的信息对于每一篇文档一开始是一个fieldcount也即此文档包含的域的数目接下来是fieldcount个项每一项保存一个域的信息。对于每一个域fieldnum是域号接着是一个8位的byte最低一位表示此域是否分词(tokenized)倒数第二位表示此域是保存字符串数据还是二进制数据倒数第三位表示此域是否被压缩再接下来就是存储域的值比如new Field(title, lucene in action, Field.Store.Yes, …)则此处存放的就是lucene in action这个字符串。域索引文件(fdx) 由域数据文件格式我们知道每篇文档包含的域的个数每个存储域的值都是不一样的因而域数据文件中segment size篇文档每篇文档占用的大小也是不一样的那么如何在fdt中辨别每一篇文档的起始地址和终止地址呢如何能够更快的找到第n篇文档的存储域的信息呢就是要借助域索引文件。域索引文件也总共有segment size个项每篇文档都有一个项每一项都是一个long大小固定每一项都是对应的文档在fdt文件中的起始地址的偏移量这样如果我们想找到第n篇文档的存储域的信息只要在fdx中找到第n项然后按照取出的long作为偏移量就可以在fdt文件中找到对应的存储域的信息。l 词典文件(tis) TermCount词典中包含的总的词数IndexInterval为了加快对词的查找速度也应用类似跳跃表的结构假设IndexInterval为4则在词典索引(tii)文件中保存第4个第8个第12个词这样可以加快在词典文件中查找词的速度。SkipInterval倒排表无论是文档号及词频还是位置信息都是以跳跃表的结构存在的SkipInterval是跳跃的步数。MaxSkipLevels跳跃表是多层的这个值指的是跳跃表的最大层数。TermCount个项的数组每一项代表一个词对于每一个词以前缀后缀规则存放词的文本信息(PrefixLength Suffix)词属于的域的域号(FieldNum)有多少篇文档包含此词(DocFreq)此词的倒排表在frqprx中的偏移量(FreqDelta, ProxDelta)此词的倒排表的跳跃表在frq中的偏移量(SkipDelta)这里之所以用Delta是应用差值规则。l 词典索引文件(tii) 词典索引文件是为了加快对词典文件中词的查找速度保存每隔IndexInterval个词。词典索引文件是会被全部加载到内存中去的。IndexTermCount TermCount / IndexInterval词典索引文件中包含的词数。IndexInterval同词典文件中的IndexInterval。SkipInterval同词典文件中的SkipInterval。MaxSkipLevels同词典文件中的MaxSkipLevels。IndexTermCount个项的数组每一项代表一个词每一项包括两部分第一部分是词本身(TermInfo)第二部分是在词典文件中的偏移量(IndexDelta)。假设IndexInterval为4此数组中保存第4个第8个第12个词...l 标准化因子文件(nrm) 为什么会有标准化因子呢从第一章中的描述我们知道在搜索过程中搜索出的文档要按与查询语句的相关性排序相关性大的打分(score)高从而排在前面。相关性打分(score)使用向量空间模型(Vector Space Model)在计算相关性之前要计算Term Weight也即某Term相对于某Document的重要性。在计算Term Weight时主要有两个影响因素一个是此Term在此文档中出现的次数一个是此Term的普通程度。显然此Term在此文档中出现的次数越多此Term在此文档中越重要。 这种Term Weight的计算方法是最普通的然而存在以下几个问题 不同的文档重要性不同。有的文档重要些有的文档相对不重要比如对于做软件的在索引书籍的时候我想让计算机方面的书更容易搜到而文学方面的书籍搜索时排名靠后。不同的域重要性不同。有的域重要一些如关键字如标题有的域不重要一些如附件等。同样一个词(Term)出现在关键字中应该比出现在附件中打分要高。根据词(Term)在文档中出现的绝对次数来决定此词对文档的重要性有不合理的地方。比如长的文档词在文档中出现的次数相对较多这样短的文档比较吃亏。比如一个词在一本砖头书中出现了10次在另外一篇不足100字的文章中出现了9次就说明砖头书应该排在前面码不应该显然此词在不足100字的文章中能出现9次可见其对此文章的重要性。由于以上原因Lucene在计算Term Weight时都会乘上一个标准化因子(Normalization Factor)来减少上面三个问题的影响。 标准化因子(Normalization Factor)是会影响随后打分(score)的计算的Lucene的打分计算一部分发生在索引过程中一般是与查询语句无关的参数如标准化因子大部分发生在搜索过程中会在搜索过程的代码分析中详述。 标准化因子(Normalization Factor)在索引过程总的计算如下 它包括三个参数 Document boost此值越大说明此文档越重要。Field boost此域越大说明此域越重要。lengthNorm(field) (1.0 / Math.sqrt(numTerms))一个域中包含的Term总数越多也即文档越长此值越小文档越短此值越大。从上面的公式我们知道一个词(Term)出现在不同的文档或不同的域中标准化因子不同。比如有两个文档每个文档有两个域如果不考虑文档长度就有四种排列组合在重要文档的重要域中在重要文档的非重要域中在非重要文档的重要域中在非重要文档的非重要域中四种组合每种有不同的标准化因子。 五索引优化合并策略以前的版本中通过合并因子Mergefactor以及maxMergegeDocs都是通过IndexWriter来设置的在3.5版本中这些方法都过时了现在这些优化方法都集成到MergePolicy一个抽象类所以索引优化时可以用如下方法来设置MergePolicy me new LogMergePolicy()该类继承MergePolicy; 然后通过IndexWriterConfig调用setMergePolicy(MergePolicy mergePolicy) 来设置然后通过3.5版本中IndexWriter的唯一推荐的构造方法IndexWriter(Directory d, IndexWriterConfig conf) 来设置其他构造方法都过时了。六、IndexReader类该类主要负责索引的操作如读取修改删除操作具体可以参考http://xiaozu.renren.com/xiaozu/258210/336375170 很代码已经详细说明了。转载于:https://www.cnblogs.com/qingfeideyi/archive/2012/03/04/2379526.html