如何在国外社交网站上做原单外贸,模板建站能建个门户网站吗,ih5制作平台官网免费,网站搜索引擎关键字怎么做摘要#xff1a; 前言 Apache Lucene是一个开源的高性能、可扩展的信息检索引擎#xff0c;提供了强大的数据检索能力。Lucene已经发展了很多年#xff0c;其功能越来越强大#xff0c;架构也越来越精细。它目前不仅仅能支持全文索引#xff0c;也能够提供多种其他类型的索…摘要 前言 Apache Lucene是一个开源的高性能、可扩展的信息检索引擎提供了强大的数据检索能力。Lucene已经发展了很多年其功能越来越强大架构也越来越精细。它目前不仅仅能支持全文索引也能够提供多种其他类型的索引方式来满足不同类型的查询需求。
前言Apache Lucene是一个开源的高性能、可扩展的信息检索引擎提供了强大的数据检索能力。Lucene已经发展了很多年其功能越来越强大架构也越来越精细。它目前不仅仅能支持全文索引也能够提供多种其他类型的索引方式来满足不同类型的查询需求。基于Lucene的开源项目有很多最知名的要属Elasticsearch和Solr如果说Elasticsearch和Solr是一辆设计精美、性能卓越的跑车那Lucene就是为其提供强大动力的引擎。为了驾驭这辆跑车让它跑的更快更稳定我们需要对它的引擎研究透彻。在此之前我们在专栏已经发表了多篇文章来剖析Elasticsearch的数据模型、读写路径、分布式架构以及Data/Meta一致性等问题这篇文章之后我们会陆续发表一系列的关于Lucene的原理和源码解读来全面解析Lucene的数据模型和数据读写路径。Lucene官方对自己的优势总结为几点Scalable, High-Performance IndexingPowerful, Accurate and Efficient Search Algorithms希望通过我们的系列文章能够让读者理解Lucene是如何达到这些目标的。整个分析会基于Lucene 7.2.1版本在读这篇文章之前需要有一定的知识基础例如了解基本的搜索和索引原理知道什么是倒排、分词、相关性等基本概念了解Lucene的基本使用例如Directory、IndexWriter、IndexSearcher等。基本概念在深入解读Lucene之前先了解下Lucene的几个基本概念以及这几个概念背后隐藏的一些东西。如图是一个Index内的基本组成Segment内数据只是一个抽象表示不代表其内部真实数据结构。Index索引类似数据库的表的概念但是与传统表的概念会有很大的不同。传统关系型数据库或者NoSQL数据库的表在创建时至少要定义表的Scheme定义表的主键或列等会有一些明确定义的约束。而Lucene的Index则完全没有约束。Lucene的Index可以理解为一个文档收纳箱你可以往内部塞入新的文档或者从里面拿出文档但如果你要修改里面的某个文档则必须先拿出来修改后再塞回去。这个收纳箱可以塞入各种类型的文档文档里的内容可以任意定义Lucene都能对其进行索引。Document文档类似数据库内的行或者文档数据库内的文档的概念一个Index内会包含多个Document。写入Index的Document会被分配一个唯一的ID即Sequence Number更多被叫做DocId关于Sequence Number后面会再细说。Field字段一个Document会由一个或多个Field组成Field是Lucene中数据索引的最小定义单位。Lucene提供多种不同类型的Field例如StringField、TextField、LongFiled或NumericDocValuesField等Lucene根据Field的类型FieldType来判断该数据要采用哪种类型的索引方式Invert Index、Store Field、DocValues或N-dimensional等关于Field和FieldType后面会再细说。Term和Term DictionaryLucene中索引和搜索的最小单位一个Field会由一个或多个Term组成Term是由Field经过Analyzer分词产生。Term Dictionary即Term词典是根据条件查找Term的基本索引。Segment一个Index会由一个或多个sub-index构成sub-index被称为Segment。Lucene的Segment设计思想与LSM类似但又有些不同继承了LSM中数据写入的优点但是在查询上只能提供近实时而非实时查询。Lucene中的数据写入会先写内存的一个Buffer类似LSM的MemTable但是不可读当Buffer内数据到一定量后会被flush成一个Segment每个Segment有自己独立的索引可独立被查询但数据永远不能被更改。这种模式避免了随机写数据写入都是Batch和Append能达到很高的吞吐量。Segment中写入的文档不可被修改但可被删除删除的方式也不是在文件内部原地更改而是会由另外一个文件保存需要被删除的文档的DocID保证数据文件不可被修改。Index的查询需要对多个Segment进行查询并对结果进行合并还需要处理被删除的文档为了对查询进行优化Lucene会有策略对多个Segment进行合并这点与LSM对SSTable的Merge类似。Segment在被flush或commit之前数据保存在内存中是不可被搜索的这也就是为什么Lucene被称为提供近实时而非实时查询的原因。读了它的代码后发现它并不是不能实现数据写入即可查只是实现起来比较复杂。原因是Lucene中数据搜索依赖构建的索引例如倒排依赖Term DictionaryLucene中对数据索引的构建会在Segment flush时而非实时构建目的是为了构建最高效索引。当然它可引入另外一套索引机制在数据实时写入时即构建但这套索引实现会与当前Segment内索引不同需要引入额外的写入时索引以及另外一套查询机制有一定复杂度。Sequence NumberSequence Number后面统一叫DocId是Lucene中一个很重要的概念数据库内通过主键来唯一标识一行而Lucene的Index通过DocId来唯一标识一个Doc。不过有几点要特别注意DocId实际上并不在Index内唯一而是Segment内唯一Lucene这么做主要是为了做写入和压缩优化。那既然在Segment内才唯一又是怎么做到在Index级别来唯一标识一个Doc呢方案很简单Segment之间是有顺序的举个简单的例子一个Index内有两个Segment每个Segment内分别有100个Doc在Segment内DocId都是0-100转换到Index级的DocId需要将第二个Segment的DocId范围转换为100-200。DocId在Segment内唯一取值从0开始递增。但不代表DocId取值一定是连续的如果有Doc被删除那可能会存在空洞。一个文档对应的DocId可能会发生变化主要是发生在Segment合并时。Lucene内最核心的倒排索引本质上就是Term到所有包含该Term的文档的DocId列表的映射。所以Lucene内部在搜索的时候会是一个两阶段的查询第一阶段是通过给定的Term的条件找到所有Doc的DocId列表第二阶段是根据DocId查找Doc。Lucene提供基于Term的搜索功能也提供基于DocId的查询功能。DocId采用一个从0开始底层的Int32值是一个比较大的优化同时体现在数据压缩和查询效率上。例如数据压缩上的Delta策略、ZigZag编码以及倒排列表上采用的SkipList等这些优化后续会详述。索引类型Lucene中支持丰富的字段类型每种字段类型确定了支持的数据类型以及索引方式目前支持的字段类型包括LongPoint、TextField、StringField、NumericDocValuesField等。如图是Lucene中对于不同类型Field定义的一个基本关系所有字段类都会继承自Field这个类Field包含3个重要属性name(String)、fieldsData(BytesRef)和type(FieldType)。name即字段的名称fieldsData即字段值所有类型的字段的值最终都会转换为二进制字节流来表示。type是字段类型确定了该字段被索引的方式。FieldType是一个很重要的类包含多个重要属性这些属性的值决定了该字段被索引的方式。Lucene提供的多种不同类型的Field本质区别就两个一是不同类型值到fieldData定义了不同的转换方式二是定义了FieldType内不同属性不同取值的组合。这种模式下你也能够通过自定义数据以及组合FieldType内索引参数来达到定制类型的目的。要理解Lucene能够提供哪些索引方式只需要理解FieldType内每个属性的具体含义我们来一个一个看stored: 代表是否需要保存该字段如果为false则lucene不会保存这个字段的值而搜索结果中返回的文档只会包含保存了的字段。tokenized: 代表是否做分词在lucene中只有TextField这一个字段需要做分词。termVector: 这篇文章很好的解释了term vector的概念简单来说term vector保存了一个文档内所有的term的相关信息包括Term值、出现次数frequencies以及位置positions等是一个per-document inverted index提供了根据docid来查找该文档内所有term信息的能力。对于长度较小的字段不建议开启term verctor因为只需要重新做一遍分词即可拿到term信息而针对长度较长或者分词代价较大的字段则建议开启term vector。Term vector的用途主要有两个一是关键词高亮二是做文档间的相似度匹配more-like-this。omitNorms: Norms是normalization的缩写lucene允许每个文档的每个字段都存储一个normalization factor是和搜索时的相关性计算有关的一个系数。Norms的存储只占一个字节但是每个文档的每个字段都会独立存储一份且Norms数据会全部加载到内存。所以若开启了Norms会消耗额外的存储空间和内存。但若关闭了Norms则无法做index-time boostingelasticsearch官方建议使用query-time boosting来替代以及length normalization。indexOptions: Lucene提供倒排索引的5种可选参数NONE、DOCS、DOCS_AND_FREQS、DOCS_AND_FREQS_AND_POSITIONS、DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS用于选择该字段是否需要被索引以及索引哪些内容。docValuesType: DocValue是Lucene 4.0引入的一个正向索引docid到field的一个列存大大优化了sorting、faceting或aggregation的效率。DocValues是一个强schema的存储结构开启DocValues的字段必须拥有严格一致的类型目前Lucene只提供NUMERIC、BINARY、SORTED、SORTED_NUMERIC和SORTED_SET五种类型。dimensionLucene支持多维数据的索引采取特殊的索引来优化对多维数据的查询这类数据最典型的应用场景是地理位置索引一般经纬度数据会采取这个索引方式。来看下Lucene中对StringField的一个定义 StringFiled有两种类型索引定义TYPE_NOT_STORED和TYPE_STORED唯一的区别是这个Field是否需要Store。从其他的几个属性也可以解读出StringFiled选择omitNorms需要进行倒排索引并且不需要被分词。Elasticsearch数据类型Elasticsearch内对用户输入文档内Field的索引也是按照Lucene能提供的几种模式来提供。除了用户能自定义的FieldElasticsearch还有自己预留的系统字段用作一些特殊的目的。这些字段映射到Lucene本质上也是一个Field与用户自定义的Field无任何区别只不过Elasticsearch根据这些系统字段不同的使用目的定制有不同的索引方式。举个例子上图是Elasticsearch内两个系统字段_version和_uid的FieldType定义我们来解读下它们的索引方式。Elasticsearch通过_uid字段唯一标识一个文档通过_version字段来记录该文档当前的版本。从这两个字段的FieldType定义上可以看到_uid字段会做倒排索引不需要分词需要被Store。而_version字段则不需要被倒排索引也不需要被Store但是需要被正排索引。很好理解因为_uid需要被搜索而_version不需要。但_version需要通过docId来查询而且Elasticsearch内versionMap内需要通过docId做大量查询且只需要查询出_version字段所以_version最合适的是被正排索引。关于Elasticsearch内系统字段全面的解析可以看下这篇文章。总结这篇文章主要介绍了Lucene的一些基本概念以及提供的索引类型。后续我们会有一系列文章来解析Lucene提供的IndexWriter的写入流程其In-Memory Buffer的结构以及持久化后的索引文件结构来了解Lucene为何能达到如此高效的数据索引性能。也会去解析IndexSearcher的查询流程以及一些特殊的查询优化的数据结构来了解为何Lucene能提供如此高效的搜索和查询。原文链接干货好文请关注扫描以下二维码