部分来自http://www.jianshu.com/p/8cf609207497
一、总览
solr的配置重要的有三个:solr.xml、solrConfig.xml、schema.xml
solr.xml 是整个Solr节点的配置,是定义关于core的管理、collection分片、solr云
和http请求处理,不过目前改动不多,也没仔细研究。
solrConfig.xml:关于core或collection的主要配置信息。
schema.xml :定义索引中的文档结构,包括字段名、字段类型、字段处理方法等,类似于表结构定义,比它更复杂。
二、Solr启动过程
1、solr启动的时候会找Java的全局变量:solr.solr.home ,作为根目录。
在web.xml中配置java全局变量:
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>D:leaningsolrsolr-home</env-entry-value>
<env-entry-type>java.lang.String</env-entry-type>
</env-entry>
2、solr到根目录下面的每个子目录,去查找是否包含core.properties的文件,有的话自动启动这个collection或core的恢复工作。
core.properties 配置文件主要配置,core或collection名字、shard分片信息、存储的数据和日志信息以及定义的schemal.xml等。
在恢复过程中,solr会在这个子目录下面的conf文件夹下去找solrconfig.xml的配置。
下图是solr的例子程序启动过程:
三、solrconfig.xml 配置说明
3.1 基本概述
具体内容
1、solr使用的Lucene版本、使用到的Jar路径配置;JMX配置,用于MBeans监控。
2、定义如何处理查询、如何处理索引的内容。
查询过程:
solr的查询过程的详细情况分为几个阶段,如下图:
1、请求参数装饰
1)defaults - 帮忙指定默认参数。
2)invariants-设置特定参数为固定值,重写客户端提供的值。
3)append - 在客户端的参数基础上进行参数的添加。
2、 第一组件
可选择配置的,用于查询处理前的预处理。
3、查询组件链
至少包含查询组件,用于执行具体的查询工作。
4、最后组件
用于处理查询后最后工作,比如拼写检查组件。
具体的定义,可以看下solrconfig.xml中提供的一个/browse定义的相关查询整个过程的配置。
3.3 搜索器(Searcher)
搜索器说明
在solr中,具体执行的搜索工作是通过搜索器执行的,如上面的图所示。在一个solr节点中,只有一个注册的搜索器。
它是一个基于Lucene索引的可读快照,当文档被添加到索引中,不是立刻可以搜索到。
让新添加的文档可以被搜索到,需要关闭老的搜索器,打开新的搜索器。一般来说commit操作就会执行这个操作。
这个过程是比较耗时的,关闭老的搜索器的时候,如果有用户正在查询,你的关闭动作需要等待。
另外所有的缓存都是基于旧的索引的,所以所有的缓存将失效,除非重新预热。
预热搜索器
如上文所述,搜索器在commit后需要重新打开,如果原来用户正在执行查询,缓存数据完全失效了,会促使重新执行查询,
导致用户体验差,所以需要预热。
一般来说,预热做两个事情,一执行预热语句、二用新的查询到的缓存数据代替老的缓存数据。
注意,多的预热语句,将会导致打开新的搜索器变慢,影响实时性,频繁提交的话将会导致内存等占用过大问题。
使用冷搜索器
如果说预热好的搜索器称为热的搜索器:)虽然没看到这个说法,那么没有预热的搜索器称为冷搜索器,配置如下:
false 如果这个配置为true,则来查询的时候,如果没有注册的
搜索器,有的搜索器正在预热,那不管是否预热完成,直接使用这个搜索器。
(这里面有个矛盾,既然所有的搜索器都是在新的预热好,老的才被关闭的,那么这种情况怎么存在,也许是第一次执行查询的时候)。
最大预热搜索器
当每次commit都会打开一个新的搜索器进行预热,那么如果commit操作在程序里面控制,在并发的情况下,可能有多个搜索器被打开,
有个配置项:2,通过它来配置可以打开的最大搜索器的个数,超过这个阀值,
commit操作会失败,如果经常因为这个失败,要看下是不是因为预热的时间过长。
3.4 缓存配置
solr中缓存管理
1)缓存的尺寸和管理策略
Solr中设置缓存的尺寸是对象的数量,当超过这个数量的时候,Solr利用相关策略进行清除。
有两个主要策略LRU(即Least Recently Used )将最近最少使用的实体移出缓存;
LFU(least frequently used)是将最少使用次数的实体移出缓存,过滤器缓存比较适合LFU策略。
有个误区是在内存准许的情况下,尽可能设置你的缓存为尽可能的大。这个认识是错误的。
因为在commit后,缓存会失效,这将导致JVM回收这些内存,缓存大,导致JVM回收垃圾时间长,
服务被暂停的时间长。
2)缓存的命中和拆迁
命中率是指在缓存中发现一个查询请求的比例。代表你的程序从缓存中获得的好处。
期望是100%,驱逐数量显示根据前面的缓存策略,多少对象被驱逐出缓存,拆迁量大
可能意味着你的缓存设置的小。
3)缓存对象的失效
在solr中,所有的缓存对象和搜索器都是关联的,只要这个搜索器不关闭,这些缓存就是有效的。
4)自动预热新缓存
在一个commit之后,新的搜索器被打开,但是不立刻关闭老的搜索器,直到这个新的搜索器被完全预热。这个晚关闭策略主要用于填充新的搜索器的缓存。
每个solr缓存都支持一个autowarmCount的属性去设置最大的对象数量或者老的缓存的尺寸比例,去自动预热。
过滤器缓存( Filter Cache)
过滤器缓存影响最终文档结果,不影响打分。当你执行不同的查询语句,而相同过滤条件的时候,过滤器缓存就可以起作用。
过滤器缓存可以跨查询应用,可以显著优化查询的性能。
配置如下:
size="512"
initialSize="512"
autowarmCount="0"/>
当你的过滤条件复杂,或你索引中的文档数量很多的时候,过滤器的创建和保存在内存中是很耗时间的,所以你希望可以预热过滤器缓存。如果一个过滤在你的程序中对很多请求都通用,那么缓存过滤器是有意义的。
每个对象在缓存中都有个key,在过滤器缓存中,这个key就是过滤器的查询语句,比如前面例子中:manu:belkin. 当预热一个过滤器缓存时候,旧的缓存中的key被抽取出来,在新的搜索器上被重新执行。如果你有上百个过滤器缓存,那么在预热的时候,solr必须执行这个100个过滤器的查询,这将消耗大量的时间。
我们建议预热的过滤器缓存,应该将autowarmCount设置为一个比较小的值。此外建议使用
LFU策略,下面是建议的配置:
过滤缓存器所占用的内存大小,当然和你在内存中缓存的文档数量有关,需要的内存是你文档数这么多的byte内存。
1000万的文档数大概占1.2MB内存。
查询结果缓存(Query result cache)
查询结果集缓存保存的是查询结果集。多次执行同一个查询的时候,后面的查询结果一般从查询结果缓存中直接得到,而不是在索引中再次执行相同的查询,这是优化花费高查询的强大方法。
查询结果集缓存定义如下:
size="512" initialSize="512" autowarmCount="0">
查询结果集缓存了查询语句作为key,内部的Lucene文档ID链表作为value。
文档ID在索引中增加新的文档的时候或合并的时候可能发生变化,所以预热的时候,
缓存值需要被重新计算。
为了预热一个结果集,solr必须重新执行查询,相同的建议是保持autowarmCount为一个较小的值而不是默认的0,你将从中获益。还有些关于些杂项来设置查询结果集。
查询结果窗口大小
查询窗口 元素,在你执行一个查询的时候,给你提供额外的页面。
假设你的程序一页提供10个文档,在大多数情况下,用户只看第一和第二页。你可以设置这个值为20,这样在查看第二页的时候就不用再次查询了。
一般情况下,这个值设置为你一页需要查询的文档数量2-3倍,多了会给你的查询带来不必要的负担。
查询结果最大文档缓存
在前面,给缓存设置的值的大小,代表缓存的数量,每个缓存的最大大小也可以设置一个值。
200就是设置一个缓存实体可以缓存的最大文档数量。
准许延迟字段加载
具体配置为:true,设置了后,如果你的查询是查询文档集
中的一部分,那么只有需要的字段才被加载,其他字段不加载。
(默认的值为true。这样solr在根据读取Document信息时,如果enableLazyFieldLoading为True,把要返回的Field集合封装为一个SetNonLazyFieldSelector,
这里的Field的值都是立即加载的,即到索引库里把该Field的值取出来保存到Doc中的。doc的其他的Field的值则是通过延迟加载的。
也是就在document调用具体的get(String name)方式时,由LazyField去取值的。可见设置延迟加载为enableLazyFieldLoading为True,
而且我们要返回的Field也很少时,那我们去读索引库所花的时间就少了)
文档缓存(Document Cache)
查询结果缓存是保存匹配查询的一系列文档内部ID,即使查询结果在缓存中。solr仍然需要从磁盘中加载搜索结果的文档信息。文档缓存,存储的key为内部文档ID,值为从磁盘加载进来的文档内容。因此查询结果集缓存可以利用文档缓存去查询在查询结果集中对应的文档信息。
size="512"
initialSize="512"
autowarmCount="0"/>
字段值缓存(Field Cache)
它在排序的时候使用,严格来说属于Lucen来管理的。字段值缓存提供了通过文档ID来快速访问字段值。
具体的配置文件如下:
<?xml version="1.0" encoding="UTF-8" ?>
<config> <!-- 在下面的所有配置中,前缀"solr"。 为类名 是一个别名,导致solr搜索适当的包, 包括org.apache.solr。(search | update | request | core | analysis) 如果你也可以指定一个完全限定的Java类名 有自己的定制插件。 --> <luceneMatchVersion>5.1.0</luceneMatchVersion>
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-dataimporthandler-.*.jar" />
<lib dir="${solr.install.dir:../../../..}/contrib/extraction/lib" regex=".*.jar" /> <lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-cell-d.*.jar" />
<lib dir="${solr.install.dir:../../../..}/contrib/clustering/lib/" regex=".*.jar" /> <lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-clustering-d.*.jar" />
<lib dir="${solr.install.dir:../../../..}/contrib/langid/lib/" regex=".*.jar" /> <lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-langid-d.*.jar" />
<lib dir="${solr.install.dir:../../../..}/contrib/velocity/lib" regex=".*.jar" /> <lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-velocity-d.*.jar" />
<dataDir>${solr.data.dir:}</dataDir>
<!-- DirectoryFactory用于索引。
solr.StandardDirectoryFactory是文件系统 并尝试挑选当前的最佳实现 JVM和平台。 solr.NRTCachingDirectoryFactory,默认, 包装solr.StandardDirectoryFactory并将小文件缓存在内存中 为了更好的NRT性能。
可以通过solr.MMapDirectoryFactory强制实现特定的实现, solr.NIOFSDirectoryFactory或solr.SimpleFSDirectoryFactory。
solr.RAMDirectoryFactory是基于内存的,而不是 持久性,并且不能与复制配合使用。 --> <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}">
<!-- 如果您使用的是solr.HdfsDirectoryFactory, 否则会被忽略。 如果您不打算使用hdfs, 您可以安全地删除此部分 --> <str name="solr.hdfs.home">${solr.hdfs.home:}</str> <str name="solr.hdfs.confdir">${solr.hdfs.confdir:}</str> <str name="solr.hdfs.blockcache.enabled">${solr.hdfs.blockcache.enabled:true}</str> <str name="solr.hdfs.blockcache.global">${solr.hdfs.blockcache.global:true}</str>
</directoryFactory>
<codecFactory class="solr.SchemaCodecFactory"/> <schemaFactory class="ClassicIndexSchemaFactory"/>
<indexConfig> <lockType>${solr.lock.type:native}</lockType> <infoStream>true</infoStream> </indexConfig>
<!-- JMX
此示例可在JMX中启用并且仅当现有的MBeanServer 如果要通过JVM配置JMX,请使用此选项 参数。 删除它以禁用暴露Solr配置并向JMX统计。 --> <jmx />
<updateHandler class="solr.DirectUpdateHandler2">
<!-- 启用事务日志,用于实时获取,持久性和 和solr云复制恢复。 日志可以增长 未提交的索引更改,所以使用硬性的autoCommit被推荐(见下文)。 "dir" - 事务日志的目标目录,默认为 solr数据目录。 --> <updateLog> <str name="dir">${solr.ulog.dir:}</str> </updateLog>
<!-- AutoCommit
在特定条件下自动执行强制提交。 而不是启用autoCommit,请考虑在添加文档时使用"commitWithin"。
http://wiki.apache.org/solr/UpdateXmlMessages
maxDocs - 自动触发新提交之前自上次提交以来要添加的最大文档数。
maxTime - 在自动触发新提交之前自添加文档以来允许通过的最大时间(以ms为单位)。 openSearcher - 如果为false,则提交将导致最近的索引更改被刷新到稳定存储,但不会导致新的搜索器被打开以使这些更改可见。
如果启用了updateLog,那么强烈建议您使用某种类型的autoCommit来限制日志大小。 --> <autoCommit> <maxTime>${solr.autoCommit.maxTime:15000}</maxTime> <openSearcher>false</openSearcher> </autoCommit>
<!--softAutoCommit就像autoCommit,除了它导致一个"软"提交, 只能确保更改是可见的,但不能确保数据被同步到磁盘。 这比一个艰难的承诺更快,更接近实时友好。 -->
<autoSoftCommit> <maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime> </autoSoftCommit>
</updateHandler>
<!-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 查询部分 - 这些设置控制查询时间,如缓存 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --> <query>
<maxBooleanClauses>1024</maxBooleanClauses>
<!-- Solr内部查询缓存,基于同步的LinkedHashMap和基于ConcurrentHashMap的FastLRUCache, 有两种可用于Solr,LRUCache的缓存实现。 FastLRUCache在单线程操作中具有更快的获取速度和更慢的速度,因此当缓存的命中率高(> 75%)时,通常快于LRUCache,并且在多CPU系统的其他情况下可能会更快。 -->
<!-- Filter Cache
过滤器缓存
参数: class - SolrCache实现LRUCache或(LRUCache或FastLRUCache) size - 缓存中最大条目数 initialSize - 缓存的初始容量(条目数)。 (参见java.util.HashMap) autowarmCount - 预填充和旧缓存的条目数。 --> <filterCache class="solr.FastLRUCache" size="512" initialSize="512" autowarmCount="0"/>
<!-- 查询结果缓存
缓存搜索结果 - 基于查询,排序和请求的文档范围的文档ID(DocList)的有序列表。 --> <queryResultCache class="solr.LRUCache" size="512" initialSize="512" autowarmCount="0"/>
<!-- 文档缓存
缓存Lucene Document对象(每个文档的存储字段)。 由于Lucene内部文档id是短暂的, 此缓存不会被自动加热。 --> <documentCache class="solr.LRUCache" size="512" initialSize="512" autowarmCount="0"/>
<!-- custom cache currently used by block join --> <cache name="perSegFilter" class="solr.search.LRUCache" size="10" initialSize="0" autowarmCount="10" regenerator="solr.NoOpRegenerator" />
<!-- 字段懒加载
如果为true,那么未请求的存储字段将被懒惰地加载。 如果通常的情况是不加载所有存储的字段, 则这可以导致显着的速度改善,特别是如果跳过的字段是大的压缩文本字段。 --> <enableLazyFieldLoading>true</enableLazyFieldLoading>
<!--结果窗口大小
与queryResultCache一起使用的优化。 当请求搜索时,请求所需数量的文档ID的超集 被收集。 例如,如果搜索特定查询请求匹配文档10到19,并且queryWindowSize为50, 那么文件0到49将被收集和缓存。 通过缓存可以满足该范围内的任何其他请求。 --> <queryResultWindowSize>20</queryResultWindowSize>
<!-- queryResultCache中任何条目缓存的最大文档数。 --> <queryResultMaxDocsCached>200</queryResultMaxDocsCached>
<!-- 查询相关事件侦听器 各种IndexSearcher相关事件可以触发侦听器采取行动。 newSearcher - 每当新的搜索者正在准备中,并且有一个当前的搜索者处理请求(也称为注册)时就被触发。 它可以用于提示某些缓存,以防止某些请求的长时间请求。 firstSearcher - 每当一个新的搜索者准备好,但没有当前注册的搜索者来处理请求或从中获取自动加密数据时,它们就被触发。 --> <!-- QuerySenderListener接受NamedList数组,并按顺序对每个NamedList执行本地查询请求。 --> <listener event="newSearcher" class="solr.QuerySenderListener"> <arr name="queries"> <!-- <lst><str name="q">solr</str><str name="sort">price asc</str></lst> <lst><str name="q">rocks</str><str name="sort">weight asc</str></lst> --> </arr> </listener> <listener event="firstSearcher" class="solr.QuerySenderListener"> <arr name="queries"> <lst> <str name="q">static firstSearcher warming in solrconfig.xml</str> </lst> </arr> </listener>
<!-- 使用冷搜索器
如果搜索请求进入并且没有当前注册的搜索者,则立即注册仍然变暖的搜索者并使用它。 如果"false",则所有请求将被阻塞,直到第一个搜索者完成加温。 --> <useColdSearcher>false</useColdSearcher>
<!-- 最大预热搜索器
可能在后台同时预热的搜索者的最大数量。 如果超出此限制,则返回错误。 推荐值为1-2for read-only slaves
--> <maxWarmingSearchers>2</maxWarmingSearchers>
</query>
<!-- 请求调度器 requestDispatcher将请求分发给相应的请求处理器 本节包含有关SolrDispatchFilter在处理此SolrCore请求时应如何运行的说明。 handleSelecttrue"是为了向旧版本兼容 不必考虑 为了向后兼容 --> <requestDispatcher handleSelect="false" > <!-- Request Parsing 设置请求的http表单的一些限制大小等配置 --> <requestParsers enableRemoteStreaming="true" multipartUploadLimitInKB="2048000" formdataUploadLimitInKB="2048" addHttpRequestToContext="false"/>
<httpCaching never304="true" /> </requestDispatcher>
<!-- 请求处理器
http://wiki.apache.org/solr/SolrRequestHandler
传入的查询将根据请求中指定的路径以名称的形式发送到特定的请求处理器 -->
<requestHandler name="/dataimport" class="solr.DataImportHandler"> <lst name="defaults"> <str name="config">db-data-config.xml</str> </lst> </requestHandler>
<requestHandler name="/select" class="solr.SearchHandler"> <!-- 默认值 其中df为默认查询字段 --> <lst name="defaults"> <str name="echoParams">explicit</str> <int name="rows">10</int> <str name="df">text</str> </lst>
<!-- 追加 --> <!-- <lst name="appends"> <str name="fq">inStock:true</str> </lst> --> <!-- 重写 --> <!-- <lst name="invariants"> <str name="facet.field">cat</str> <str name="facet.field">manu_exact</str> <str name="facet.query">price:[* TO 500]</str> <str name="facet.query">price:[500 TO *]</str> </lst> --> <!-- 如果不希望使用SearchComponent的默认列表,则该列表可以被完全覆盖,也可以将组件添加到默认列表中。 (见下文) <!-- <arr name="components"> <str>nameOfCustomComponent1</str> <str>nameOfCustomComponent2</str> </arr> --> </requestHandler>
<requestHandler name="/query" class="solr.SearchHandler"> <lst name="defaults"> <str name="echoParams">explicit</str> <str name="wt">json</str> <str name="indent">true</str> <str name="df">text</str> </lst> </requestHandler>
<requestHandler name="/get" class="solr.RealTimeGetHandler"> <lst name="defaults"> <str name="omitHeader">true</str> <str name="wt">json</str> <str name="indent">true</str> </lst> </requestHandler>
<requestHandler name="/browse" class="solr.SearchHandler"> <lst name="defaults"> <str name="echoParams">explicit</str>
<!-- VelocityResponseWriter settings --> <str name="wt">velocity</str> <str name="v.template">browse</str> <str name="v.layout">layout</str>
<!-- Query settings --> <str name="defType">edismax</str> <str name="q.alt">*:*</str> <str name="rows">10</str> <str name="fl">*,score</str>
<!-- Faceting defaults --> <str name="facet">on</str> <str name="facet.mincount">1</str> </lst> </requestHandler>
<initParams path="/update/**,/query,/select,/tvrh,/elevate,/spell,/browse"> <lst name="defaults"> <str name="df">text</str> </lst> </initParams>
<requestHandler name="/update" class="solr.UpdateRequestHandler">
</requestHandler>
<!-- Solr Cell Update Request Handler
http://wiki.apache.org/solr/ExtractingRequestHandler
--> <requestHandler name="/update/extract" startup="lazy" class="solr.extraction.ExtractingRequestHandler" > <lst name="defaults"> <str name="lowernames">true</str> <str name="uprefix">ignored_</str>
<!-- capture link hrefs but ignore div attributes --> <str name="captureAttr">true</str> <str name="fmap.a">links</str> <str name="fmap.div">ignored_</str> </lst> </requestHandler>
<requestHandler name="/analysis/field" startup="lazy" class="solr.FieldAnalysisRequestHandler" />
<requestHandler name="/analysis/document" class="solr.DocumentAnalysisRequestHandler" startup="lazy" />
<requestHandler name="/admin/" class="solr.admin.AdminHandlers" />
<requestHandler name="/admin/ping" class="solr.PingRequestHandler"> <lst name="invariants"> <str name="q">solrpingquery</str> </lst> <lst name="defaults"> <str name="echoParams">all</str> </lst>
</requestHandler>
<!-- Echo the request contents back to the client --> <requestHandler name="/debug/dump" class="solr.DumpRequestHandler" > <lst name="defaults"> <str name="echoParams">explicit</str> <str name="echoHandler">true</str> </lst> </requestHandler>
<requestHandler name="/replication" class="solr.ReplicationHandler" >
</requestHandler>
<!-- 搜索组件
搜索组件已注册到SolrCore并由其使用 SearchHandler的实例(可以通过名称访问它们)
默认情况下,以下组件可用:
<searchComponent name ="query"class ="solr.QueryComponent"/> <searchComponent name ="facet"class ="solr.FacetComponent"/> <searchComponent name ="mlt"class ="solr.MoreLikeThisComponent"/> <searchComponent name ="highlight"class ="solr.HighlightComponent"/> <searchComponent name ="stats"class ="solr.StatsComponent"/> <searchComponent name ="debug"class ="solr.DebugComponent"/>
requestHandler中的默认配置如下所示:
<arr name="components"> <str>query</str> <str>facet</str> <str>mlt</str> <str>highlight</str> <str>stats</str> <str>debug</str> </arr>
如果您将searchComponent注册到其中一个标准名称, 这将被使用而不是默认值。
要在"标准"组件之前或之后插入组件,请使用:
<arr name ="first-components"> <STR> myFirstComponentName </ STR> </ ARR>
<arr name ="last-components"> <STR> myLastComponentName </ STR> </ ARR>
注意:使用名称"debug"注册的组件将会 总是在"最后的组件"之后执行
--> </config> |