lucene索引文件大小优化小结_lucene 减少tis文件大小-程序员宅基地

技术标签: 优化小结  lucene  数据库  索引文件大小  

http://www.cnblogs.com/LBSer/p/4068864.html

      随着业务快速发展,基于lucene的索引文件zip压缩后也接近了GB量级,而保持索引文件大小为一个可以接受的范围非常有必要,不仅可以提高索引传输、读取速度,还能提高索引cache效率(lucene打开索引文件的时候往往会进行缓存,比如MMapDirectory通过内存映射方式进行缓存)。

      如何降低我们的索引文件大小呢?本文进行了一些尝试,下文将一一介绍。

1 数值数据类型索引优化

1.1 数值类型索引问题

        lucene本质上是一个全文检索引擎而非传统的数据库系统,它基于倒排索引,非常适合处理文本,而处理数值类型却不是强项。

        举个应用场景,假设我们倒排存储的是商家,每个商家都有人均消费,用户想查询范围在500~1000这一价格区间内的商家

       一种简单直接的想法就是,将商家人均消费当做字符串写入倒排(如图所示),在进行区间查询时:1)遍历价格分词表,将落在此区间范围内的倒排id记录表找出来;2)合并倒排id记录表。这里两个步骤都存在性能问题:1)遍历价格分词表,比较暴力,而且通过term查找倒排id记录表次数过多,性能非常差,在lucene里查询次数过多,可能会抛出Too Many Boolean Clause的Exception。2)合并倒排id记录表非常耗时,说白了这些倒排id记录表都在磁盘里。

       当然还有种思路就是将其数字长度补齐,假设所有商家的人均消费在[0,10000]这一区间内,我们存储1时写到倒排里就是00001(补齐为5位),由于分词表会按照字符串排序好,因此我们不必遍历价格分词表,通过二分查找能快速找到在某一区间范围内的倒排id记录表,但这里同样未能解决查询次数过多、合并倒排id记录表次数过多的问题。此外怎样补齐也是问题,补齐太多浪费空间,补齐太少存储不了太大范围值。

1.2  lucene解决方法

       为解决这一问题, Schindler和 Diepenbroek提出了基于trie的解决方法,此方法08年发表在 Computers & Geosciences (地理信息科学sci期刊,影响因子1.9),也被lucene 2.9之后版本采用。( Schindler, U, Diepenbroek, M, 2008. Generic XML-based Framework for Metadata Portals. Computers & Geosciences 34 (12),论文:http://epic.awi.de/17813/1/Sch2007br.pdf

       简单来说,整数423不是直接写入倒排,而是分割成几段写入倒排,以十进制分割为例,423将被分割为423、42、4这三个term写入, 本质上这些term形成了trie树(如图所示)。

       如何查询呢?假设我们要查询[422, 642]这一区间范围的doc,首先在树的最底层找到第一个比422大的值,即423,之后查找423的右兄弟节点,发现没有便找其父节点的右兄弟(找到44),对于642也是,找其左兄弟节点(641),之后找父节点的左兄弟(63),一直找到两者的公共节点,最终找出423、44、5、63、641、642这6个term即可。通过这种方法,原先需要查询423、445、446、448、521、522、632、633、634、641、642这11次term对应的倒排id列表,并合并这11个term对应的倒排id列表,现在仅需要查询423、44、5、63、641、642这6个term对应的倒排id列表并合并,大大降低了查询次数以及合并次数,尤其是查询区间范围较大时效果更为明显。

       这种优化方法本质上是一种以空间换时间的方法,可以看到term数目将增大许多。

 

       在实际操作中,lucene将数字转换成2进制来处理,而且实际上这颗trie树也无需保存数据结构,传统trie一个节点会有指向孩子节点的指针同时会有指向父节点的指针,而在这里只要知道一个节点,其父节点、右兄弟节点都可以通过计算得到。此外lucene也提供了precisionstep这一字段用于设置分割长度,默认情况下int、double、float等数字类型precisionstep为4,就是按4位二进制进行分割。precisionstep长度设置得越短,分割的term越多,大范围查询速度也越快,precisionstep设置得越长,极端情况下设置为无穷大,那么不会进行trie分割,范围查询也没有优化效果,precisionstep长度需要结合自身业务进行优化。

1.3 索引文件大小优化方案

        我们的应用中很多field都是数值类型,比如id、avescore(评价分)、price(价格)等等,但是用于区间范围查询的数值类型非常少,大部分都是直接查询或者为进行排序使用。

        因此优化方法非常简单,将不需要使用范围查询的数字字段设置precisionstep为Intger.max,这样数字写入倒排仅存一个term,能极大降低term数量。

复制代码
 1 public final class CustomFieldType {
 2     public static final FieldType INT_TYPE_NOT_STORED_NO_TIRE = new FieldType();
 3     static {
 4         INT_TYPE_NOT_STORED_NO_TIRE.setIndexed(true);
 5         INT_TYPE_NOT_STORED_NO_TIRE.setTokenized(true);
 6         INT_TYPE_NOT_STORED_NO_TIRE.setOmitNorms(true);
 7         INT_TYPE_NOT_STORED_NO_TIRE.setIndexOptions(FieldInfo.IndexOptions.DOCS_ONLY);
 8         INT_TYPE_NOT_STORED_NO_TIRE.setNumericType(FieldType.NumericType.INT);
 9         INT_TYPE_NOT_STORED_NO_TIRE.setNumericPrecisionStep(Integer.MAX_VALUE);
10         INT_TYPE_NOT_STORED_NO_TIRE.freeze();
11     }
12 }
复制代码

1.4 效果

      优化之后效果明显,索引压缩包大小直接减少了一倍。

2 空间数据类型索引优化

.1 地理数据索引问题

       还是一样的话,lucene基于倒排索引,非常适合文本,而对于空间类型数据却不是强项。

       举个应用场景,每一个商家都有唯一的经纬度坐标(x, y),用户想筛选附近5千米的商家。

       一种直观的想法是将经度x、维度y分别当做两个数值类型字段写到倒排里,然后查询的时候遍历所有的商家,计算与用户的距离,并保留小于5千米的商家。这种方法缺点很明显:1)需要遍历所有的商家,非常暴力;2)此外球面距离计算非涉及到大量的三角函数计算,效率较低(博主研发了一种快速距离计算方法,能提高至少10倍计算速度:地理空间距离计算优化)。

       简单的优化方法使用矩形框对这些商家进行过滤,之后对过滤后的商家进行距离计算,保留小于5千米的商家,这种方法尽管极大降低了计算量,但还是需要遍历所有的商家。

2.2  lucene解决方法

         lucene采用geohash的方法对经纬度进行编码(geohash介绍参见:GeoHash)。简单描述下,geohash对空间不断进行划分并对每一个划分子空间进行编码,比如我们整个北京地区被编码为“w”,那么再对北京一分为4,某一子空间编码为“WX”,对“WX”子空间再进行划分,对各个子空间再进行标识,例如“WX4”(简单可以这么理解)。

         那么一个经纬度(x,y)怎样写入到倒排索引呢?假设某一经纬度落在“WX4”子空间内,那么经纬度将以“W”、“WX”、“WX4”这三个term写入到倒排。

         如何进行附近查询呢?首先将我们附近5km划分一个个格子,每个格子有geohash的编码,将这些编码当做查询term,去倒排查询即可,比如附近5km的geohash格子对应的编码是“WX4”,那么直接就能将落在此空间范围的商家找出。

2.3 索引文件大小优化方案

       上述方法本质上也是一种以空间换时间的方法,比如一个经纬度(x,y),只有两个字段,但是以geohash进行编码将产生许多term并写入倒排。

       lucene默认最长的geohash长度为24,也就是一个经纬度将以24个字符串的形式来写入到倒排中。最初采用的geohash长度为11,但实际上针对我们的需求,geohash长度为9的时候已经足够满足我们的需求(geohash长度为9大约代表了5*4米的格子)。

      下表表示geohash长度对应的精度,摘自维基百科:http://en.wikipedia.org/wiki/Geohash

geohash length
lat bits
lng bits
lat error
lng error
km error
1 2 3 ±23 ±23 ±2500
2 5 5 ± 2.8 ± 5.6 ±630
3 7 8 ± 0.70 ± 0.7 ±78
4 10 10 ± 0.087 ± 0.18 ±20
5 12 13 ± 0.022 ± 0.022 ±2.4
6 15 15 ± 0.0027 ± 0.0055 ±0.61
7 17 18 ±0.00068 ±0.00068 ±0.076
8 20 20 ±0.000085 ±0.00017 ±0.019
1 private void spatialInit() {
2         this.ctx = SpatialContext.GEO; // 选择geo表示经纬度坐标,会按照球面计算距离,否则是平面欧式距离
3         int maxLevels = 9; // geohash长度为9表示5*5米的格子,长度过长会造成查询匹配开销
4         SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels); // geohash字符串匹配树
5         this.strategy = new RecursivePrefixTreeStrategy(grid, "poi"); // 递归匹配
6     }

 

2.4 效果

      此优化效果结果未做记录,不过经纬度geohash编码占据了term数量的25%,而我们又将geohash长度从11减少到9(降低18%),相当于整个term数量降低了25%*18%=4.5%。

3 只索引不存储

       上面两种方法本质上通过减少term数量来减少索引文件大小,下面的方法走的是另一种方式。       

       从lucene查出一堆docid之后,需要通过docid找出相应的document,并找出里面一些需要的字段,例如id,人均消费等等,然后返回给客户端。但实际上我们只需要获取id,通过这些id再去请求DB/Cache获取额外的字段。

       因此优化方法是只存储id等必须的字段,对于大部分字段我们只索引而不存储,通过这种方法,索引压缩文件降低了10%左右。

 1 doc.add(new StringField("price", each, Field.Store.NO)); 

4 小结

     本文基于lucene的一些基础原理以及自身业务,对索引文件大小进行了优化,使得索引文件大小下降了一半多。

 

 

检索实践文章系列:

lucene join解决父子关系索引

lucene字典实现原理

排序学习实践

lucene如何通过docId快速查找field字段以及最近距离等信息?

转载请标明源地址:http://www.cnblogs.com/LBSer
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wpw1205/article/details/79416771

智能推荐

android:layout_gravity 和android:gravity 区别 -------浅谈_"gravity=\"center_horizontal|top"-程序员宅基地

文章浏览阅读389次。android:gravity是调整元素本身的内容或元素包含的子元素显示的位置,默认是显示在左侧android:layout_gravity是相对与它的父元素说的,说明元素显示在父元素的什么位置。比如说Button: android:layout_gravity 表示按钮在界面上的位置。 android:gravity表示Button上的字在button上的位置。举个例子:_"gravity=\"center_horizontal|top"

python计算机毕设【附源码】学生社团管理系统(django+mysql+论文)-程序员宅基地

文章浏览阅读574次,点赞17次,收藏13次。提升学生社团的影响力:通过学生社团管理系统,可以将学生社团的优秀活动和成果展示给更多的人,提升学生社团的知名度和影响力。在数据库管理工具的选择上,使用了Navicat 11,这是一个用户友好且功能强大的数据库管理软件,它支持多种数据库系统,包括MySQL,并提供了图形化界面,使得数据库的管理和维护工作更加便捷。培养学生的信息化管理能力:学生社团管理系统的开发和使用,可以让学生在实践中学习和掌握信息化管理的方法和技能,提高学生的信息化素养,为未来的职业生涯打下坚实的基础。

kafka Commit cannot be completed since the group has already rebalanced and assigned the partitions_kafka offset commit failed the request time out-程序员宅基地

文章浏览阅读655次。k8s helm 部署 kafka集群,启动一个producer ,再起一个consumer, 报错如下root@kafka-0:/# kafka-console-consumer --topic test --bootstrap-server kafka-headless.flink.svc.cluster.local:9092[2021-12-10 06:20:04,901] ERROR [Consumer clientId=consumer-1, groupId=console-consumer_kafka offset commit failed the request time out

机器学习-李宏毅| 回归演示 | python_李宏毅线性回归python-程序员宅基地

文章浏览阅读217次。回归的定义Regression就是指找到一个函数functionfunctionfunction,通过输入特征x,输出一个数值ScalarScalarScalar看了李宏毅老师的机器学习课程视频,其中的Regression demo部分,关于预测宝可梦的CP值的应用代码,在jupyter notebook中实现。现在假设有10个x_data和y_data,x和y之间的关系是y_data=b+..._李宏毅线性回归python

python binding_OpenCV-Python Binding(读书笔记)-程序员宅基地

文章浏览阅读159次。OpenCV-Python Binding的思维导图,提炼关键点。11.OpenCV-Python Binding1 目标了解:1.如何生成OpenCV-Python bindings?2.如何将新的OpenCV模块扩展到Python?2 OpenCV-Python bindings如何生成?1. 在OpenCV中,所有算法均以C ++实现。2.但是这些算法可以从不同的语言(例如Python,Ja..._python ./modules/python/src2/gen2.py

3秒自动转页面php,HTML页面3秒后自动跳转的三种常见方法-程序员宅基地

文章浏览阅读6.5k次。在练习中,我们常常遇到一种问题就是,怎么实现页面N秒之后自动跳转呢?我自己遇到问题和查找资料,总结了3个方法方法1:最简单的一种:直接在前面里面添加代码: //3秒之后自动跳转到res.html,两个属于同一文件下面,要是需要跳转到jsp页面,就需要在url里面填写url地址————(浏览器的地址栏里面写入的数据,如:http://localhost:8080/TestDemo/1.jsp)方..._三秒后自动跳转到指定页面

随便推点

SpringBoot获取yml和properties配置文件的内容_applycation.yml中加上version-程序员宅基地

文章浏览阅读2.4k次。一、yml配置文件pom.xml加入依赖 org.springframework.boot spring-boot-configuration-processor ${spring-boot.version}在application.yml文件中加上:#自定义的属性和值myYml: simpleProp: simplePropValue _applycation.yml中加上version

vue 文件及描述信息一起上传_vue上传多个文件,附件和其他数据一起传给后台...-程序员宅基地

文章浏览阅读277次。前端:实现多图上传主要用到以下两个属性:style="padding-left:0px"class="upload-demo"action="admin/zuul/lcloud-elis-rms-gwb/um/rmsAnnex/upload":on-preview="handlePreview":on-remove="handleRemove":before-remove="beforeRemov..._多图上传带描述

初识Dubbo学习,一文掌握Dubbo基础知识文集(4)-程序员宅基地

文章浏览阅读941次,点赞30次,收藏19次。在更高级的安全场景下,Dubbo 还可以与分布式安全管理系统进行集成,确保在复杂的多系统、多环境的分布式安全管理需求下能够提供一致的安全保障。这种方式比较通用,但性能一般。它提供了一套完整的解决方案,包括服务注册与发现、负载均衡、远程调用、断路器、配置管理等,以简化分布式系统开发和维护的复杂性。:Spring Cloud是一套基于Spring Boot的分布式系统开发工具集,提供了众多分布式系统的基础设施,如服务注册与发现、服务调用、负载均衡、断路器、网关等,是构建微服务架构的首选框架之一。

Aop源码分析-程序员宅基地

文章浏览阅读298次。执行之后,打印了前置通知,后置通知,和异常通知,也拿到了方法的名字,参数和异常信息。可以看到这次拿到了结果。_aop源码分析

南林暑期实训 网络技术 day5 day6 day7 vlan通信、ACL、NAT技术、eigrp 协议_思科vlan通信-程序员宅基地

文章浏览阅读186次。一、vlan通信1.1 单臂路由1.1.1 利用子接口和802.1Q技术1.1.2 用三层交换机和vlan接口实现实现vlan通信二、ACL2.1 基础知识三、NAT技术:网络地址转换技术四、路由补充利用NAT实现上网五、eigrp 协议(Cisco特有协议)_思科vlan通信

使用友盟+的APM服务实现对移动端APP的性能监控_友盟性能监控能否传入页面自定义名称-程序员宅基地

文章浏览阅读9.6k次。背景对于信息系统服务,一般我们的重点监控对象都是核心的后端服务,通常会采用一些主流的APM(Application Performance Management)框架进行监控、告警、分析。那么对于移动端的APP、小程序的运行时状态如何进行实时监控与分析呢?经过这次CSDN官方的推荐,友盟+提供的APM服务可以实现我们的这一目标,下面我们就尝试集成体验下友盟+提供的这款APM服务。由于我们的 APP 是基于华为的鸿蒙操作系统进行开发,而注册友盟后,发现当前对于移动端APP,友盟官方提供了 Androi_友盟性能监控能否传入页面自定义名称

推荐文章

热门文章

相关标签