solr 插入数据后变数组

时间: 2023-10-04 admin IT培训

solr 插入数据后变数组

solr 插入数据后变数组

为了得到最好的检索性能,Solr会在内存中缓存不同的数据:

Result Set: 检索结果

Filter: filter query结果

Document Field: 文档的字段值

所以随后类似的检索可以被快速处理。

Solr缓存并不复杂,但是理解它们是如何工作的,知道如何调整以适应自己的业务就比较重要了。本文介绍Solr各种不同的缓存,观察它们内存使用情况,并讨论如何知道缓存设置正确了。

如果在Solr索引中搜索“牛仔裤”,你会发现用了几十到几百毫秒取到结果。试试再次搜索,会取得相同的结果,但是使用的时间减少了。这就是缓存的作用。有操作系统级别的缓存起的作用,当然还有Solr缓存。

1, Solr Cache类型

Solr缓存不同种类的数据,确保类似的检索时,不会做一些不必要的工作。有三种主要的缓存:

Query Cache: 保存query返回的Document ID。如果你的检索返回1000个结果,那么所有1000个Document ID会被保存到Query Cache。并且有Query String与之对应。

Filter Cache: 保存filter query过滤结果。如果检索使用fq参数,例如:fq=category:男装。Solr会把过滤条件和对应的结果记录在缓存中。

Document Cache: 保存Document的字段值。当你向Solr发起一个检索,使用fl参数指定返回哪些字段。Solr会缓存返回Document的字段,以减少后续请求取得字段值的时间。

在后面部分,我们会看到这几种不同的缓存和它们使用的内存量。然后,会看到一些判断缓存大小是否被正确设置的工具。

2, Query Cache

假如要搜索“牛仔裤”,Solr是这样处理检索请求的:

首先Solr会先分词,把“牛仔裤”分成“牛仔”和“裤”

Solr在索引中找到所有包含“牛仔”的Document,返回Document ID列表。一个Document ID代表包含“牛仔”这个词的Document。

对于“裤”这个词,重复上一个过程。

最后,合并生成的两个列表。如果默认使用OR,Solr会取并集。如果默认使用AND,Solr会取并集。

随着查询变得更复杂,Solr会做更多的工作。如果要搜索“牛仔裤 皮带 -category:男装”。Solr会找到4套Document ID,合并前三套Document ID,然后减掉满足否定条件的Document ID。

因为有齐夫定律,情况大多是这样的:某些特定的检索,会一次又一次重复出现。长尾检索只会出现几次。查看搜索log,会发现最流行的检索次数是下一个流行的检索近2倍。这样一级一级地找,很快就会缩小到大量只出现过一次的检索。

Query Cache与这些大量重复的检索有很大关系。每次Solr计算出符合检索的Document ID集合,Solr就把结果保存在Query Cache中。如果另外一个相同的检索:“牛仔裤 皮带 -category:男装”请求进来,Solr能什么都不用做,立刻返回结果。

Query Cache并不只是为了重复的流行检索。Solr接口提供分页取得检索结果,Query Cache对分页结果取得也有好处。从Solr的视角看问题,用户一次次点击下一页,相当于重复相同的检索过程。Query Cache可以减少取得后续页面数据的工作量。

Query Cache用整数数组保存数据,每个缓存实体由两部分组成:Query部分和Document ID部分。Query部分保存Query String,大小由String自身大小决定。Document ID部分保存Document ID,每个Document ID由8个字节一个保存。举个简单的例子:

如果每个Query平均50个字符长度(100字节)

每个Query返回10000个结果(每个ID有8个字节,一共80000字节)

这样每个缓存实体刚刚超过80K

如果配置Solr的Query Cache可保存1000个实体。那么大约需要80M内存。

3, Filter Cache

Filter Cache是Query Cache的亲密伙伴。Filters限定了搜索范围。比如下面的例子,Query如下:

/select?q=牛仔裤&fq=category:男装会返回“牛仔裤”的结果,但category必须是男装。

你可能会想,这样写不是也可以吗:/select?q=牛仔裤+AND+category:男装

大体上是这样的,但使用Filter有下面几点好处:

使用Filter Query不会影响结果的相关性排序。就算category是男装的Document,它的相关性权重也不会提高。

将多余的词与Query分开,这意味着对“牛仔裤”的搜索,可以命中缓存,不必再做真搜索了。

Filter可以被缓存并重复利用,如果Filter被使用多次,速度很快。

从概念上讲,可以把Filter想像成Document ID的大集合。使用Filter的Query叫做filtered query。Solr是这样处理filtered query的:首先像处理普通query一样,生成Document ID结果集,然后与Filter的结果集做交集。所有在query结果集中,但不在filter结果集中的Document会被剔除。剩下的是最后的filtered query检索结果。

注意一旦取得Filtercategory:男装的Document ID集合,就可以一次次重复使用,去处理相同的filtered query。如果用户执行下面三个Query:

/select?q=牛仔裤&fq=category:男装

/select?q=运动鞋&fq=category:男装

/select?q=帽子&fq=category:男装

那么,Filter被执行3次,其中2次是并没有什么性能开销的。Filter理想的使用方式是:划分那些可预见的子集,比如男装分类、有权限查看的集合、2015年创建的,等等诸如此类。

Filter Cache支持了Filter的多次重复使用。一旦Solr构建了Filter对应的Document ID集合,就会被保存到Filter Cache,以备重复使用。

与Query Cache一样,Filter Cache使用的内存可能会很大。Filter结果是这样存储的,用一个bit位表示Document是否符合Filter条件。如果索引中有100万Document,那么需要100万个bit位,换算一下,8位一个字节,那么需要125KB的空间。如果Filter Cache保存1000个缓存实体,那么一共占用的内存量为120M。

4, Document Cache

最后关注一下Document Cache。当查询Solr时,我们想要的不仅仅是Document ID,还有其它信息,比如:价格、商品名等等。在索引数据期间,把这些字段设置为stored,这样就可以在查询时再取回这些字段。

当Solr返回搜索结果时,会发送请求的stored字段。为了取得这些字段的值,必须单独从索引里读取。访问硬盘数据结构取得与Document ID对应的字段。读取硬盘上的数据,比读内存中的数据慢。

如果某些Document被频繁请求,Solr会把它的字段保存到内存中,节省读取字段值的性能损耗。这就是Document Cache。大体来说,Document Cache对性能方面的影响,没有另外两个Cache影响得那么大。同一个Document通常不会频繁请求,所以Cache的命中率通常比较低。

如果有很多stored段,或者stored字段很大,可能就需要让Document Cache相对小一点了,因为这种数据会消耗大量内存。

5, 调整Solr缓存

刚刚使用Solr通常会把Solr的缓存大小开得很大,超过所需很多。毕竟机器有很多内存,为什么不把缓存调大一些呢?其实这么做对性能没有好处:

把大量内量分配给Solr,操作系统可以使用的空闲内存就少了。操作系统通常会很好地利用空闲内存提高IO性能。这对Solr来说很有好处,这会缩短Solr访问索引的时间,提高Solr整体的搜索性能,不仅仅是那些命中缓存的搜索。

大缓存只是大内存垃圾的另一种说法。如果缓存中积累了大量对象,Java的垃圾收集器用的时间会增加,会影响Solr的响应时间。

缓存要按需使用,使用较大的缓存未必就好。必须证明确实有必要加大缓存,才能把缓存调大。那么如何做好决策呢?

要查看缓存是否正确配置,最好的查看的地方是Solr的Web接口,点击[Core Selector] → [core name] → [Plugins / Stats]。以Solr4.8为例,出现下面的画面:

在这个画面中,你可以看到所有上面提到的缓存。还有一些其它信息。统计数据有很多种,要判断缓存是否有效,关注下面数据:

cumulative_hitratio: 是一个0〜1之间的数,代表请求命中缓存的百分比。

cumulative_inserts: 在缓存的整个生存期中,有多少缓存实体对象被加入的缓存当中。

cumulative_evictions: 在缓存的整个生存期中,有多少缓存实体对象从缓存中被移除。

最终衡量缓存性能的是命中率。你需要做实验调整缓存大小,但时刻要关注命中率,看命中率是不是越来越高。下面是调整缓存大小的一些提示:

如果发现cumulative_evictions比cumulative_inserts高一些,那么可以试着增加缓存大小,观察命中率,有可能是因为缓存实体被移除得太快了。

如果发现缓存的命中率很高,而且cumulative_evictions值很小,那么说明缓存大小设置有点大了。试着减少缓存大小,观察命中率,直到命中率有变化。

如果缓存命中率很也不要觉得灰心,如果你的查询一般都不会有重复的case出现,命中率本来就不可能上来,这时你可以调小缓存的大小。

即使缓存的命中率很低,也不要把缓存关掉。对某些请求来说缓存还是起作用的。把缓存大小调小就可以了,保留缓存是值得的。

当调整了缓存的大小,试着用上面提到过的方法,大体估算一下内存使用的最坏情况。确保不会使用过大的内存。

缓存的调整并不是一个硬科学,要根据不同情况进行调整。注重实验和细节,可能会大幅提升搜索的性能。