solrconfig.xml配置文件详解

1,219 阅读25分钟

配置文件


<?xml version="1.0" encoding="UTF-8" ?>
<config>
    <luceneMatchVersion>4.10.4</luceneMatchVersion>
    <dataDir>${solr.data.dir:}</dataDir>
    <directoryFactory name="DirectoryFactory"
        class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}" />
    <codecFactory class="solr.SchemaCodecFactory" />
    <schemaFactory class="ClassicIndexSchemaFactory" />

    <indexConfig>
        <writeLockTimeout>10000</writeLockTimeout>
        <ramBufferSizeMB>100</ramBufferSizeMB>
        <mergePolicy class="org.apache.lucene.index.TieredMergePolicy">
            <int name="maxMergeAtOnce">10</int>
            <int name="segmentsPerTier">10</int>
        </mergePolicy>
        <mergeFactor>10</mergeFactor>
        <mergeScheduler class="org.apache.lucene.index.ConcurrentMergeScheduler" />
        <lockType>${solr.lock.type:native}</lockType>
        <unlockOnStartup>false</unlockOnStartup>
        <termIndexInterval>128</termIndexInterval>
        <reopenReaders>true</reopenReaders>
        <deletionPolicy class="solr.SolrDeletionPolicy">
            <str name="maxCommitsToKeep">1</str>
            <str name="maxOptimizedCommitsToKeep">0</str>
            <str name="maxCommitAge">30MINUTES</str><!-- 1DAY -->
        </deletionPolicy>
        <infoStream>true</infoStream><!-- attr: file="INFOSTREAM.txt" -->
        <checkIntegrityAtMerge>false</checkIntegrityAtMerge>
    </indexConfig>
    

    <updateHandler class="solr.DirectUpdateHandler2">
        <updateLog>
            <str name="dir">${solr.data.dir:}</str>
        </updateLog>
        <maxPendingDeletes>100000</maxPendingDeletes>
        <autoCommit>
            <maxDocs>${solr.autoCommit.maxDocs:1000}</maxDocs>
            <maxTime>${solr.autoCommit.maxTime:1000}</maxTime>
            <openSearcher>true</openSearcher>
        </autoCommit>
    </updateHandler>
    

    <query>
        <maxBooleanClauses>1024</maxBooleanClauses>
        <filterCache class="solr.FastLRUCache" size="100000"
            initialSize="5000" autowarmCount="1024" />
        <queryResultCache class="solr.FastLRUCache" size="100000"
            initialSize="5000" autowarmCount="1024" />
        <documentCache class="solr.LRUCache" size="100000"
            initialSize="8000" autowarmCount="1024" />
        <fieldValueCache class="solr.FastLRUCache" size="200"
            autowarmCount="128" showItems="100" />
        <enableLazyFieldLoading>true</enableLazyFieldLoading>
        <useFilterForSortedQuery>true</useFilterForSortedQuery>
        <queryResultWindowSize>30</queryResultWindowSize>
        <queryResultMaxDocsCached>200</queryResultMaxDocsCached>
        <useColdSearcher>false</useColdSearcher>
        <maxWarmingSearchers>2</maxWarmingSearchers>
    </query>

    <requestDispatcher handleSelect="false">
        <requestParsers enableRemoteStreaming="true"
            multipartUploadLimitInKB="204800" formdataUploadLimitInKB="2048"
            addHttpRequestToContext="false" />
        <httpCaching never304="true" />
    </requestDispatcher>

    <requestHandler name="/select" class="solr.SearchHandler">
        <!-- default values for query parameters can be specified, these will be 
            overridden by parameters in the request -->
        <lst name="defaults">
            <str name="echoParams">explicit</str>
            <str name="defType">edismax</str>
            <int name="rows">10</int>
            <!--<str name="fl">*,score</str>-->
            <str name="facet.mincount">1</str>
            <!-- 不限制Facet字段返回的结果条数. -->
            <str name="facet.limit">-1</str>
            <str name="facet.sort">count</str>
        </lst>
        <lst name="appends">
        </lst>
    </requestHandler>


    <!-- A request handler that returns indented JSON by default -->
    <requestHandler name="/query" class="solr.SearchHandler">
        <lst name="defaults">
            <str name="echoParams">explicit</str>
            <str name="indent">true</str>
            <str name="q.alt">*:*</str>
            <str name="fl">*</str>
            <int name="rows">10</int>
            <str name="facet.mincount">1</str>
            <!-- 不限制Facet字段返回的结果条数. -->
            <str name="facet.limit">-1</str>
            <str name="wt">xml</str>
        </lst>
        <lst name="appends">
        </lst>
    </requestHandler>

    <!-- Solr MoreLikeThis Query -->
    <!-- 相似查询 MoreLikeThis -->
    <!-- 在solr中有两种方式实现MoreLikeThis -->
    <!-- 第一种:SearchHandler中的MoreLikeThisComponent,MoreLikeThis以组件的身份出现,适于简单应用。 -->
    <!-- 第二种:MoreLikeThisHandler,MoreLikeThis作为一个单独的Handler来处理,可以应用过滤等较复杂操作 -->
    <!-- 相似查询 -->
    <requestHandler name="/mlt" class="solr.MoreLikeThisHandler">
        <lst name="defaults">
            <str name="q.alt">*:*</str>
            <str name="fl">*</str>
            <!-- 开启相似查询 -->
            <str name="mlt">true</str>
            <!-- 最小分词频率,源文档中小于该频率的分词将被忽略掉。tf:分词后的词在该文档中的频率 -->
            <int name="mlt.mintf">1</int>
            <!-- 最小文档频率,该词所在文档的个数小于这个值时将不用于相似判断。df:该词所在文档的个数。 -->
            <int name="mlt.mindf">1</int>
            <!-- 设置相似查询字段,最好采用TermVectors存储。 -->
            <str name="mlt.fl">GoodsId</str>
            <!-- 控制返回结果的最大数量 -->
            <int name="rows">5</int>
            <str name="wt">xml</str>
        </lst>
        <lst name="appends">
        </lst>
    </requestHandler>

    <!-- realtime get handler, guaranteed to return the latest stored fields 
        of any document, without the need to commit or open a new searcher. The current 
        implementation relies on the updateLog feature being enabled. -->
    <requestHandler name="/get" class="solr.RealTimeGetHandler">
        <lst name="defaults">
            <str name="omitHeader">true</str>
        </lst>
        </lst>
    </requestHandler>

    <!-- The export request handler is used to export full sorted result sets. 
        Do not change these defaults. -->
    <requestHandler name="/export" class="solr.SearchHandler">
        <lst name="invariants">
            <str name="rq">{!xport}</str>
            <str name="wt">xsort</str>
            <str name="distrib">false</str>
        </lst>
        <arr name="components">
            <str>query</str>
        </arr>
    </requestHandler>


    <!-- Update Request Handler. http://wiki.apache.org/solr/UpdateXmlMessages 
        The canonical Request Handler for Modifying the Index through commands specified 
        using XML, JSON, CSV, or JAVABIN Note: Since solr1.1 requestHandlers requires 
        a valid content type header if posted in the body. For example, curl now 
        requires: -H 'Content-type:text/xml; charset=utf-8' To override the request 
        content type and force a specific Content-type, use the request parameter: 
        ?update.contentType=text/csv This handler will pick a response format to 
        match the input if the 'wt' parameter is not explicit -->
    <requestHandler name="/update" class="solr.UpdateRequestHandler">
        <!-- <lst name="defaults"> <str name="update.chain">dedupe</str> </lst> -->
    </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">
            <!-- All the main content goes into "text"... if you need to return the 
                extracted text or do highlighting, use a stored field. -->
            <str name="fmap.content">text</str>
            <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>


    <!-- Field Analysis Request Handler RequestHandler that provides much the 
        same functionality as analysis.jsp. -->
    <requestHandler name="/analysis/field" startup="lazy"
        class="solr.FieldAnalysisRequestHandler" />


    <!-- Document Analysis Handler http://wiki.apache.org/solr/AnalysisRequestHandler -->
    <requestHandler name="/analysis/document"
        class="solr.DocumentAnalysisRequestHandler" startup="lazy" />

    <!-- Admin Handlers Admin Handlers - This will register all the standard 
        admin RequestHandlers. -->
    <requestHandler name="/admin/" class="solr.admin.AdminHandlers" />
    <!-- This single handler is equivalent to the following... -->
    <!-- 
    <requestHandler name="/admin/luke" class="solr.admin.LukeRequestHandler"/> 
        <requestHandler name="/admin/system" class="solr.admin.SystemInfoHandler"/> 
        <requestHandler name="/admin/plugins" class="solr.admin.PluginInfoHandler"/> 
        <requestHandler name="/admin/threads" class="solr.admin.ThreadDumpHandler"/> 
        <requestHandler name="/admin/properties" class="solr.admin.PropertiesRequestHandler"/> 
        <requestHandler name="/admin/file" class="solr.admin.ShowFileRequestHandler"/> -->
    <!-- If you wish to hide files under ${solr.home}/conf, explicitly register 
        the ShowFileRequestHandler using: -->
    <!-- 
    <requestHandler name="/admin/file" class="solr.admin.ShowFileRequestHandler"> 
    <lst name="invariants"> 
    <str name="hidden">synonyms.txt</str> 
    <str name="hidden">anotherfile.txt</str>
    </lst> 
    </requestHandler>
     -->

    <!-- ping/healthcheck -->
    <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>
        <!-- <str name="healthcheckFile">server-enabled.txt</str> -->
    </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>

    <queryResponseWriter name="json" class="solr.JSONResponseWriter">
        <!-- For the purposes of the tutorial, JSON responses are written as plain 
            text so that they are easy to read in *any* browser. If you expect a MIME 
            type of "application/json" just remove this override. -->
        <str name="content-type">text/plain; charset=UTF-8</str>
    </queryResponseWriter>

    <!-- Custom response writers can be declared as needed... -->
    <queryResponseWriter name="velocity"
        class="solr.VelocityResponseWriter" startup="lazy" />

    <!-- XSLT response writer transforms the XML output by any xslt file found 
        in Solr's conf/xslt directory. Changes to xslt files are checked for every 
        xsltCacheLifetimeSeconds. -->
    <queryResponseWriter name="xslt" class="solr.XSLTResponseWriter">
        <int name="xsltCacheLifetimeSeconds">5</int>
    </queryResponseWriter>

    <!-- Legacy config for the admin interface -->
    <admin>
        <defaultQuery>*:*</defaultQuery>
    </admin>
</config>

详解

1、luceneMatchVersion - 指定Lucene版本

<luceneMatchVersion>4.10.4</luceneMatchVersion>

表示Solr底层使用的Lucene的版本,官方推荐使用新版本的Lucene。

使用注意事项:如果更改了这个设置,必须对所有已经创建的索引数据重新索引(re-index),否则可能出现无法查询的情况。

2、dataDir - 索引数据路径

<dataDir>${solr.data.dir:}</dataDir>

配置SolrCore的data目录。

data目录用来存放当前SolrCore的index索引文件和tlog事务日志文件。

solr.data.dir 表示 ${SolrCore}/data 的目录位置。

建议不作修改,否则配置多个SolrCore时容易出错。

3、directoryFactory - 索引存储工厂

<directoryFactory name="DirectoryFactory" 
                  class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}">       
    <!-- These will be used if you are using the solr.HdfsDirectoryFactory,
         otherwise they will be ignored. If you don't plan on using hdfs,
         you can safely remove this section. -->      
    <!-- The root directory that collection data should be written to. -->     
    <str name="solr.hdfs.home">${solr.hdfs.home:}</str>
    <!-- The hadoop configuration files to use for the hdfs client. -->    
    <str name="solr.hdfs.confdir">${solr.hdfs.confdir:}</str>
    <!-- Enable/Disable the hdfs cache. -->    
    <str name="solr.hdfs.blockcache.enabled">${solr.hdfs.blockcache.enabled:true}</str>
    <!-- Enable/Disable using one global cache for all SolrCores. 
         The settings used will be from the first HdfsDirectoryFactory created. -->    
    <str name="solr.hdfs.blockcache.global">${solr.hdfs.blockcache.global:true}</str>
</directoryFactory>

有以下存储方案:

  1. solr.StandardDirectoryFactory :这是基于文件系统存储目录的工厂 它会基于当前的操作系统和JVM版本选择最好的实现。
  2. solr.NRTCachingDirectoryFactory默认方案:此工厂的设计目的是在内存中存储部分索引, 从而加快近实时搜索(Near-Real-Time)的速度。
  3. solr.MMapDirectoryFactory:这是Solr 3.1 - 4.0 版本在Linux64位系统下的默认实现, 它通过使用虚拟内存和内核特性调用 mmap去访问存储在磁盘中的索引文件, 允许Lucene或Solr直接访问I/O缓存. 如果不需要近实时搜索功能, 使用此工厂是个不错的方案。
  4. solr.NIOFSDirectoryFactory:适用于多线程, 但据报道, Solr 4.x之前的版本不适用在Windows系统上(慢), 因为JVM还存在bug。
  5. solr.SimpleFSDirectoryFactory:适用于小型应用程序, 不支持大数据和多线程。
  6. solr.RAMDirectoryFactory:这是内存存储方案, 不能持久化存储, 在系统重启或服务器crash时数据会丢失. 而且不支持索引复制(不能使用副本)。

4、codeFactory - 编解码方式

<codecFactory class="solr.SchemaCodecFactory"/>
<schemaFactory class="ClassicIndexSchemaFactory"/>

Solr中,编码可以使用自定义的编解码器,比如:想启动per-field DocValues 格式,可以在solrconfig.xml文件中设置Schemafactory的内容:

  • docValuesFormat="Lucene42":默认设置, 所有数据会被加载到堆内存中;
  • docValuesFormat="Disk":这是另一个实现,将部分数据存储在磁盘上;
  • docValuesFormat="SimpleText":文本格式, 非常慢, 仅仅用于学习测试。

5、indexConfig - 索引配置

<indexConfig>
    <!-- maxFieldLength was removed in 4.0. To get similar behavior, include
        a LimitTokenCountFilterFactory in your fieldType definition. E.g. <filter
        class="solr.LimitTokenCountFilterFactory" maxTokenCount="10000"/> -->
    <writeLockTimeout>10000</writeLockTimeout>
    <useCompoundFile>false</useCompoundFile>
    <ramBufferSizeMB>100</ramBufferSizeMB>
    <mergePolicy class="org.apache.lucene.index.TieredMergePolicy">
        <int name="maxMergeAtOnce">10</int>
        <int name="segmentsPerTier">10</int>
    </mergePolicy>
    <mergeFactor>10</mergeFactor>
    <mergeScheduler class="org.apache.lucene.index.ConcurrentMergeScheduler" />
    <lockType>${solr.lock.type:native}</lockType>
    <unlockOnStartup>false</unlockOnStartup>
    <termIndexInterval>128</termIndexInterval>
    <reopenReaders>true</reopenReaders>
    <deletionPolicy class="solr.SolrDeletionPolicy">
        <str name="maxCommitsToKeep">1</str>
        <str name="maxOptimizedCommitsToKeep">0</str>
        <str name="maxCommitAge">30MINUTES</str>
    </deletionPolicy>
    <infoStream>true</infoStream>
    <checkIntegrityAtMerge>false</checkIntegrityAtMerge>
</indexConfig>

indexConfig 标签用于设置索引的属性。

  1. maxFieldLength:对文档建立索引时,文档字段的最大长度,超过这个长度的值将被截断。如果文档很大,就需要增加这个数值。这个值设置的过高会导致内存不足异常。 该配置在Solr 4.0版本开始已经移除了,类似的设置需要在fieldType中定义。如:
<!-- 限制token最大长度 -->
<filter class="solr.LimitTokenCountFilterFactory" maxTokenCount="10000"/>
  1. writeLockTimeout:IndexWriter等待写锁的最长时间(毫秒)。默认是1000毫秒。

  2. maxIndexingThreads:生成索引时一个IndexWriter可以使用的最大线程数。默认是8,当很多线程到达时,多出的线程就只能等待运行中的线程结束,以空出资源。

  3. useCompoundFile:开启整合文件。 开启此选项,Lucene会将多个内部文件整合为若干个大文件,来减少使用Lucene内部文件的数量。即使用更少的用于索引的文件,这有助于减少Solr用到的文件句柄的数目,代价是降低了性能——用于索引的文件数更少了。除非应用程序用完了文件句柄,否则使用默认值false就可以。 Lucene中默认是true,Solr3.6开始默认为false。

  4. ramBufferSizeMB:Lucene创建或删除index后,合并内存中的文档数据、创建新的segment、将内存中数据刷新到磁盘之前可用的RAM大小。默认是100MB,较大的值可以提高创建索引的时间,但会牺牲更多内存。

  5. maxBufferedDocs:在将内存中的索引数据刷到磁盘之前,可以使用的buffer大小。 默认是1000个文档,较大的值可以提高创建索引的时间,但会牺牲更多的内存。 说明:ramBufferSizeMB和maxBufferedDocs同时设置时,优先满足阈值小的选项。

  6. mergePolicyFactory:合并策略。

<mergePolicyFactory class="solr.TieredMergePolicyFactory">
    <!-- 一次最多合并的段的个数 -->
    <int name="maxMergeAtOnece">10</int>
    <int name="segmentsPerTier">10</int>
</mergePolicyFactory>

配置Lucene中segment(段,索引信息的呈现方式)的合并策略:

从Solr/Lucene3.3开始,使用TieredMergePolicyFactory。

从Lucene2.3开始,默认使用LogByteSizeMergePolicy;

更早的版本使用LogDocMergePolicy。

  1. mergeFactor:合并因子,每次合并多少个segment。默认是10,每次合并多少个segment。
<mergeFactor>10</mergeFactor>

越小的值(最小为2)使用的内存越少,但创建索引的时间也更慢;

值越大,可以让索引时间变快,但会用掉更多的内存——典型的时间与空间的平衡。

  1. mergeScheduler:合并段的调度器,控制Lucene如何实现段的合并。
<mergeScheduler class="org.apache.lucene.index.ConcurrentMergeScheduler"/>

从Lucene 2.3开始默认使用ConcurrentMergeScheduler调度器, 可以使用单独的线程在后台并行执行合并;

Lucene 2.2之前默认使用SerialMergeScheduler调度器, 并不能并行执行合并。

  1. lockType:指定Lucene使用哪个LockFactory的实现, 即Lock策略。
 <lockType>${solr.lock.type:native}</lockType>

共有三种策略:

  • single - SingleInstanceLockFactory, 建议用于只读索引(read-only)或不存在其他进程会修改索引的场景;
  • native - NativeFSLockFactory,使用操作系统本地文件锁机制, 当同一个JVM中的多个Solr Web应用试图共享同一个索引时,不能使用;
  • simple - SimpleFSLockFactory,普通文件的行锁定方式。

Solr3.6之后默认是native策略,之前的版本使用的是simple策略。

  1. unlockOnStartUp:启动Solr服务时释放锁。
<unlockOnStartup>false</unlockOnStartup>

某些情况下,索引可能会由于不正确的关机或其他错误而一直处于锁定状态,导致不能田间和更新索引。将其设置为true可以禁用启动锁定,从而允许添加和更新操作。

默认为false。

如果设置为true,在Solr启动时将释放所有的写锁或提交锁——忽略多线程环境中保护索引的锁定机制,将导致进程可以绕过Lucene索引的锁机制直接访问索引,请慎用。

如果锁类型为```single````,该配置将不起作用。

  1. termIndexInterval:Lucene将term加载到内存中的频率。
<termIndexInterval>128</termIndexInterval>

最佳实践:使用默认值128,大多数情况下都很有用。

  1. nrtMode:近实时模式。
<nrtMode>true</nrtMode>

默认为true,设置为true,将从IndexWriter打开/重新打开IndexReaders,而不是从文件目录打开。

在主/从模式的主机中, 将其设置为false;

在SolrCloud集群中, 将其设置为true.

  1. deletionPolicy:删除策略。

在这里指定自定义的删除策略。策略类必须实现org.apache.lucene.index.IndexDeletionPolicy

默认配置如下:

<deletionPolicy class="solr.SolrDeletionPolicy">
    <!-- 最多能够保留多少个提交点 -->
    <!-- <str name="maxCommitsToKeep">1</str> -->
    <!-- 最多能够保留多少个优化提交点-->
    <!-- <str name="maxOptimizedCommitsToKeep">0</str> -->
    <!-- 达到指定的时间, 就删除所有的提交点. 支持DateMathParser语法, 如:  -->
    <!--
       <str name="maxCommitAge">30MINUTES</str>
       <str name="maxCommitAge">1DAY</str>
    -->
</deletionPolicy>

Solr默认的实现类支持删除索引提交点的提交数量,索引提交点和优化状态的年龄(即内部扫描的次数)。无论如何,都应该一直保留最新的提交点。

  1. infoStream:Lucene的信息流,控制索引时的日志信息。
<infoStream file="INFOSTREAM.txt">false</infoStream> 

为了方便调试,Lucene提供了InfoStream用于显示索引时的详细信息。

默认为false。设置为true时,Lucene底层的IndexWriter将会把自己的信息流写入Solr的日志,具体日志信息还要通过log4j.properties文件控制。

  1. checkIntegrityAtMerge:合并段时的安全检查。
<checkIntegrityAtMerge>false</checkIntegrityAtMerge> 

设置为true,将启用此安全检查——有助于在合并segment时 降低旧segments中损坏的索引转移到新段的风险,代价是合并的速度将变慢。

6、updateHandler - 更新处理器

Solr默认使用的高可用的updateHandler是:

<updateHandler class="solr.DirectUpdateHandler2">
  1. updateLog - 索引库的事务日志
<updateLog>
    <!-- dir: 事务日志的存储目录 -->
    <str name="dir">${solr.ulog.dir:}</str>
</updateLog>

默认路径:${SOLR_HOME}/data/tlog

启用事务日志用于实时查询、持久化索引数据、Solr Cloud中副本的恢复……

随着索引库的频繁更新,tlog日志文件会越来越大,所以建议提交索引时采用硬提交 - 即批量提交的方式。 - hard commit

  1. autoCommit - 自动(硬)提交策略

这是默认的自动提交策略。

<autoCommit>
    <!-- 多少个文档提交一次: 要添加的文档数达到此值时自动触发新的提交 -->
    <maxDocs>10000</maxDocs>
    <!-- 多少毫秒提交一次: 添加文档操作的时间持续到此值时自动触发新的提交, 与maxDocs配置其一即可 -->
    <!-- 两者同时配置时满足其中一个条件即可触发自动提交 -->
    <maxTime>${solr.autoCommit.maxTime:15000}</maxTime> 
    <!-- 如果为false, 提交操作会将最近的更改信息刷新到磁盘, 但不会立即打开查询器 - 也就是说客户端查询不到; 
         实时性要求高的项目, 需要设置为true - 在6.0之后的版本中默认为true -->
    <openSearcher>true</openSearcher> 
</autoCommit>
  • autoCommit是硬提交,开启后会进行如下操作。
  1. 生成一个新的tlog文件,删除旧的tlog文件;
  2. 把内存中缓存的文档fsync(OS内部的函数)到磁盘中,并创建一个index descriptor,用来记录各个文档的存储位置;此时就算JVM崩溃或系统宕机,也不影响这部分数据,不利之处是:占用资源较多。
  3. 如果<openSearcher>true</openSearcher>,就会打开查询器,让此次硬提交的文档可供搜索。
  • 可选项 - commitWithin - 在指定时间之后强制提交文档:

在Solr6.x版本中,支持如下配置:

这个多用在近实时搜索中,因此默认情况下执行的是软提交——修改后的文档不会被复制到集群中的slave服务器中,也就存在数据丢失的隐患。

当然可以通过添加参数进行强制硬提交。

<commitWithin>
   <softCommit>false</softCommit>
</commitWithin>

使用方法类似于:<add commitWithin=10000>,Solr会在10s内提交添加的文档。其他用法有:

  1. 在add方法中设置参数,比如server.add(doc, 10000)
  2. 在SolrRequest中设置,比如:
UpdateRequest req = new UpdateRequest();
req.add(doc);
req.setCommitWithin(10000);
req.process(server);
  • 最佳实践建议:

在频繁添加文档的应用中,官方建议使用commitWithin,而不是启用autoCommit

通过代码操作时,请不要使用 commit API手动提交,因为这会触发硬提交,出现大量的创建、删除tlog文件的操作,影响IO性能。

如果启用了updateLog,官方强烈建议使用某种硬提交策略来限制日志的大小。

最佳的自动提交设置:需要在性能和可见性之间进行权衡。

// 如果要手动提交, 不要使用无参方法, 推荐指定提交策略: 是否等待刷新(建议不等待, 因为会阻塞)、等待可搜索(建议不等待, 因为会阻塞)、软提交
 // 这是Solr 4.10版本API中的用法.
 solrServer.commit(false, false, true);
  1. autoSoftCommit - 软提交策略
<autoSoftCommit> 
    <maxTime>${solr.autoSoftCommit.maxTime:-1}</maxTime> 
</autoSoftCommit>
  • autoSoftCommit是软提交,配置后会进行如下操作:
  1. 把内存中缓存的索引的文档fsync(OS内部的函数)到磁盘中,但不会创建index descriptor——也就是说各个文档的真实存储位置并没有被记录下来。
  2. 打开文档查询器,涉及到的索引数据可以被查询到——近实时(NRT)更好。
  3. 软提交不会等待后台合并、整理文档等操作,只确保了修改的可见性,没有获取到文档的具体存储位置——也就是说如果此时JVM崩溃活着系统宕机,就找不到这些数据了
  • 最佳实践建议:

软提交比硬提交更快,更能做到近实时查询,但是如果服务器不稳定,或JVM崩溃,会导致提交的数据无法被检索到。

7、query - 查询相关配置

最大布尔子句

  1. maxBooleanClauses :最大布尔子句,可以组合在一起形成一个查询的布尔子句数量的上限,默认的1024已经足够。
<maxBooleanClauses>1024</maxBooleanClauses>

如果应用程序大量使用了通配符或范围查询,为了避免抛出TooManyClausesException异常,建议增加这个值。

这个选项会修改所有SolrCores的全局Lucene属性,如果多个solrconfig.xml文件中的配置不一致,将以最后初始化的文件为基准。

查询缓存

  • 关于缓存:

Solr使用Searcher类来处理查询。这个类将与索引相关的数据加载到内存中,根据索引、CPU及内存的大小,加载过程可能耗时比较久。

要改进这一设计和显著提高性能,Solr引入一种“预热”策略,就是把这些新的Searcher联机以便为用户提供查询服务之前,先对它们“热身”。

  • Solr中有2中缓存实现:
  1. 基于LinkedHashMap的LRUCache;
  2. 基于ConcurrentHashMap的FastLRUCache。

区别:FastLRUCache在单线程操作中具有更快的查询和更慢的添加操作,因此当缓存的命中率(> 75%)时通常比LRUCache更快,并且在多CPU系统的其他场景下可能更快。

  • 缓存的通用参数:

class:SolrCache的实现类;

size:cache中可保存的最大项。

initalSize:cache的初始化大小,与java.util.HashMap中entry的容量相关。

  • 其他说明:
  1. 对所有缓存模式而言,设置缓存参数时,都有必要在内存、CPU和磁盘访问之间进行均衡。Solr Web管理员界面的Statistics对分析缓存的hit-to-miss比例以及微调缓存大小等统计数据都非常有用。
  2. 并非所有应用程序都会从缓存收益,实际上一些应用程序反而会由于“将某个永远用不到的条目存储在缓存中”这一额外步骤而受到影响。
  1. filterCache:过滤器缓存。
<filterCache class="solr.FastLRUCache" size="512" 
             initialSize="512" autowarmCount="0"/>

是SolrIndexSearcher用于过滤(filter queries,也就是fq参数)的缓存:将得到的文档存储为无序的集合DocSets;

结果还能用来facet分片查询——有效提高了Solr的查询性能。

  1. queryResultCache:查询结果缓存。
<queryResultCache class="solr.LRUCache" size="512"
                  initialSize="512" autowarmCount="0"/>

缓存查询结果——基于查询、排序和请求的有序的文档范围,也就是文档id列表。

  1. documentCache:文档缓存。
<documentCache class="solr.LRUCache" size="512"
               initialSize="512" autowarmCount="0"/>

缓存Lucene的Document对象,也就是每个文档的stored fields - 在schema.xml文件中配置。

由于Lucene内部文档ID是瞬态的(会被更改),因此该缓存不会自热。

  1. cache:块连接使用的自定义缓存。
<cache name="perSegFilter" class="solr.search.LRUCache"
       size="10" initialSize="0" autowarmCount="10"
       regenerator="solr.NoOpRegenerator" />
  1. fieldValueCache:字段值缓存。
<fieldValueCache class="solr.FastLRUCache" size="512"
                 autowarmCount="128" showItems="32" />

该缓存用来按照文档的id保存能够快速访问的字段的值,就算这里不配置,Solr也会默认创建fieldValueCache。

  1. cache:自定义缓存。
<!-- 自定义缓存的示例:  -->
<cache name="myUserCache" class="solr.LRUCache"
       size="4096" initialSize="1024" autowarmCount="1024"
       regenerator="com.mycompany.MyRegenerator"
/>

自定义缓存的目的是实现用户/应用程序级数据的轻松缓存。

如果需要自热,则应将regenerator参数指定为solr.CacheRegenerator类的实现类。

filterCachequeryResultCache实现了solr.CacheRegenerator,所以都可以自热。可以通过SolrIndexSearcher.getCache()cacheLookup()cacheInsert()按名称访问Solr的缓存。

懒加载Field

  1. enableLazyFieldLoading:开启懒加载Field。
<enableLazyFieldLoading>true</enableLazyFieldLoading>

性能优化建议:如果应用程序只会检索文档中的少数几个Field,可以把这个属性设置为true——没有请求的存储字段(stored fields)将延迟加载。

懒加载大多发生在应用程序返回部分检索结果时,用户常常会单击其中一个来查看存储在此索引中的原始文档,初始往往只需要显示很短的一段信息。

查询很大的Document,尤其是含有很大的text类型的字段时,应该避免加载整个文档。

使用过滤器

  1. useFilterForSortedQuery :为存储字段使用过滤器。
<useFilterForSortedQuery>true</useFilterForSortedQuery>

通过使用过滤器进行搜索的优化,如果请求的排序条件不包括文档的得分(score),Solr将检查filterCache以查找和查询匹配的过滤器。如果找到,相关过滤器将作为文档ID的来源,然后对其ID进行排序返回。

大多数情况下,除非 经常使用不同的排序规则 并 重复进行相同的查询,否则这个配置没有多大用处,可以不用配置。

query result - 查询结果

  1. queryResultWindowSize :查询结果窗口大小。
<queryResultWindowSize>20</queryResultWindowSize>

用于queryResultCache的优化。发起查询请求时,将手机所请求数文档ID的数量集合。

例如:搜索特定查询请求并匹配文档10-19,并且queryWindowSize = 50,Solr将收集并缓存文档0-49。

可以通过缓存实现该范围内的任意其他查询请求。

  1. queryResultMaxDocsCached :查询结果的最大文档缓存数。
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>

设置查询结果中可以缓存的最大文档数。

Searcher的监听器

负责查询操作的各类搜索器(IndexSearcher),都可以触发相关监听器,进而采取下一步操作:

  1. newSearcher - 每当创建新的搜索器时触发,并且当前的搜索器正在处理请求(也成为被注册了)。它可以用来启动某些缓存,以防止某些请求的请求时间过长。
  2. firstSearcher - 创建第一个搜索器时触发,但这时是没有可用的搜索器来处理请求或加载缓存中的数据的。
  1. QuerySenderListener

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>
<!-- 开启此搜索器, 会导致Solr服务启动较慢 -->
<listener event="firstSearcher" class="solr.QuerySenderListener">
   <arr name="queries">
      <lst>
         <str name="q">static firstSearcher warming in solrconfig.xml</str>
      </lst>
   </arr>
</listener>
  1. useColdSearcher:使用冷搜索器。
<useColdSearcher>false</useColdSearcher>

如果搜索请求到来,并且目前还没有被注册的搜索器,就立即注册仍在加载缓存(自热)的搜索器并使用它。

默认为false - 所有请求都将阻塞,直到第一个搜索器完成缓存数据的加载。

  1. maxWarmingSearchers:最大的搜索器个数,默认是2。
<maxWarmingSearchers>2</maxWarmingSearchers>

在后台同时预热(加载缓存)的搜索器的最大数量,这些搜索器事先预热好,可以随时使用,如果申请的搜索器个数超出范围将会报错。

对只读的索引库,建议设置为1-2,对于可读写的索引库,根据设备内存和CPU的大小,可以设置更高的值。

如果频繁读写的索引库中,此参数较小,可能会抛出Error opening new searcher. exceeded limit of maxWarmingSearchers=2, try again later. 的错误,尝试将其调高即可解决此问题。

8、requestDispatcher - 请求转发器

开启handleSelect处理器

<requestDispatcher handleSelect="false" >

Request Dispatcher用来指示SolrCore里的SolrDispatchFilter处理请求的行为。

handleSelect是一个以前版本中遗留下来的属性,会影响请求的行为(比如/select?qt=XXX)。

如果/select没有注册,当handleSelect="true"时,SolrDispatchFilter就会把请求转发给qt参数指定的处理器;除非使用/select显示注册了处理器,否则当handleSelect="false"时,SolrDispatchFilter会忽略/select请求,并导致404错误——使用上更安全。

对于新用户不建议使用handleSelect="true",但这是默认向后兼容的配置。

requestParses - 请求解析器

<requestParsers enableRemoteStreaming="true" 
                multipartUploadLimitInKB="2048000"
                formdataUploadLimitInKB="20480"
                addHttpRequestToContext="false"/>

这里配置Solr请求的解析行为,以及对请求的ContentStreams的限制。

  1. enableRemoteStreaming:是否允许使用stream.file和stream.url参数来指定远程streams。这里介绍的Solr4.10版本中默认开始了此选项,授权Solr获取远程文件——不安全,官方建议我们要确保系统具有身份验证功能。
  2. multipartUploadLimitInKB:指定Solr允许一个多文件上传的请求中文件的最大大小值,以KB为单位。
  3. formdataUploadLimitInKB:指定通过POST请求发送的表单数据(application/x-www-form-urlencoded)的最大值,以KB为单位。
  4. addHttpRequestToContext:设置为true,它将声明原始的HttpServletRequest对象应该被包括在SolrQueryRequest的上下文集合(context map)中,这里的SolrQueryRequest是基于httpRequest的请求。这个HttpServletRequest不会被任何现有的Solr组件使用,但在开发自定义插件时可能很有用。

httpCaching - HTTP 缓存

httpCaching :控制HTTP缓存控制头(HTTP cache control headers),是W3C HTTP规格定义的HTTP响应的缓存过程,与Solr内部的缓存完全不同,请勿混淆。

<httpCaching> :元素的属性决定了是否允许对一个GET请求进行304响应:当一个客户端发起一个GET请求,如果资源从上一次被获取后还没有被修改,那么它可以在响应头中指定304响应。

304状态码的相关信息可参考:HTTP 304状态码的详细讲解

  1. 默认设置:
xml <httpCaching never304="true" />

never304:如果设置为true,那么即使请求的资源没有被修改,客户端的GET请求也不会得到304响应。将这个属性设置为true对开发来说是方便的,因为当通过支持缓存头的Web浏览器或其他用户修补Solr的响应时,这里的304响应可能会让人混淆。

  1. 示例配置:
<httpCaching never304="false" lastModFrom="openTime" etagSeed="Solr">
 <cacheControl>max-age=30, public</cacheControl>
</httpCaching>

如果包含<caccheControl>指令,将会生成Cache-Control头信息,如果值包含max-age=,还会生成Expires头信息——默认情况下不会生成任何Cache-Control头部信息。

即使设置了never304="true",也可以使用<cacheControl>选项。

如果要让Solr能够使用自动生成的HTTP缓存头进行响应,并正确响应缓存验证请求,就要把never304的值设置为"false" => Solr将根据索引的属性生成相关的Last-Modified和ETag头信息。

还可以指定以下选项来限制响应头的信息:

  1. lastModFrom:默认值为"openTime"(记录了最后的更改时间),这意味着Last-Modified(以及对If-Modified-Since请求的验证)将全部与当前Searcher的openTime相关联。如果希望lastModFrom与上次修改物理索引的时间精确同步,可以将其更改为lastModFrom="dirLastMod"
  2. etagSeed="...":是一个可以更改的选项,即使索引没有更改,改变这个值将强制更改ETag头信息,从而强制让用户重新获取内通,比如对配置文件做了重大修改时。

如果使用了never304="true",Solr将忽略lastModifiedFrometagSeed的配置。

9、requestHandler - 请求处理器

Solr通过RequestHandler(请求处理器),提供类似WebService的功能——通过HTTP请求对索引进行访问。

Solr通过下述步骤选择Request Handler去处理请求:

  1. 传入的查询将根据请求中qt参数指定的路径,按名称分配给特定的Request Handler。
  2. 如果请求路径使用了/select,但却没有任何一个Request Handler具有select这个名称,而requestDispatcher,就会根据qt参数调度Request Handler。
  3. 没有/的请求,是这样被执行的:http://host/app/[core/]select?qt=name,如果没有给出qt参数,那么将使用配置为default="true"的requestHandler或者名称为"standard"(标准处理器)的处理器处理。
  4. 如果要使用配置为startup="lazy"的处理器,则在第一个使用这个请求处理器的请求到来之前不会初始化它。

通过 /select 搜索索引

<requestHandler name="/select" class="solr.SearchHandler">
    <!-- 设置默认的参数值, 可以在请求地址中修改这些参数 -->
    <lst name="defaults">
        <!-- 调试信息返回到客户端的参数 --> 
        <str name="echoParams">explicit</str>
        <int name="rows">10</int>   <!-- 显示的数量 -->
        <str name="df">text</str>   <!-- 默认的搜索字段 -->
    </lst>
</requestHandler>
  1. default - 默认值:可以指定查询参数的默认值,这些都会被请求中的参数覆盖,也就是说请求中的优先。
  2. appends - 追加值:除了默认值之外,还可以指定appends(追加)参数来标识 从查询参数(或现有的“default”的值)中获取参数值,然后追加到multi-val参数列表中。 下面的例子中,参数fq=instock:true将追加到用户指定的任何查询的fq参数上,这种分区索引机制独立于所有客户端的过滤查询。
<!--
    <lst name="appends">
        <str name="fq">inStock:true</str>
    </lst>
-->

在Solr中,客户端无法阻止这些追加的值被使用,所以除非你确定你总是想要它,否则不要使用这种机制。

  1. invariants - 不变量:这个参数用来设置不会被客户端覆盖的值 => 在invariants部分定义的值总会被使用,而不用考虑用户或客户端指定的defaultsappends的值。下面的例子中,将修复facet.fieldfacet.query参数,从而限制客户端可以使用的分面(facet,类似于一种过滤搜索)。
<!--
    <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>
-->

默认情况下,Solr中的facet是不会打开的,但如果客户端在请求中指定了faccet=true,那么不管它们指定的facet.feildfacet.query参数是什么,这里配置的都将是客户端唯一能得到的facet的内容。

注意:绝对客户端无法阻止使用这些“不变量”值,因此除非您确定总是需要它,否则不要使用此机制。

  1. components - 组件:在request handler的最后, 是组件components的定义: 定义可以用在一个request Handler的搜索组件的列表, 它们仅在 Request Handler 中注册.
<!--
    <arr name="components">
        <str>nameOfCustomComponent1</str>
        <str>nameOfCustomComponent2</str>
    </arr>
-->

搜索组件元素只能被用于SearchHandler, 如果不需要默认的SearchComponents列表, 可以完全覆盖该列表, 也可以将组件添加到默认列表中或将其附加到默认列表中。

通过 /query 搜索索引

Solr中的请求处理器, 默认返回缩进的JSON格式的内容:

<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>

通过 /get 获取索引

RealTimeGetHandler - 实时获取处理器, 保证返回的每个文档的最新存储字段, 而不需要提交或打开新的Searcher。

<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>

Solr当前版本的RealTimeGetHandler的实现, 需要开启updateLog功能。

如果使用SolrCloud,就不要在/get处禁用RealTimeGetHandler, 否则每次触发的Leader选举都将导致选举涉及到的Shard中的所有Replicas被完全同步。

同样, Replica的恢复也将始终从Leader中获取完整的索引,因为如果没有RealTimeGetHandler的情况下, Replicas将无法进行部分同步。

通过 /export 导出结果

导出请求处理器用于导出完整排序的结果集, 请不要更改这些默认的配置值。

<requestHandler name="/export" class="solr.SearchHandler">
    <lst name="invariants">
        <str name="rq">{!xport}</str>
        <str name="wt">xsort</str>
        <str name="distrib">false</str>
    </lst>
    <arr name="components">
        <str>query</str>
    </arr>
</requestHandler>

通过 /update 修改索引

通过 /update 维护索引, 可以通过使用XML、JSON、CSV或JAVABIN指定的命令对索引进行添加、修改、删除操作。

<requestHandler name="/update" class="solr.UpdateRequestHandler">
    <!--
    <lst name="defaults">
        <str name="update.chain">dedupe</str>
    </lst>
    -->
</requestHandler>

注意事项:

从Solr1.1版本开始,requestHandlers在请求体中需要包含有效的Content-type(内容类型)头信息, 例如:curl 中这样使用:-H 'Content-type:text/xml;charset= UTF-8'

要覆盖请求体重Content-type并强制使用特定的Content-type,就需要在请求参数中指定: ?update.contentType=text/csv

如果wt相应类型参数没有给出, 处理器将选择一个响应格式以匹配输入的内容。

参考资料