`

(转) lucene索引结构改进-支持单机十亿级别的索引的检索

 
阅读更多

术语解释:

Lucene:是apache软件基金会4 jakarta项目组的一个子项目,是一个开放源代码的全文检索引擎工具包,即它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的 查询引擎和索引引擎,部分文本分析引擎(英文与德文两种西方语言)。Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中 实现全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。

二分查找: 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表, 且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比 较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一 步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

倒排索引:(英语:Inverted index),也常被称为反向索引、置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最常用的数据结构。
 

单机版的lucene只能应对千万级,或百万级的索引,通过修改索引,能够支持10亿以上索引的检索。

当前lucene首次加载需要读取整个索引文件,如果数据量较大,索引文件也很大,会照成内存瓶颈。

 

 

     Lucene 使用倒排索引进行文档的检索,假设存在三个文档

中华人民共和国

人民英雄

中华美食

     Lucene在创建索引的的过程中,会将三个文档按照分词结果进行倒排,组成一个倒排表tis文件

中华 {1,3}

人民 {1,2}

共和国 {1}

英雄 {2}

美食 {3}

     这样当用户搜索“中华”这个关键词的时候,根据倒排  “中华 {1,3}”就可以知道在文档1和3中含有此关键词,文档1和3就会返回给用户。

     我们通常将倒排表中的每个词语叫做一个term,如果想知道,人民这个term对应那些文档,必须先知道 人民这个term在倒排表中位置,然后才能知道这个term (人民)对应那些文档({,2}),故首先要进行的是对term的查找,找到term所在的位置

以上述倒排表为例,假设,中华在倒排表中的偏移量为1,人民的偏移量为2,共和国为3,英雄为4,美食为5

这里的偏移量为距离文件起始的位置,知道了偏移量,就可以通过seek操作,将文件指针直接定位到目标term所在的位置,然后就可以读取文档ID,也就是查询的结果了。

另外很重要的一点是,lucene创建索引的时候会保证倒排表的term是有序的。

     Lucene采用128跳跃表的方式创建索引,原理如下

由于lucene索引本身是有序的特点,lucene会在索引文件里存储一些关键term,

 假设倒排表里一共有1280个term,那么第1个term,第129个term,257…,1281 一个11个关键term以及偏移量会存储在索引文件tii中。

在进行term的检索前,lucene会将tii文件中的所有关键term,加载到内 存里,以数组的形式存储,当然也是有序的。当我们要检索一个term,首先会在内存里检索此term会落在那两个关键term之间,因为有序的原因,目标 term肯定会在这两个term之间,然后根据两个关键term中较小的term的偏移量,从倒排表tis文件中的偏移量的位置之后开始查找,由于跳跃表 的间隔是128位,那么最多比较128次就可以查找到这个term了。

     128跳跃表存在的问题

在进行term检索前,索引文件tii要全部加载到内存里,如果term的数量比较 少,那么不会存在问题,但是如果term特别多,比如说10亿,那么也要消耗几十G的内存(视term的长度不同而不同),普通物理机器一般是没有这么大 的内存的,所以导致lucene因程序崩溃而无法进行检索。另外每次加载索引也是很消耗时间的,如果初级开发者,使用不当,每次都是打开与关闭 lucene,那就会导致索引文件被反复重复加载,也是影响检索性能的。

     那怎么解决?

Lucene倒排表tis文件有个显著的特点是,term是有序的,而偏移量是定长的long类型,那么正好适合还用二分查找(折半查找)。

Tii索引文件存储的内容修改为lucene倒排表tis中的每个term的偏移量。根据偏移量我们可以到tis文件中得到对应的term的值。

假设倒排表中一共有1000个term,我们的目标term在第501个term上, 那么二分查找首先会根据中间(折半)位置的term进行比较,也就是根第500个位置的term进行比较,发现目标term应该在500到1000这个区 间内,然后这个区间内在进行折半查找,定位在500~750这个区间,然后进一步定位500~625,500~564,500~532,500~516, 最终找到目标term的偏移量。

 

在这个过程中,索引文件没有加载到内存里,对内存的依赖较少,假设有100亿个term,那么最坏的情况,进行折半的次数为34次。

另外由于折半的特点,1/2,1/4,1/8,1/16…这些点都是高命中的点,可以 根据物理机器的内存多少,也可以预先加载到内存里,但是与128跳跃表相比,这里加载内存里的都是高命中的区域,对内存的使用率会高很多。如果缓存 16384个位置,那么久可以额外减少14次seek,那么100亿仅仅需要20次的文件seek,但是如果跟原先的进行对比的话,旧的128跳跃表最坏 情况下需要128次seek,平均为64次seek,远远高于二分法的seek次数。而且二分法由于可以在高命中点使用cache,可以进一步减少 cache的数量。

 

     存在问题以及细节的优化

随着term数量的增加,折半查找引起的seek的次数会增加,10000个term要进行12次查找,10万要进行15次,100万进行20次,1000万23次,一亿26次,10亿29次,100亿34次。

2. Term压缩方式由原先,存储上一条记录的差异,存储关键点的差异(这样会照成压缩比降低,但是二分法必须这样做)

3.如果索引二分查找文档差异<128则,保留原先链表顺序查找,调用scan方法(这样做尽管读的次数增多,但考虑磁盘的物理特点,操作系统通常有文件缓冲区,连续的数据读取速度会比不断的跳跃的seek快,物理硬盘适合读取连续的数据),这样可以用1~128此的连续seek,来减少约6~7次左右的跳跃性的seek.

4. 由于norms同样非常消耗内存,这里创建索引的时候禁用norms,待以后改进此处,当前lucene也存在此问题,不过也可以采用同样的二分法来解决此问题,禁止全部加载进内存。

 

1.        Lucene TermInfosReader使用的128位的跳跃表,示例如下

 

 

在检索的时候,跳跃表需要加载内存里,在千万级别内的term,检索速度比较理想(但是也需要1~128次的seek),但是如果term数量达到亿的级别,有可能会突破单台机器物理内存的限制,目前业界几乎都是采用分布式,打散成多个索引的方式来减少这个跳跃表的长度,但是单机也是能够支持上十亿keyvalue的检索(这个地方可以采用定长的数据类型,而且luceneTermInfos这种结构,本身就是有序的,可以支持二分法查找,如果在结合cache,不但不会像跳跃表那样耗费太多的内存,因减少了seek的数量,检索时间也会有所提升,而且支持无限大的term数量,取决于硬盘大小)

    当前lucene首次加载需要读取整个索引文件,一般需要成长连接的方式,对开发者要求较高,采用二分法的索引文件就没有此问题。

 

 

 

下表为对100W~10亿条md5值进行创建索引以及查询的情况

读的时间为查询10Wmd5的时间,单位毫秒

写为创建完整索引的时间,单位为毫秒。

 

记录数

10W记录时间

每条记录时间

创建索引时间

索引总大小

Tii文件大小

 

一百万

13667

0.13667

14338

87.6 MB

7.62 MB

 
 

二百万

14400

0.144

25508

175 MB

15.2 MB

 
 

一千万

20234

0.20234

120262

4.26 GB

381 MB

 
 

一亿

2289399

22.89399

1360215

8.51 GB

762 MB

 

五亿

3793413

37.93413

12249876

42.6 GB

3.72 GB

 

十亿

5063614

50.63614

27365596

85.2 GB

7.45 GB

 
 

 

 

Lucene压缩算法简介

Lucene采用压缩的方式进行创建索引

         对于字符串类型

文件链表的第一条记录存储的是完整的信息,第二条记录存储的是跟第一条记录的差异。

举例来说,第一条记录为 abcdefg,如果第二条记录为abcdefh,他们的差异只有h,故第二条记录仅仅会存储一个长度,加上差异的字符,就是存储6+h

对于lucene这种索引结构来说,由于索引是排序过的,故压缩比非常可观。

         数值类型的

常见对于文件偏移量的压缩,与字符串形式的压缩类似,但采用的与前一条记录的差值进行存储,如果第一条记录为8,第二条记录为9,则第二条仅仅存储9-8=1,lucene存储整形也是变长的索引,lucene通常是以append的方式创建索引,故这种压缩方式很有效。

         新索引对于压缩的改变

由于上述lucene的 压缩方式,在修改成二分法的时候,无法使用,故需要放弃一定的压缩率。我们采取定义关键点的方式来压缩,关键点存储完整数据,后面的点跟关键点比较差异, 这个跟视频图像压缩的关键帧非常相似,关键帧存储完整的图像信息,后面的帧仅仅存储差异,变化。这样可以节省计算差异的时间消耗(对lucene来说这点微不足道,不是这里解决的主要问题),但是压缩比会降低。

分享到:
评论
1 楼 zhuhuixiao 2014-02-27  
lucene的跳跃表是有层次的

相关推荐

    lucene并行索引

    传统的单机索引方法已无法满足高效处理大规模数据的需求,尤其是在搜索引擎领域。Lucene作为一款优秀的全文检索引擎库,其高效、灵活的特点受到了广泛的关注。然而,在面对海量数据时,Lucene的索引构建过程可能会变...

    lucene-4.6.1官方文档

    Lucene 支持在一个文档中对多个字段进行索引和搜索,这对于复杂的信息检索需求非常有用。此外,4.6.1版本对多语言的支持也有所加强,提供了多种语言的Analyzer,满足国际化的搜索需求。 6. **更新与删除操作**: ...

    lucene-4.1.0

    随着数据量的增长,单机索引可能无法满足需求。Lucene通过Solr等工具支持分布式搜索,允许多台服务器协同工作,处理大规模数据。 8. **性能提升(Performance Enhancements)**: Lucene 4.1.0引入了更快的文档遍历...

    Lucene搜索-引擎开发权威经典pdf+源码第二部分

    7. **分布式搜索**:随着数据量的增大,单机索引可能无法满足需求,因此需要了解如何利用Solr或Elasticsearch等基于Lucene的分布式搜索解决方案。 8. **性能优化**:这部分可能涵盖索引和查询性能的优化策略,如...

    Lucene实战(第二版)

    通过分析和运行这些代码,读者可以学习如何配置Lucene索引,如何处理各种类型的文档数据,以及如何实现高效的查询和排序机制。 以下是一些关键知识点的详细说明: 1. **全文检索**:Lucene的核心功能是支持高效的...

    lucene in action 书中例子源码

    在3.0版本中,Lucene引入了许多增强功能和改进,比如更高效的倒排索引结构、新的查询解析器和过滤器等。 在这个压缩包中,我们可以期待找到以下知识点: 1. **文本分析**:Lucene的Analyzer类是处理文本的关键,它...

    Lucene in action配套源代码

    1. **索引构建**:展示了如何使用Lucene来读取和索引文本数据,包括从文件系统、数据库或其他数据源中抽取内容,并将其转换为可供搜索的索引结构。这通常涉及到分析器(Analyzer)的选择,如标准分析器、中文分词器...

    Java搜索引擎 Lucene.7z

    Lucene的核心功能包括索引和搜索,支持丰富的查询语法,以及对文本分析的高级处理。 1. **什么是Lucene?** Lucene是一个纯Java库,它可以将数据结构化为索引,以便快速搜索。它处理文本,将其分词并创建倒排索引...

    Lucene 实战(第2版)中文带书签.pdf

    1. **Lucene基础**:介绍了Lucene的基本架构,包括倒排索引的概念、文档的存储与检索方式,以及如何使用Lucene进行基本的索引和搜索操作。 2. **索引构建**:详细讲解了如何创建、更新和优化索引。包括字段分析、...

    lucene.net源码

    - Lucene.NET支持多种查询类型,如布尔查询、短语查询、模糊查询等。查询执行后,会根据查询的相关度对结果进行评分,评分高的结果优先展示。 5. **更新与删除** - Lucene.NET允许动态更新索引,即添加、修改或...

    lucene包 java搜索好东西

    Lucene提供了高级的文本分析、索引和搜索功能,广泛应用于各种信息检索系统,包括网站搜索、文档检索、邮件过滤等场景。 1. **全文搜索引擎基础** Lucene的核心思想是将非结构化的文本数据转化为结构化的索引,...

    lucene高级搜索进阶项目_01

    Solr和Elasticsearch是在Lucene基础上构建的分布式搜索平台,它们提供集群管理和负载均衡,能处理PB级别的数据,并支持复杂的查询和聚合操作。 六、扩展应用 1. ** autocomplete**:利用Lucene的PrefixQuery或...

    自己动手写搜索引擎

    - 在这一章节中,作者深入探讨了Lucene索引的建立过程,包括索引的结构、索引文档的格式、文档的分词处理等内容。此外,还介绍了如何优化索引的性能,例如使用批量索引来提高效率。 #### 四、使用Lucene进行搜索 -...

    Lucene in Action

    Lucene是Java平台上最流行、最强大的开源搜索库之一,它为开发者提供了丰富的文本检索和分析功能。 该书首先会引导读者了解搜索的基本概念,包括倒排索引、TF-IDF(词频-逆文档频率)等核心算法。通过这些基础知识...

    Manning.Lucene.in.Action.2nd.Edition.Jun.2010.MEAP.rar

    1. **Lucene概述**:Lucene是一个高性能、可扩展的信息检索库,支持全文检索、布尔查询、短语查询、模糊查询等多种搜索方式。它提供了一个Java API,开发者可以将其集成到Java应用程序中,构建自己的搜索引擎。 2. ...

    Solr3.5开发应用指导

    - **1.2.1 Solr使用Lucene并且进行了扩展**:Solr是一个开源的高性能搜索引擎,它基于Lucene构建,提供了更高级别的功能和服务,如全文检索、自动完成和实时更新等。 - **1.2.2 Schema(模式)**:Solr使用Schema来...

    开源企业搜索引擎SOLR的应用教程

    - **SOLR的使用过程说明**:从设计索引结构、构建索引到执行搜索,整个流程都非常直观。 - **一个简单的例子**:通过一个具体的例子来展示如何设计Solr Schema、构建索引以及进行搜索测试。 - **搜索引擎的规划设计*...

    开源企业搜索引擎SOLR的 应用教程

    通过Schema,可以灵活地定义索引结构,满足不同类型的搜索需求。 - **1.2.3 查询** Solr支持丰富的查询语言,包括全文查询、范围查询、模糊查询等,使得用户能够精确地找到所需的信息。 - **1.2.4 核心** 每个...

    Solr.学习文档

    Solr 是一个高度可扩展的、高性能的、开源的企业级搜索平台,它基于 Lucene 构建,能够提供强大的全文检索功能。Solr 可以用于各种应用环境中,包括网站搜索、电子商务商品搜索等场景。其主要特性包括:高可用性、...

Global site tag (gtag.js) - Google Analytics