热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Lucene剖析基本概念

媒介ApacheLucene是一個開源的高機能、可擴大的信息檢索引擎,供應了壯大的數據檢索才能。Lucene已生長了許多年,其功用愈來愈壯大,架構也愈來愈邃密。它現在不僅僅能支撐全

媒介

Apache Lucene是一個開源的高機能、可擴大的信息檢索引擎,供應了壯大的數據檢索才能。Lucene已生長了許多年,其功用愈來愈壯大,架構也愈來愈邃密。它現在不僅僅能支撐全文索引,也能夠供應多種其他範例的索引體式格局,來滿足差別範例的查詢需求。

基於Lucene的開源項目有許多,最着名的要屬Elasticsearch和Solr,假如說Elasticsearch和Solr是一輛設想優美、機能卓着的跑車,那Lucene就是為其供應壯大動力的引擎。為了駕御這輛跑車讓它跑的更快更穩固,我們須要對它的引擎研討透闢。

在此之前我們在專欄已宣布了多篇文章來理會Elasticsearch的數據模型、讀寫途徑、分佈式架構以及Data/Meta一致性等題目,這篇文章以後我們會一連宣布一系列的關於Lucene的道理和源碼解讀,來周全剖析Lucene的數據模型和數據讀寫途徑。

Lucene官方對本身的上風總結為幾點:
Scalable, High-Performance Indexing
Powerful, Accurate and Efficient Search Algorithms
願望經由過程我們的系列文章,能夠讓讀者明白Lucene是怎樣到達這些目標的。

悉數分析會基於Lucene 7.2.1版本,在讀這篇文章之前,須要有肯定的學問基礎,比方相識基礎的搜刮和索引道理,曉得什麼是倒排、分詞、相干性等基礎觀點,相識Lucene的基礎運用,比方Directory、IndexWriter、IndexSearcher等。

基礎觀點

在深切解讀Lucene之前,先相識下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 Dictionary
Lucene中索引和搜刮的最小單元,一個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 Dictionary),Lucene中對數據索引的構建會在Segment flush時,而非及時構建,目標是為了構建最高效索引。固然它可引入別的一套索引機制,在數據及時寫入時即構建,但這套索引完成會與當前Segment內索引差別,須要引入分外的寫入時索引以及別的一套查詢機制,有肯定複雜度。

Sequence Number
Sequence 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剖析 - 基本概念》

如圖是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 boosting(elasticsearch官方發起運用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五種範例。
dimension:Lucene支撐多維數據的索引,採用特別的索引來優化對多維數據的查詢,這類數據最典範的運用場景是地理位置索引,平常經緯度數據會採用這個索引體式格局。

來看下Lucene中對StringField的一個定義:

《Lucene剖析 - 基本概念》

StringFiled有兩種範例索引定義,TYPE_NOT_STORED和TYPE_STORED,唯一的區分是這個Field是不是須要Store。從其他的幾個屬性也能夠解讀出,StringFiled挑選omitNorms,須要舉行倒排索引而且不須要被分詞。

Elasticsearch數據範例

Elasticsearch內對用戶輸入文檔內Field的索引,也是根據Lucene能供應的幾種形式來供應。除了用戶能自定義的Field,Elasticsearch另有本身預留的體系字段,用作一些特別的目標。這些字段映照到Lucene本質上也是一個Field,與用戶自定義的Field無任何區分,只不過Elasticsearch依據這些體系字段差別的運用目標,定製有差別的索引體式格局。

《Lucene剖析 - 基本概念》

舉個例子,上圖​是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能供應云云高效的搜刮和查詢。


推荐阅读
  • 本文详细探讨了JDBC(Java数据库连接)的内部机制,重点分析其作为服务提供者接口(SPI)框架的应用。通过类图和代码示例,展示了JDBC如何注册驱动程序、建立数据库连接以及执行SQL查询的过程。 ... [详细]
  • ElasticSearch 集群监控与优化
    本文详细介绍了如何有效地监控 ElasticSearch 集群,涵盖了关键性能指标、集群健康状况、统计信息以及内存和垃圾回收的监控方法。 ... [详细]
  • docker镜像重启_docker怎么启动镜像dock ... [详细]
  • 本文详细介绍了如何配置Apache Flume与Spark Streaming,实现高效的数据传输。文中提供了两种集成方案,旨在帮助用户根据具体需求选择最合适的配置方法。 ... [详细]
  • Elasticsearch排序机制详解
    本文深入探讨了Elasticsearch中的排序功能,包括相关性排序、字段值排序、多级排序及字符串和多值字段的排序策略,旨在帮助读者更好地理解和优化搜索结果。 ... [详细]
  • 本文详细探讨了如何在 SparkSQL 中创建 DataFrame,涵盖了从基本概念到具体实践的各种方法。作为持续学习的一部分,本文将持续更新以提供最新信息。 ... [详细]
  • MySQL索引详解与优化
    本文深入探讨了MySQL中的索引机制,包括索引的基本概念、优势与劣势、分类及其实现原理,并详细介绍了索引的使用场景和优化技巧。通过具体示例,帮助读者更好地理解和应用索引以提升数据库性能。 ... [详细]
  • 毕业设计:基于机器学习与深度学习的垃圾邮件(短信)分类算法实现
    本文详细介绍了如何使用机器学习和深度学习技术对垃圾邮件和短信进行分类。内容涵盖从数据集介绍、预处理、特征提取到模型训练与评估的完整流程,并提供了具体的代码示例和实验结果。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 本文介绍如何在现有网络中部署基于Linux系统的透明防火墙(网桥模式),以实现灵活的时间段控制、流量限制等功能。通过详细的步骤和配置说明,确保内部网络的安全性和稳定性。 ... [详细]
  • 深入解析:OpenShift Origin环境下的Kubernetes Spark Operator
    本文探讨了如何在OpenShift Origin平台上利用Kubernetes Spark Operator来管理和部署Apache Spark集群与应用。作为Radanalytics.io项目的一部分,这一开源工具为大数据处理提供了强大的支持。 ... [详细]
  • 收割机|篇幅_国内最牛逼的笔记,不接受反驳!!
    收割机|篇幅_国内最牛逼的笔记,不接受反驳!! ... [详细]
  • 在Elasticsearch中,映射(mappings)定义了索引中字段的结构,类似于传统数据库中的表结构。虽然Elasticsearch支持字段的增删,但直接修改字段类型是不允许的。本文介绍了一种通过创建新索引并迁移数据的方式来改变字段类型的方法。 ... [详细]
  • Elasticsearch集群构建指南:本地环境搭建与管理
    本文详细介绍了如何在本地环境中搭建Elasticsearch集群,包括节点配置、主节点选举机制、以及如何通过单播和广播方式增加节点。同时,文章还探讨了集群的高可用性和扩展性,以及如何通过配置防止脑裂现象的发生。 ... [详细]
  • 构建Filebeat-Kafka-Logstash-ElasticSearch-Kibana日志收集体系
    本文介绍了如何使用Filebeat、Kafka、Logstash、ElasticSearch和Kibana构建一个高效、可扩展的日志收集与分析系统。各组件分别承担不同的职责,确保日志数据能够被有效收集、处理、存储及可视化。 ... [详细]
author-avatar
央央说去_531
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有