本篇文章我们来了解一下solr的性能方面的调优,分为Schema优化、索引更新与提交调优、索引合并性能调优、Solr缓存、Solr查询性能优化

Schema优化

  1、index=true比index=false在索引时占用更多的内存、索引合并和优化时间更长,索引体积也响应变的更大,如果你不需要针对该域进行检索,可以设置为index=false

  2、如果不关心Term在文档中出现的次数对最终文档的影响可以设置omitNorms=true,即取消标准化因此对score的影响。它能减少磁盘空间的占用并加快索引速度

     3、如果你不需要对该域进行高亮,你还可以设置omitPositions=true进一步减小索引体积

  4、如果只需要利用倒排索引结构根据指定的Term找到对应的document,不需要计算Term在Document中的出现频率来考虑每个索引文档的权重,那么还可以设置omitTermFreqAndPositions=true即忽略TF计算以及Term在TermVector中的位置信息,这样能够进一步减小索引体积

  5、对于stored属性而言,在响应结果集中通过FL参数返回stored=true的域的执行开销很大,因为域值需要存储到硬盘写IO,查询时提取域值需要磁盘读IO,如果不需要存储可以设置stored=false,进一步优化索引的体积

  6、如果你想要存储的域值长度并不大, 但是为了能够缓解提取存储域带来的磁盘IO,此时可以设置compressed=true即启用域值数据压缩。开启compressed会降低磁盘IO但会增大CUP开销

  7、如果并不是一直都需要使用存储域,你可以设置域延迟加载,尤其是当你开启了域值数据压缩。设置延迟加载开启延迟加载之后,要返回的字段会被SetNonLazyFieldSelector立即加载,其他的域为延迟加载。启用域延迟加载,需要在solrconfig.xml中进行如下配置  

<enableLazyFieldLoading>false</enableLazyFieldLoading>

  8、如果你的域值很大,可以使用ExternalFileField域(外部文件),他不支持solr查询,只能用于显示和function计算,还可以将域值储存在外部系统,比如redis等,当需要域值的时候根据solr的UniqueKey去缓存中提取

  9、对于Java里的日期时间类型的数据,建议你使用Solr里的date域类型,如果你需要进行日期时间范围区间查询,那么建议使用Solr里的date域类型,而不是使用string域类型

  10、可以对facet域、排序域设置为docValue=true,它将会生成一个额外的正排表,会提升分面和排序的效率

  

索引更新与提交调优

  1、不建议使用显示硬提交,建议在solrConfig里面配置自动软/硬提交方式

   2、客户端在提交索引文档的时,建议使用批量软提交的方式添加索引文档

   3、单机模式下,在提交索引的时候建议使用ConcurrentUpdateSolrClient类,对于solrCloud模式下建议使用CloudSolrClient类来更新或提交索引

   4、默认情况下,solr会将document的每个域域值进行索引,当在对一些大文档进行索引的时候,因为创建索引过程中solr需要将document缓存在内存中,如果域的域值很大,内存占用就很大,可能触发更频繁的GC,GC可能会导致暂停索引创建过程,对一些大文本域使用的域类型配置LimitTokenCountFilterFactory来限制实际索引的文本长度,从而减少索引过程中内存占用

   5、在创建索引的时候,需要对文本进行分词处理时,建议配置停止词来剔除掉无用的噪音词,从而减少索引体积,同时还可以避免噪音词印象最终的检索结果

   6、禁用CompoundFile(复合)文件:开始复合文件虽然可以减少段文件个数,但是它会使得你的索引创建时间增加7%~33%,具体配置如下  

<useCompoundFile>false</useCompoundFile> 
<mergePolicy class=”org.apache.lucene.index.TieredMergePolicy”>
<float name=”noCFSRatio”>0.0</float>
</mergePolicy>

   7、如果索引速度经过一系列优化还是比较慢,建议可以使用MapReduce框架,利用多台机器的资源并行创建solr索引,从而加快索引速度

 

索引合并性能调优  

   1、降低索引合并频率:索引合并之后能加快Solr查询性能,但是索引合并是一个执行开销很大的操作,因此你需要在保证查询性能的前提下,尽量的降低索引合井的频率

  2、加大ramBufferSizeMB和maxBufferedDocs参数值,并且尽量降低显式提交的频率:索引提交除了用户显式的执行commit操作之外,ramBufferSizeMB或者maxBufferedDocs参数达到限定的阔值之后也会自动触发索引提交。 因此,为了降低索引合并的频率, 应该加大ramBufferSizeMB和maxBufferedDocs参数值,并且尽量降低显式提交的频率,比如采用批量commit,或者直接在solrconfig刀nl 中配置自动提交并控制自动提交的频率,避免显式提交

  3、增大mergeFactor参数值:加大mergeFactor参数值确实可以加快索引创建速度,降低索引合并频率但是同时它也会降低你的Solr查询响应速度

 

Solr缓存

  Solr中缓存都是由SolrIndexSearcher实例来管理的,一个SolrIndexSearcher实例对应一套缓存体系,如果你新建立一个SolrIndexSearcher实例,那么之前的SolrIndexSearcher全部会失效,当你数据量很大的时候,增量很频繁的时候对缓存的依赖很大,这个之后你需要在新建SolrIndexSearcher进行缓存预加载,术语叫预热

  solr默认的4中缓存类型

 

  1、filterCache

    用于缓存Filter Query从硬盘提取出来的Document的无序ID ,下次执行相同的FieldQuery就直接会命中缓存。Solr会默认为每一个FilterQuery提供FilterCache.

  应用场景:

  1)  缓存所有FilterQuery返回的结果集,solr会将主Q查询的结果集和Filter缓存的无序Document ID set集合取交集

  2)  当facet.method=enum时候会命中Filter缓存

  3)  如果solrconfig.xml中配置了<useFilterForSortedQuery/>true</useFilterForSortedQuery>,那么对于Solr排序操作也会使用Filter缓存。

  4)  Filter缓存通常还会用于其他Solr查询,比如facet.query、 group.query

  不适用场景

  价格区间、时间区间查询:全品类价格区间太多,时间精确到秒。如果对每一个价格区间的FilterQuery都启用FilterCache需要大量的内存支撑,另外由于区间太复杂,缓存命中率也会大大下降,所以这个时候我们可以类似这样的FilterQuery禁用Filter缓存

  2、documentCache

  DocumentCache(即文档缓存):用于储存已经从磁盘上提取出来的Lucence中的document对象。Document缓存保存的最大项数:应该大于返回结果集中可能的最大值*查询的最大并发量。 这样做的目的是因为为了确保solr不在从磁盘上提取索引文档,但是随着doc数目越来也多,documentCache占用的内存就会越来越大

  当你开启了document缓存并且开启了延迟加载,那么indexReader所提取的对象仅仅包含fl参数指定的Field,其他的Field会被延迟加载,这么做可以减少document缓存对内存的占用,当延迟加载的域,被后续请求到,那么indexReader会临时从硬盘加载该域

  还需要注意的是document缓存并不能进行缓存预热,也就意味这次当打开了一个SolrIndexSearcher的时候,缓存并不会提前进行加载,因为document缓存使用的是lucence内部的document ID,当索引数据变化了之后,该ID也会发生变化

 

  3、queryResultCache

  QueryResult缓存(查询结果集缓存):用于缓存查询的TOP N结果集的有序的Document ID,按照排序域进行排序。查询结果集缓存的内存占用明显要比Filter小,因为只有q,fq,sort参数同时一致的查询才会命中缓存

 

  4、fieldValueCache

  fieldValueCache(即域值缓存):与lucence中的fieldCache相似,但是不同的是FieldValueCache支持每个document对应多个值(多值域的多个值域,或者单值域因分词产生多个Term)。此缓存多用于facet查询,缓存的key为域的名称,value为docid到多个值的映射的数据结构。如果solrconfig.xml中没有定义<fieldValueCache>,那么Solr会自动为你生成一个size=10, max Size= 10 000,无autowarm的<fieldValueCache>

  

  HTTP缓存:除了可以在后台服务层启用Solr缓存之外,你还可以在前端HTTP协议层启用HTTP缓存,对于没有更新的资源,可以直接从HTTP缓存中直接返回,避免了同样的查询请求频繁请求服务器,这能在一定程度上减轻Solr Server的负载压力。如果想要开启HTTP缓存,配置如下:  

<httpCaching never304=”false”>
<cacheControl>max-age=30,  public</cacheControl> 
</httpCaching>

或者

<httpCaching lastModifiedFrom=”openTime” etagSeed=”Solr”>
<cacheControl>max-age=30,  public</cacheControl> 
</httpCaching>

  never304参数设置为false 即表示开启Solr中的HTTP缓存,默认never304=true即禁用HTTP缓存。 Solr中的HTTP缓存只支持GET和HEAD请求,不支持POST请求。 SolrHTTP缓存兼容HTTPI.O和HTTPl.l协议头信息。

  你还可以在solrconfig.xml 配置firstSearcher和newSearcher事件监昕器来自动触发缓存自动预热。

  newSearcher用于当一个新的IndexSearcher实例被创建时,除了从旧IndexSearcher实例自动预热一部分缓存之外,还可以显式的指定一个查询来对缓存进行预热。 当某个查询耗时很长时,你可以提前通过newSearcher监昕器进行预热,这样后续你再执行该慢查询时会直接命中缓存。

  firstSearcher表示当一个新的IndexSearcher实例正在被初始化并且当前没有旧的Index Searcher实例用于新的IndexSearcher实例进行缓存自动预热,此时你需要显式的指定一个查询来自动预热缓存。 这个firstSearcher主要用于配置Solr刚启动时执行什么查询并放入缓存。 因为Solr刚启动时,缓存肯定是空的,为了保证刚启动的一段时间内的查询性能高效,因此你需要配置firstSearcher来提取预热。

  当使用que可Result缓存时,你还可以额外添加<queryResultWindowSize>配置来对其进行优化。 当一个查询被执行,返回的DocumentID会被收集,比如查询匹配的documentID是[10, 19)之间,如果queryWindowSize= 50,那么DocumentID [0, 50] 会被收集并缓存,在此范围内的Document将会命中缓存

 

Solr查询性能优化

  1、如果你的查询需要在三个域上进行查询,此时可以用copyField将三个域合并成为一个域,在合并之后的域上进行查询。因为在单个域上进行查询比在N个域上进行查询效率要高。但是使用copyField之后,你无法为每个单独的域进行加权

  2、应该优先让那些能够过滤掉大部分索引文档的FilterQuery先执行

  3、在对数字域进行范围查询的时候,可以调整precisionStep来对rangeQuery进行优化。precisionStep默认值是4,这个值越大,分解出来的索引前缀索引就越多,数字范围查询越快,但是会增大索引体积

  查询方面的优化点还有很多,需要针对不同的场景不同的去分析使用。大部分是在学习solr的过程中自己就可以体会到的,所以在这里不在赘述了