部分來自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:\leaning\solr\solr-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> |