快取與查詢預熱
Solr 的快取提供了一種改善查詢效能的基本方法。快取可以儲存文件、查詢中使用的篩選器,以及先前查詢的結果。
快取在提交後會被清除,通常需要重新填入,才能再次看到其好處。為了避免這種情況,可以在新的搜尋器被視為開啟之前「預熱」快取,方法是自動用舊快取中的值填入新的快取。
快取管理對於成功的 Solr 實作至關重要,因此應該注意的是,隨著應用程式的成長,快取將需要進行微調。
solrconfig.xml 中的 <query>
本節中的設定會影響 Solr 處理和回應查詢的方式。
這些設定全部在 solrconfig.xml
中 <query>
元素的子元素中設定。
<config>
<query>
...
</query>
</config>
快取
Solr 快取與索引搜尋器的特定實例相關聯,索引搜尋器是索引的特定視圖,在該搜尋器的生命週期內不會變更。只要正在使用該索引搜尋器,其快取中的任何項目都會有效且可重複使用。依預設,快取的 Solr 物件不會在一段時間間隔後過期;相反地,它們在索引搜尋器的生命週期內保持有效。可以使用 maxIdleTime
選項啟用基於閒置時間的過期。
當開啟新的搜尋器時,目前的搜尋器會繼續處理請求,同時新的搜尋器會自動預熱其快取。新的搜尋器會使用目前搜尋器的快取來預先填入自己的快取。當新的搜尋器準備就緒時,它會註冊為目前的搜尋器並開始處理所有新的搜尋請求。舊的搜尋器會在完成處理其所有請求後關閉。
快取實作
Solr 隨附預設的 SolrCache
實作,用於不同類型的快取。
CaffeineCache
是由 Caffeine 快取程式庫支援的實作。依預設,它使用 Window TinyLFU (W-TinyLFU) 清除原則,該原則允許根據使用頻率和最近使用情況,在 O(1) 時間內以較小的佔用空間進行清除。通常,這種快取通常比舊版快取具有更低的記憶體佔用空間、更高的命中率和更好的多執行緒效能。
CaffeineCache
使用自動預熱計數,支援整數和百分比,這些值在預熱發生時會相對於快取的目前大小進行評估。
Solr 管理介面中的外掛程式與統計資訊畫面會顯示所有作用中快取的效能資訊。這些資訊可協助您針對您的特定應用程式適當微調各種快取的大小。當搜尋器終止時,其快取使用情況的摘要也會寫入記錄檔。
快取參數
每個快取都有設定來定義其初始大小 (initialSize
)、最大大小 (size
) 以及預熱期間要使用的項目數 (autowarmCount
)。對於 autowarmCount
,這也可以表示為百分比,而不是絕對值。
maxIdleTime
屬性控制自動移除一段時間未使用的項目。此屬性以秒為單位表示,預設值為 0
,表示不會因為閒置時間過長而自動移除項目。此屬性的值越小,舊項目會越快被移除,這會減少快取記憶體的使用量,但也可能因為相同項目的重複移除-查閱-未命中-插入循環而導致資源浪費。較大的值會讓項目保留較長時間,等待重複使用,但代價是增加記憶體使用量。合理的值,取決於查詢量和模式,可能介於 60-3600 之間。
maxRamMB
屬性限制快取可能消耗的最大記憶體量。當同時指定 size
和 maxRamMB
限制時,maxRamMB
限制會優先,而 size
限制會被忽略。
async
屬性決定快取是否儲存直接結果 (async=false
,停用),或者是否儲存對運算的間接參考 (async=true
,預設啟用)。如果您的查詢包含子文件或聯結查詢,則必須啟用非同步快取才能正常運作。停用非同步選項可能會在每個快取項目上使用稍微少的記憶體,但代價是增加 CPU 使用率。當許多並行查詢請求尚未快取的相同結果集時,非同步快取會提供最顯著的改進,作為較大快取大小或增加自動預熱計數的替代方案。但是,非同步快取不會防止時間限制查詢的資料競爭,因為這些查詢預期會提供部分結果。
可以使用參數 enabled
並將其值設定為 false
來停用所有快取。
以下說明每個快取的詳細資訊。
篩選快取
此快取會保留已剖析的查詢,並搭配符合該查詢的所有文件的無序集合。除非此集合非常小,否則集合實作會是位元集。
Solr 使用 filterCache
最典型的方式是快取每個 fq
搜尋參數的結果,儘管也有其他一些使用案例。後續使用相同參數篩選查詢的查詢會導致快取命中,並快速傳回結果。有關 fq
的詳細討論,請參閱fq (篩選查詢) 參數。
可以使用 cache 本機參數來停用特定查詢的 fq 對此快取的使用。 |
使用此快取的另一個 Solr 功能是預設 Lucene 查詢剖析器中的 filter(…)
語法。
當配置參數 facet.method
設定為 fc
時,Solr 也會將此快取用於分面。有關分面參數的討論,請參閱欄位值分面參數。
<filterCache class="solr.CaffeineCache"
size="512"
initialSize="512"
autowarmCount="128"/>
此快取支援 maxRamMB
參數,可限制此快取使用的最大堆積記憶體量。CaffeineCache
僅支援依堆積使用量或大小進行移除,但不能同時使用兩者。因此,如果指定了 maxRamMB
,則會忽略 size
參數。
<filterCache class="solr.CaffeineCache"
maxRamMB="1000"
autowarmCount="128"/>
篩選快取非常適合啟用 async
計算。
<filterCache class="solr.CaffeineCache"
size="1024"
autowarmCount="0"
async="true"/>
查詢結果快取
queryResultCache
會保留先前搜尋的結果:根據查詢、排序和要求的檔案範圍排序的檔案 ID 清單 (DocList)。
queryResultCache
具有一個可選設定,可限制使用的最大 RAM 量 (maxRamMB
)。這可讓您指定此快取內容使用的最大堆積大小 (以 MB 為單位)。當快取增長超出此大小時,最舊存取的查詢將會被移除,直到快取的堆積使用量降至指定限制以下。如果在 maxRamMB
之外還指定了 size
,則只會遵循堆積使用量限制。
<queryResultCache class="solr.CaffeineCache"
size="512"
initialSize="512"
autowarmCount="128"/>
文件快取
documentCache
保留 Lucene 文件物件 (每個檔案的已儲存欄位)。由於 Lucene 內部檔案 ID 是暫時性的,因此不會自動預熱此快取。
documentCache
的大小應始終大於 max_results
乘以 max_concurrent_queries
,以確保 Solr 在請求期間不需要重新擷取文件。您在文件中儲存的欄位越多,此快取的記憶體使用量就越高。
<documentCache class="solr.CaffeineCache"
size="512"
initialSize="512"
autowarmCount="0"/>
請勿對 documentCache 使用 maxRamMB 設定。快取文件所需的記憶體量將無法正確計算,這可能會導致快取使用的記憶體遠遠超出預期。 |
使用者定義的快取
您也可以定義具名的快取供自己的應用程式碼使用。您可以透過呼叫 SolrIndexSearcher
方法 getCache()
、cacheLookup()
和 cacheInsert()
,依名稱尋找並使用您的快取物件。
<cache name="myUserCache" class="solr.CaffeineCache"
size="4096"
initialSize="1024"
autowarmCount="1024"
regenerator="org.mycompany.mypackage.MyRegenerator" />
如果您想要自動預熱您的快取,請包含一個 regenerator
屬性,其中包含實作 solr.search.CacheRegenerator
的類別完整名稱。您也可以使用 NoOpRegenerator
,它只會使用舊項目重新填入快取。使用 regenerator
參數定義它,例如 regenerator="solr.NoOpRegenerator"
。
監控快取大小和使用情況
快取統計資料章節說明每個快取可用的指標。這些指標可以在外掛程式與統計資訊畫面中或使用指標 API存取。
評估快取時,最重要的指標是大小和命中率。
大小表示快取中有多少項目。某些快取支援以 MB RAM 設定最大快取大小。
命中率是快取提供的查詢百分比,顯示為 0 到 1 之間的數字。較高的值表示快取經常被使用,而較低的值則表示快取對查詢沒有太大幫助。理想情況下,此數字應盡可能接近 1。
如果您發現命中率很低,但已將快取大小設定得很高,則可以透過減少快取大小來最佳化,因為當這些物件未使用時,沒有必要將它們保留在記憶體中。
另一個有用的指標是快取移除,它會測量從快取中移除的物件。高移除率可能表示您的快取太小,增加快取可能會顯示更高的命中率。或者,如果您的命中率很高但移除率很低,則您的快取可能太大,減少大小可能會對您有利。
低命中率並不總是特定快取問題的徵兆。如果您的查詢不常重複,則會預期出現低命中率,因為重複使用快取物件的可能性較低。在這些情況下,較小的快取大小可能最適合您的系統。
查詢大小調整與預熱
有幾個元素可用於控制查詢的大小以及快取的預熱方式。
<maxBooleanClauses> 元素
設定剖析布林查詢字串時允許的最大子句數。
此限制僅會影響使用者在查詢字串中指定的布林查詢,並提供對使用者指定的布林查詢複雜程度的每個集合控制。指定子句數超過此限制的查詢字串將會導致錯誤。
如果此每個集合的限制大於在 solr.xml
中指定的全域 maxBooleanClauses
限制,則不會有任何作用,因為該設定也會限制使用者指定的布林查詢的大小。
在預設配置中,此屬性會使用 solr.max.booleanClauses
系統屬性的值 (如果已指定)。這與預設 solr.xml
中的全域 maxBooleanClauses
設定中使用的相同系統屬性,這使得 Solr 管理員可以輕鬆地增加這兩個值 (在所有集合中),而無需搜尋和更新每個集合中的 solrconfig.xml
檔案。
<maxBooleanClauses>${solr.max.booleanClauses:1024}</maxBooleanClauses>
<minPrefixQueryTermLength> 元素
基於前置詞的查詢會消耗與索引中以指定前置詞開頭的詞彙數量成正比的資源。特別是短前置詞,例如只有一個或兩個字元的前置詞,往往會符合索引的很大一部分,因此它們是資源爭用和不穩定性的常見原因。此設定為查詢建立了最小前置詞長度,讓管理員能夠封鎖可能導致穩定性問題的查詢。不符合此最小前置詞長度的查詢會觸發錯誤。此設定可以在每個查詢的基礎上覆寫,方法是提供具有不同值的 minPrefixQueryTermLength
"本機參數"。
此設定旨在管理所有基於前置詞的查詢 (例如,val_s:a*
、{!prefix f=val_s}a
、{!complexphrase}val_s:"a*"
)。
在預設配置集中,最小前置詞設定為 '-1' (語意為「無限制」的旗標值) 或 solr.query.minPrefixLength
系統屬性的值 (如果已指定)。
<enableLazyFieldLoading> 元素
當此參數設定為 true
時,未直接要求的欄位只會在需要時才會載入。
如果最常見的查詢只需要一小部分欄位,尤其是當不常存取的欄位很大時,這可以提高效能。
<enableLazyFieldLoading>true</enableLazyFieldLoading>
<useFilterForSortedQuery> 元素
此設定僅會影響要求排序不包含「分數」的查詢 (或分數不相關的查詢,例如,未要求文件,查詢輸出常數分數)。在這種情況下,將此元素設定為 true
會導致查詢 filterCache
是否有符合主查詢的篩選條件。如果重複發出相同的搜尋,但具有不同的排序選項或透過 offset
或 cursorMark
的不同分頁,則這會很有用 (再次,前提是「分數」未包含或與要求的排序無關)。如果啟用此選項,請確保 filterCache
具有足夠的容量來支援預期的使用模式。
<useFilterForSortedQuery>true</useFilterForSortedQuery>
<queryResultWindowSize> 元素
與 queryResultCache
一起使用,這會快取所要求文件 ID 的超集。
例如,如果查詢要求文件 10 到 19,且 queryWindowSize
為 50,則會快取文件 0 到 49。
<queryResultWindowSize>20</queryResultWindowSize>
<queryResultMaxDocsCached> 元素
此參數設定 queryResultCache
中任何項目的快取文件最大數量。
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
與查詢相關的監聽器
如 快取 章節中所述,新的搜尋器會被快取。可以使用監聽器的觸發器來執行與查詢相關的任務。最常見的用途是定義查詢,以便在搜尋器啟動時進一步「暖機」。這種方法的一個好處是,欄位快取會預先填入以加快排序速度。
良好的查詢選擇是這種類型監聽器的關鍵。最好選擇您最常見和/或最繁重的查詢,不僅要包括使用的關鍵字,還要包括任何其他參數,例如排序或篩選請求。
有兩種事件可以觸發監聽器。
-
當正在準備新的搜尋器,但沒有目前註冊的搜尋器來處理請求或從中獲取自動暖機資料時(即在 Solr 啟動時),會發生
firstSearcher
事件。 -
每當準備新的搜尋器時,例如在提交之後,並且有目前的搜尋器正在處理請求時,就會觸發
newSearcher
事件。
以下(已註解)的範例可以在 Solr 附帶的 sample_techproducts_configs
配置集 的 solrconfig.xml
檔案中找到,並示範如何使用 solr.QuerySenderListener
類別來暖機一組明確的查詢
<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>
以上程式碼來自範例 一個關鍵的最佳實務是在將應用程式投入生產之前修改這些預設值,但請注意:雖然範例查詢在「newSearcher」的部分被註解掉,但範例查詢在「firstSearcher」事件中沒有被註解掉。 如果查詢字串「static firstSearcher warming in solrconfig.xml」與您的搜尋應用程式無關,則沒有必要使用該查詢字串自動暖機您的搜尋器。 |
使用 Config API 管理暖機查詢
可以使用 Config API 透過以下命令管理暖機查詢。
可以提供具有不同 name
屬性的多個集合,並且任何變更都會立即生效,無需重新啟動。
新增暖機查詢集
要新增一組暖機查詢,請使用 add-listener
命令。(您可能希望使用單獨的命令和 name
來提供 firstSearcher
查詢。)
{
"add-listener": {
"name": "my-warming-queries",
"event": "newSearcher",
"class": "solr.QuerySenderListener",
"queries": [
{ "q": "solr", "sort": "price asc" }
]
}
}
更新查詢集
要更新集合,請使用 update-listener
命令。請注意,整個集合將被替換。
{
"update-listener": {
"name": "my-warming-queries",
"event": "newSearcher",
"class": "solr.QuerySenderListener",
"queries": [
{ "q": "solr", "sort": "price asc" },
{ "q": "rocks", "sort": "weight asc" }
]
}
}
如果暖機查詢定義在 solrconfig.xml
中,如果為每個 <listener>
元素新增 name
屬性,則可以使用 Config API 覆寫它們。