Solr查询调优三:facet.threads

This param will cause loading the underlying fields used in faceting to be executed in parallel with the number of threads specified. Specify as facet.threads=N where N is the maximum number of threads used. Omitting this parameter or specifying the thread count as 0 will not spawn any threads, and only the main request thread will be used. Specifying a negative number of threads will create up to Integer.MAX_VALUE threads.

facet.threads指定执行facet查询时,并行执行的线程数量。
facet.threads默认为1或者指定为0时,在执行facet的时候只有一个单线程处理。当设置 facet.threads为N时,就会指定最大N个线程执行。当设置为-1时,等于设置为Interger.MAX_VALUE.

Solr查询调优二:fq 禁用缓存和post filter

关闭filter query的缓存
实际应用中,有很多的filter cache是没有必要的,而且filter cahce的上限数量是固定,所以应该禁用一些不常用的filter cache。
例子:
1、fq={!cache=false}id:123&fq={!frange l=90 u=100 cache=false}
2、scale(query({!v=”content:(solr OR lucene)”}),0,100)

改变filter执行顺序
将过滤最多数据的filter置于最前面,这样后面如果有需要进行高开销的filter,计算的数据量就大大减少。
例子:
fq={!cost=1}category:technology&
fq={!cost=2}date:[NOW/DAY-1YEAR TO *]&
fq={!geofilt pt=37.773,-122.419 sfield=location d=50 cost=3}&
fq={!frange l=90 u=100 cache=false cost=100}
scale(query({!v=”content:(solr OR lucene)”}),0,100)

COST的数值越高,filter越后执行。将特别耗资源的filter设置成100,同时将cache变成false,因为它的结果是随机值,没有保存的意义。类似于POST FILER。

POST FILTER
Post Filter是一个特殊filter。它在所有的main query和filter执行完毕后才开始执行,即在mainquery和filter产生的最后交集文档后执行post filter。
post filter类似于前面提到的将filter设置为cost=100.
post filter 一般用于高开销的检索和匹配。自己可以实现postfiler interface实现自己的post filter。

Solr查询调优一: query VS filterquery 区别

Solr有两个查询参数,分别是query(q)和filterquery(fq)。官方文档没有写清楚两者之间具体有什么区别。

fq的官方文档这样写着:https://lucene.apache.org/solr/guide/7_3/common-query-parameters.html#fq-filter-query-parameter

The fq parameter defines a query that can be used to restrict the superset of documents that can be returned, without influencing score. It can be very useful for speeding up complex queries, since the queries specified with fq are cached independently of the main query. When a later query uses the same filter, there’s a cache hit, and filter results are returned quickly from the cache.
When using the fq parameter, keep in mind the following:

  • The fq parameter can be specified multiple times in a query. Documents will only be included in the result if they are in the intersection of the document sets resulting from each instance of the parameter. In the example below, only documents which have a popularity greater then 10 and have a section of 0 will match.fq=popularity:[10 TO *]&fq=section:0
  • Filter queries can involve complicated Boolean queries. The above example could also be written as a single fq with two mandatory clauses like so:fq=+popularity:[10 TO *] +section:0
  • The document sets from each filter query are cached independently. Thus, concerning the previous examples: use a single fq containing two mandatory clauses if those clauses appear together often, and use two separate fq parameters if they are relatively independent. (To learn about tuning cache sizes and making sure a filter cache actually exists, see The Well-Configured Solr Instance.)
  • It is also possible to use filter(condition) syntax inside the fq to cache clauses individually and – among other things – to achieve union of cached filter queries.
  • As with all parameters: special characters in an URL need to be properly escaped and encoded as hex values. Online tools are available to help you with URL-encoding. For example: http://meyerweb.com/eric/tools/dencoder/.

fq和q虽然不太好区分,但是能明确区分出两者的差别,对性能提升很高。两者的主要区别如下:
1、q又叫main query,fq全程filter query;
2、相关性评分
fq只有一个用途:就是查询出满足条件的文档。q有两个用途:1、查询出满足条件的文档;2、对返回的文档针对搜索关键字进行相关性评分。因此可以这样使用两者:将q看成一个特殊的filter,仅会多一步相关性评分。所以可以将用户搜索的关键词放入q中,这样可以根据用户的搜索给出相关性最高的文档,例如keyword=apache solr,同时将用户下拉选择的枚举字段放入fq参数中,例如category=techonology。
3、缓存和执行速度
将filter query 从main query中分离出来,有两个目的:
1、filter query 可以使用 filter query cache。
2、filter query 不进行开销巨大的相关性评分,加快执行速度。
4、可以指定多fq,但是只能有一个q
5、执行顺序
到底是fq先执行,还是q执行,看了很多文档,各执一词。但是solr in action的答案比较靠谱,执行顺序还是要看具体情况。

1 、每一个fq参数都会首先到filter cache中查询文档是否存在。
2、如果fq参数没有在 filter cache 找到,就会检索索引文件,并将检索到docset放入缓存中。
3、所有filter的docset进行取交集,最终生成一个唯一的docset。
4 、The q parameter is passed in (along with the filter DocSet) to be executed as a
Lucene query. When executing the query, Lucene plays leapfrog between the
query and combined filters, advancing both the query and filter results objects
to their next present internal ID (an integer). When both the query result and
filter result objects contain the same ID, that ID is collected, a process that
includes generating the relevancy score for the document
这段我翻译的不太清楚。意思大概是将q查出来的结果和前面filter的结果进行交集,最后为交集的每一个结果计算相关性评分。
5、执行post filter

参考资料:
1、solr in action

Solr优化一:部署调整

我们有一张大宽表,数据量大概在20亿左右,100多个字段,HDFS中不算复制因子,原始数据文件差不多1.8TB。这算是一个较大的宽表了。
大数据集群节点大概20台.CDH默认只能在一个节点上安装一个SOLR实例。由于其版本过低,不满足我们的功能要求。改为了独立部署当时最新的SOLR版本V7.3.1。

第一种方案:
由于每个物理机上留给SOLR的内存只有60GB,所以一开始,我们在每个节点上部署了3个实例,每个SOLR实例 60GB/3 =20GB。这样部署有以下几个问题:
1、SOLR普通检索过慢,经常需要10S到几十秒不等。
2、SOLR的distinct分析语句经常导致 SOLR实例OOM。
3、SOLR实例挂掉后,无法自动重启。
4、索引建立还行,每分钟接近1000万。

第二种方案:
从大数据集群中独立出6台物理机,专门用作SOLR集群。扣掉HBASE占用的50GB内存,操作系统50GB,剩下的150GB留给SOLR使用。每个节点上部署5个实例,摊到每个实例上150GB/5=30GB。部署后结果:
1、SOLR普通检索速度提升,时间变为1秒到3秒之内。
2、SOLR的distinct分析语句偶尔导致 SOLR实例OOM 。但是SOLR能够自动重启。
3、 SOLR的distinct分析语句执行时间较长,大致在3.3分钟左右。
4、索引建立极慢,20分钟才能建完400万数据。目前未探明是卡在网络还是磁盘?磁盘应该不会,因为每个实例都在一块独立的磁盘。

个人认为OOM的原因是因为内存不足,没有给SOLR足够的缓存空间吧。因为在SOLR实例中看到系统的物理内存始终为250.6G,差一点256GB,濒临崩溃的边缘。但是CDH的监控,只有146GB,和SOLR的监控不一致。SOLR的HEAP-SPACE,32GB只用到了8GB.

solr 分片与复制

在没有使用solrcloude的时候,可以使用如下的架构图进行分片与复制:

具体可以参考solr的官方指南:Combining Distribution and Replication  章节 。简单来说就是一主两从。从片的同步方式,我觉得应该是通过从主片同步快照的方式,来实现的。

Snapshot :A directory containing hard links to the data files of an index. Snapshots are distributed from the master nodes when the slaves pull them, “smart copying” any segments the slave node does not have in snapshot directory that contains the hard links to the most recent index data files.

在solr cloud里面,这种方式主要是用来进行备份使用。其实我个人觉得这种快照的复制方式应该是用来快速备份的,不应该是用来进行主从分片同步用的,更可能用的是PULL索引文件的形式。

Solr cloud提供了三种分片模式,分别为:

NRT: This is the default. A NRT replica (NRT = NearRealTime) maintains a transaction log and writes new documents to it’s indexes locally. Any replica of this type is eligible to become a leader. Traditionally, this was the only type supported by Solr.

TLOG: This type of replica maintains a transaction log but does not index document changes locally. This type helps speed up indexing since no commits need to occur in the replicas. When this type of replica needs to update its index, it does so by replicating the index from the leader. This type of replica is also eligible to become a shard leader; it would do so by first processing its transaction log. If it does become a leader, it will behave the same as if it was a NRT type of replica.

PULL: This type of replica does not maintain a transaction log nor index document changes locally. It only replicates the index from the shard leader. It is not eligible to become a shard leader and doesn’t participate in shard leader election at all.

这三种模式的主要分别是,NRT可以做主片,可以使用近实时索引(支持SOFT COMMIT),同步索引靠数据转发;TLOG也可以做主片,当为主片是和NRT一致,不能近实时索引,从片需要和主片同步的时候,只是从从片同步索引文件;PULL不能做主片,仅从主片同步索引文件。
创建分片的时候,副本默认使用的NRT模式。

Solr cloud可推荐使用的分片组合方式:

1、全部NRT:适用于小到中级的集群;更新吞吐量不太高的大型集群;

2、全部TLOG:不需要 实时索引;每一个分片的副本数较多;同时需要所有分片都能切换为主片;

3、TLOG+PULL:不需要 实时索引;每一个分片的副本数较多;提高查询能力,能够容忍短时的过期数据。

我们做了个测试:solr7.3,16个物理节点,每个节点3个实例,每个实例20G,需要索引的数据量为一亿,160个spark executors,一主两从(注:我们不需要NRT特性,我们是夜间批量)

1、全部NRT需要20分钟,大概每分钟600-800万。

2、全部TLOG需要10分钟,大概每分钟10000万。

3、TLOG+PULL:未测

PS:solr创建索引,可以先使用solr自带的zk脚本工具中uploadconfig方法上传配置文件,再使用solr的collection api里面的createcollection方法创建。

一份参考资料:

下面参考文章的原文地址:https://berlinbuzzwords.de/sites/berlinbuzzwords.de/files/media/documents/replicatypes-berlinbuzzwords.pdf

其中有启发的一张图:

solr 一主多从模式灌数据总是报错

我们有一张大宽表,大概200个字段,共有20亿左右的数据。在使用spark并行从hive导入Solr的时候,总是会报错,不是 no register leader 就是we are leader这类的错误。

后来搜索后发现这类问题有两类原因:

1、solr 内存过小,导致GC时间过长,从而让zk认为solr已经挂掉了。但是我们给了16G的内存还算不错,同时也检查了solr的gc日志,没有发现有GC时间过长的情况。

2、solr 与Zookeeper的timeout 时间过短。这正是我们的问题所在,我们在安装solr的时候没有指定solr的timeout时间。http://lucene.472066.n3.nabble.com/SOLR-zookeeper-connection-timeout-during-startup-is-hardcoded-to-10000ms-td4403341.html#a4403671

解决方法:

找到/ETC/solr.in.sh,添加配置:

ZK_CLIENT_TIMEOUT=”120000″

同时调整zookeeper的最大会话超时时间为160秒。

solr shard down无法启动

solr 上的一个collection的一个分片处于down的状态,无论如何重启solr都没有任何作用,一直是处于down 的状态。

解决办法:执行splitshard

执行以下链接:

http://serverip:9984/solr/admin/collections?action=SPLITSHARD&shard=shardname&collection=collectionname&wt=xml

刚方法会将原来down的shard,默认分为两个分片即可。

CDH5.13上独立安装Solr7.3.1

CDH5.13默认带的Solr版本号比较低,只有4.10.3。这种低版本无法支持我们的应用需求,所以只能独立安装Solr7.3.1,唯一的缺点就是无法在CDH上面统一管理了。

1、下载Solr的安装包省略,下载后解压Solr安装包。下面的流程默认解压到当前用户根目录,即 ~

2、解压solr7

tar -zxvf solr-7.3.1.tgz

3、创建ZK的solr7 root

cd ~/solr-7.3.1/bin
./solr zk mkroot /solr7 -z 10.127.60.2,10.127.60.3,10.127.60.4:2181
4、查看端口占用情况,避免端口被CDH占用
netstat -nl | grep 9983
或者
sudo netstae -nltp | grep 9983,这样可以拿到正在使用端口的pid
5、执行安装指令。如下指令,在一个物理机上建立两个solr实例。建议将每个实例的数据文件目录放在不同硬盘下。

sudo ./install_solr_service.sh ../../solr-7.3.1.tgz -i /srv/BigData/hadoop/solr1 -d /srv/BigData/hadoop/solr1/solr_data -u solrup -s solr1 -p 9983 -n

sudo ./install_solr_service.sh ../../solr-7.3.1.tgz -i /srv/BigData/hadoop/solr2 -d /srv/BigData/hadoop/solr2/solr_data -u solrup -s solr2 -p 9984 -n

6、修改 /etc/default/solr1.in.sh,改变部分参数。
----HDFS版本
SOLR_JAVA_MEM="-Xms16g -Xmx16g -Dsolr.directoryFactory=HdfsDirectoryFactory -Dsolr.lock.type=hdfs -Dsolr.hdfs.home=hdfs://10.127.60.1:8020/solr7 -XX:MaxDirectMemorySize=20g -Dsolr.autoSoftCommit.maxTime=-1 -Dsolr.autoCommit.maxTime=-1 -XX:+UseLargePages -Dsolr.hdfs.blockcache.slab.count=100"
ZK_HOST="10.127.60.2,10.127.60.3,10.127.60.4/solr7"

---本地
SOLR_JAVA_MEM="-Xms16g -Xmx16g -Dsolr.autoSoftCommit.maxTime=-1 -Dsolr.autoCommit.maxTime=-1 -XX:+UseLargePages"

ZK_HOST="10.127.60.2,10.127.60.3,10.127.60.4/solr7"

SOLR_JAVA_MEM="-Xms32g -Xmx32g -Dsolr.autoSoftCommit.maxTime=-1 -Dsolr.autoCommit.maxTime=-1 -XX:+UseLargePages"

ZK_HOST="10.127.60.2,10.127.60.3,10.127.60.4/solr7"
7、创建collection

---在zookeeper上传配置文件
bin/solr zk upconfig -z 10.127.60.2,10.127.60.3,10.127.60.4:2181 -n mynewconfig -d /path/to/configset

–参考资料:https://lucene.apache.org/solr/guide/7_3/solr-control-script-reference.html#solr-control-script-reference

./solr create -c picc_bigdata -d /zp_test/solor7/conf -n picc_bigdata -s 6

8、如果将数据温江放在HDFS上,solrup用户需要有对应的权限。在HDFS上创建目录 /solr7,同时赋予solrup用户所有权。 hdfs dfs -chown solrup /solr7

Solr索引建立优化

测试环境的硬件情况:四台pc,20颗2核,内存256G,11盘1.4T。带宽为千兆网络,最快传输速度为140MB/S。

测试情况结论:

1、Solr在使用HDFS索引的建立速度远不如本地索引。但是我们在其它公司使用的都是HDFS索引,不至于这么慢。最有可能的情况是网络传输速度不够,因为在其它公司都是使用的双万兆网卡。

2、增加Solr的实例数量,可以增加Solr的分片数量,提高写入速度。

3、每行的数据量越大,也减慢写入速度,毕竟一行的数据字段数越多,一行数据的数据量越大。

4、由于我们只使用批量导入,不是会设计到近实时索引。所以我们禁用了soft commit。而且只在批量导入完成的时候,执行一次hard commit。这样做可以极大的降低solr的压力。因为每一次hard commit或者达到soft commit的阀值的时候,就会触发solr的索引handler更替,以及一系列动作。

禁用软提交的方法:

修改 /etc/default/solr1.in.sh,设置参数-Dsolr.autoSoftCommit.maxTime=-1 -Dsolr.autoCommit.maxTime=-1;

----HDFS版本
SOLR_JAVA_MEM="-Xms16g -Xmx16g -Dsolr.directoryFactory=HdfsDirectoryFactory -Dsolr.lock.type=hdfs -Dsolr.hdfs.home=hdfs://10.127.60.1:8020/solr7 -XX:MaxDirectMemorySize=20g -Dsolr.autoSoftCommit.maxTime=-1 -Dsolr.autoCommit.maxTime=-1 -XX:+UseLargePages -Dsolr.hdfs.blockcache.slab.count=100"

---本地
SOLR_JAVA_MEM="-Xms16g -Xmx16g -Dsolr.autoSoftCommit.maxTime=-1 -Dsolr.autoCommit.maxTime=-1 -XX:+UseLargePages"

SOLR_JAVA_MEM="-Xms32g -Xmx32g -Dsolr.autoSoftCommit.maxTime=-1 -Dsolr.autoCommit.maxTime=-1 -XX:+UseLargePages"