使用 Apache Solr 實現更加靈巧的搜索,第 2 部分: 用於企業的 Solr
管理、配置和性能
在本部分中,Lucene Java™ 的提交人 Grant Ingersoll 通過對用於企業的特性(包括管理界面、高級配置選項)以及與性能相關的特性(比如緩存、複製和日誌記錄)的探究,完成了對 Solr 的介紹。
0 評論:
Grant Ingersoll, 高級軟件工程師, Center for Natural Language Processing at Syracuse University
2007 年 7 月 02 日
在本系列的 第 1 部分,我爲您介紹了 Apache Solr,一種基於 HTTP 的開源搜索服務器,它可以很容易地與多種 Web 應用程序集成。我展示了 Solr 最基本的功能,包括索引、搜索和瀏覽,介紹了 Solr 模式並解釋了它在配置 Solr 功能方面的作用。在本部分中,我將通過列舉 Solr 作爲大型生產環境中理想的解決方案時所具備的特性來完成對 Solr 的介紹。涵蓋的主題包括管理、緩存、複製和可擴展性。
請參閱 第 1 部分 來獲得安裝和設置 Solr 的指導。
配置和管理
本部分介紹了可用於監視和控制 Solr 功能性的諸多選項,首先來看看 Solr 的 Administration Start Page,該頁可在 http://localhost:8080/solr/admin/ 找到。一旦找到了起始頁,在繼續之前,請務必花些時間熟悉一下上面的各種菜單選項。在起始頁中,根據這些選項所提供的信息的不同對它們進行了分組:
- Solr 給出了有關這種活動模式(請參見 第 1 部分)、配置以及當前部署的統計數據的詳細信息。
- App server 給出了容器的當前狀態,包括 threading 信息以及所有 Java 系統屬性的列表。
- Make a Query 提供了調試查詢所需的快捷界面以及到功能更加全面的查詢界面的鏈接。
- Assistance 提供了到外部資源的有用鏈接以便理解和解決使用 Solv 可能遇到的一些問題。
如下的章節詳細介紹了這些菜單選項並重點突出了其中的管理特性。
要使用 Solr 的配置選項,可以單擊初始頁上的 CONFIG
鏈接,這會顯示當前的 solrconfig.xml 文件。您可以在 示例應用程序 的 dw-solr/solr/conf 目錄找到該文件。現在,讓我們先來看看與索引和查詢處理有關的一些常見的配置選項,而與 緩存、複製 和 擴展 Solr 有關的配置選項則留到後面的章節再介紹。
索引配置
mainIndex
標記段定義了控制 Solr 索引處理的低水平的 Lucene 因素。Lucene 基準發佈(位於 Lucene 源代碼的 contrib/benchmark
之下)包含了很多可用來對這些因素的更改效果進行基準測試的工具。此外,請參閱 參考資料 一節中的 「Solr 性能因素」 來了解與各種更改相關的性能權衡。表 1 概括了可控制 Solr 索引處理的各種因素:
表 1. 對性能因素進行索引
因素 | 描述 |
---|---|
useCompoundFile | 通過將很多 Lucene 內部文件整合到單一一個文件來減少使用中的文件的數量。這可有助於減少 Solr 使用的文件句柄數目,代價是降低了性能。除非是應用程序用完了文件句柄,否則 false 的默認值應該就已經足夠。 |
mergeFactor | 決定低水平的 Lucene 段被合併的頻率。較小的值(最小爲 2)使用的內存較少但導致的索引時間也更慢。較大的值可使索引時間變快但會犧牲較多的內存。 |
maxBufferedDocs | 在合併內存中文檔和創建新段之前,定義所需索引的最小文檔數。段 是用來存儲索引信息的 Lucene 文件。較大的值可使索引時間變快但會犧牲較多的內存。 |
maxMergeDocs | 控制可由 Solr 合併的 Document 的最大數。較小的值 (< 10,000) 最適合於具有大量更新的應用程序。 |
maxFieldLength | 對於給定的 Document ,控制可添加到 Field 的最大條目數,進而截斷該文檔。如果文檔可能會很大,就需要增加這個數值。然而,若將這個值設置得過高會導致內存不足錯誤。 |
unlockOnStartup | unlockOnStartup 告知 Solr 忽略在多線程環境中用來保護索引的鎖定機制。在某些情況下,索引可能會由於不正確的關機或其他錯誤而一直處於鎖定,這就妨礙了添加和更新。將其設置爲 true 可以禁用啓動鎖定,進而允許進行添加和更新。 |
查詢處理配置
在 <query>
部分,有一些與 緩存 無關的特性,這一點您需要知道。首先,<maxBooleanClauses>
標記定義了可組合在一起形成一個查詢的子句數量的上限。對於大多數應用程序而言,默認的 1024 就應該已經足夠;然而,如果應用程序大量使用了通配符或範圍查詢,增加這個限值將能避免當值超出時,拋出 TooManyClausesException
。
接下來,若應用程序預期只會檢索 Document
上少數幾個 Field
,那麼可以將<enableLazyFieldLoading>
屬性設置爲 true。懶散加載的一個常見場景大都發生在應用程序返回和顯示一系列搜索結果的時候,用戶常常會單擊其中的一個來查看存儲在此索引中的原始文檔。初始的顯示常常只需要顯示很短的一段信息。若考慮到檢索大型 Document
的代價,除非必需,否則就應該避免加載整個文檔。
最後,<query>
部分負責定義與在 Solr 中發生的事件相關的幾個選項。首先,作爲一種介紹的方式,Solr(實際上是 Lucene)使用稱爲 Searcher
的 Java 類來處理 Query
實例。Searcher
將索引內容相關的數據加載到內存中。根據索引、CPU 以及可用內存的大小,這個過程可能需要較長的一段時間。要改進這一設計和顯著提高性能,Solr 引入了一種 「溫暖」 策略,即把這些新的 Searcher
聯機以便爲現場用戶提供查詢服務之前,先對它們進行 「熱身」。<query>
部分中的 <listener>
選項定義 newSearcher
和 firstSearcher
事件,您可以使用這些事件來指定實例化新搜索程序或第一個搜索程序時應該執行哪些查詢。如果應用程序期望請求某些特定的查詢,那麼在創建新搜索程序或第一個搜索程序時就應該反註釋這些部分並執行適當的查詢。
solrconfig.xml 文件的剩餘部分,除 <admin>
之外,涵蓋了與 緩存、複製 和 擴展或定製 Solr 有關的項目。admin
部分讓您可以定製管理界面。有關配置 admin
節的更多信息,請參看 Solr Wiki 和 solrconfig.xml 文件中的註釋。
監視、記錄和統計數據
在 http://localhost:8080/solr/admin 的管理頁,有幾個菜單條目可以讓 Solr 管理員監視 Solr 過程。表 2 給出了這些條目:
表 2. 用於監視、記錄和統計數據的 Solr 管理選項
菜單名 | Admin URL | 描述 |
---|---|---|
Statistics | http://localhost:8080/solr/admin/stats.jsp | Statistics 管理頁提供了與 Solr 性能相關的很多有用的統計數據。這些數據包括:
|
Info | http://localhost:8080/solr/admin/registry.jsp | 有關正在運行的 Solr 的版本以及在當前實現中進行查詢、更新和緩存所使用的類的詳細信息。此外,還包括文件存於 Solr subversion 存儲庫的何處的信息以及對該文件功能的一個簡要描述。 |
Distribution | http://localhost:8080/solr/admin/distributiondump.jsp | 顯示與索引發布和複製有關的信息。更多信息,請參見 「發佈和複製」 一節。 |
Ping | http://localhost: 8080/solr/admin/ping | 向服務器發出 ping 請求,包括在 solrconfig.xml 文件的 admin 部分定義的請求。 |
Logging | http:// localhost:8080/solr/admin/logging.jsp | 讓您可以動態更改當前應用程序的日誌記錄等級。更改日誌記錄等級對於調試在執行過程中可能出現的問題非常有用。 |
Java properties | http: //localhost:8080/solr/admin/get-properties.jsp | 顯示當前系統正在使用的所有 Java 系統屬性。Solr 支持通過命令行的系統屬性替換。有關實現此特性的更多信息,請參見 solrconfig.xml 文件。 |
Thread dump | http://localhost:8080/solr/admin/threaddump.jsp | thread dump 選項顯示了在 JVM 中運行的所有線程的堆棧跟蹤信息。 |
調試此分析過程
經常地,當創建搜索實現時,您都會輸入一個應該匹配特定文檔的搜索,但它不會出現在結果中。在大多數情況下,故障都是由如下兩個因素之一引起的:
- 查詢分析和文檔分析不匹配(雖然不推薦,但對文檔的分析可能會與對查詢的分析不同)。
-
Analyzer
正在修改不同於預期的一個或多個條目。
可以使用位於 http://localhost:8080/solr/admin/analysis.jsp 的 Solr 分析管理功能來深入調查這兩個問題。Analysis 頁可接受用於查詢和文檔的文本片段以及能確定文本該如何分析並返回正被修改的文本的逐步結果的 Field
名稱。圖 1 顯示了分析句子 「The Carolina Hurricanes are the reigning Stanley Cup champions, at least for a few more weeks」 以及相關的查詢 「Stanley Cup champions」 的部分結果,正如爲示例應用程序 schema.xml 中指定的 content Field
分析的那樣:
圖 1. 對分析進行調試
![調試 Solr 的分析過程](http://static.javashuo.com/static/loading.gif)
分析屏幕顯示了每個條件在被上述表結果 Tokenizer
或 TokenFilter
處理後的結果。比如,StopFilterFactory
會刪除字 The、are 和the。EnglishPorterFilterFactory
會將字 champions 提取爲 champion,將 Hurricanes 提取爲 hurrican。紫色的醒目顯示錶明在特定文檔中查詢條件在何處有匹配。
查詢測試
admin 頁的 Make a Query
部分提供了可輸入查詢並查看結果的搜索框。這個輸入框接受 第 1 部分 中討論到的 Lucene 查詢解析器語法,而 Full Interface
鏈接則提供了對更多搜索特性的控制,比如返回的結果的數量、在結果集中應該包括哪些字段以及如何格式化輸出。此外,該界面還可用來解釋文檔的計分以更好地理解哪些條件得到了匹配以及這些條件是如何得分的。要實現這一目的,可以查看 Debug: enable
選項並滾動到搜索結果的底端來查看相關解釋。
智能緩存
智能緩存是讓 Solr 得以成爲引人矚目的搜索服務器的一個關鍵性能特徵。例如,Solr 在提供緩存服務之前可通過使用舊緩存中的信息來自熱緩存,以便在服務於現有用戶的同時改進性能。Solr 提供了四種不同的緩存類型,所有四種類型都可在 solrconfig.xml 的 <query>
部分中配置。表 3 根據在 solrconfig.xml 文件中所用的標記名列出了這些緩存類型:
表 3. Solr 緩存類型
緩存標記名 | 描述 | 能否自熱? |
---|---|---|
filterCache | 通過存儲一個匹配給定查詢的文檔 id 的無序集,過濾器讓 Solr 能夠有效提高查詢的性能。緩存這些過濾器意味着對 Solr 的重複調用可以導致結果集的快速查找。更常見的場景是緩存一個過濾器,然後再發起後續的精煉查詢,這種查詢能使用過濾器來限制要搜索的文檔數。 | 可以 |
queryResultCache | 爲查詢、排序條件和所請求文檔的數量緩存文檔 id 的有序 集合。 | 可以 |
documentCache | 緩存 Lucene Document ,使用內部 Lucene 文檔 id(以便不與 Solr 惟一 id 相混淆)。由於 Lucene 的內部 Document id 可以因索引操作而更改,這種緩存不能自熱。 |
不可以 |
Named caches | 命名緩存是用戶定義的緩存,可被 Solr 定製插件 所使用。 | 可以,如果實現了org.apache.solr.search.CacheRegenerator 的話。 |
每個緩存聲明都接受最多四個屬性:
-
class
是緩存實現的 Java 名。 -
size
是最大的條目數。 -
initialSize
是緩存的初始大小。 -
autoWarmCount
是取自舊緩存以預熱新緩存的條目數。如果條目很多,就意味着緩存的 hit 會更多,只不過需要花更長的預熱時間。
而對於所有緩存模式而言,在設置緩存參數時,都有必要在內存、CPU 和磁盤訪問之間進行均衡。統計信息管理頁 對於分析緩存的 hit-to-miss 比例以及微調緩存大小的統計數據都非常有用。而且,並非所有應用程序都會從緩存受益。實際上,一些應用程序反而會由於需要將某個永遠也用不到的條目存儲在緩存中這一額外步驟而受到影響。
發佈和複製
對於收到大量查詢的應用程序,單一一個 Solr 服務器恐怕不足以滿足性能上的需求。因而,Solr 提供了跨多個服務器複製 Lucene 索引的機制,這些服務器必須是負載均衡的查詢服務器的一部分。複製過程由 solrconfig.xml 文件啓動的事件偵聽程序和幾個 shell 腳本(位於示例應用程序的 dw-solr/solr/bin)處理。
在複製架構中,一個 Solr 服務器充當主服務器,負責向一個或多個處理查詢請求的從服務器提供索引的副本(稱爲 snapshot
)。索引命令發送到主服務器,查詢則發送到從服務器。主服務器可以手動創建快照,也可以通過配置 olrconfig.xml 的 <updateHandler>
部分(請參見清單 1)來觸發接收到 commit
和/或 optimize
事件時的快照創建。無論是手動創建還是事件驅動的創建,都會在主服務器上調用snapshooter
腳本,這會在名爲 snapshot.yyyymmddHHMMSS
(其中的 yyyymmddHHMMSS
代表實際創建快照的時間)的服務器上創建一個目錄。之後,從服務器使用 rsync 來只複製 Lucene 索引中的那些已被更改的文件。
清單 1. 更新句柄偵聽程序
<listener event="postCommit" class="solr.RunExecutableListener"> <str name="exe">snapshooter</str> <str name="dir">solr/bin</str> <bool name="wait">true</bool> <arr name="args"> <str>arg1</str> <str>arg2</str> </arr> <arr name="env"> <str>MYVAR=val1</str> </arr> </listener>
清單 1 顯示了在收到 commit
事件後,在主服務器上創建快照所需的配置。同樣的配置也同樣適用處理 optimize
事件。在這個示例配置中,在 commit
完成後,Solr 調用位於 solr/bin
目錄的 snapshooter
腳本,傳入指定的參數和環境變量。wait
實參告知 Solr 在繼續之前先等待線程返回。有關執行 snapshooter
和其他配置腳本的詳細信息,請參見 Solr 網站上的 「Solr Collection and Distribution Scripts」 文檔(請參見 參考資料)。
在從服務器上,使用 snappuller
shell 腳本從主服務器上檢索快照。snappuller
從主服務器上檢索了所需文件後,snapinstaller
shell 腳本就可用來安裝此快照並告知 Solr 有一個新的快照可用。根據快照創建的頻率,最好是安排系統定期執行這些步驟。在主服務器上,rsync 守護程序在從服務器獲得快照之前必須先行啓動。rsyn 守護程序可用 rsyncd-enable
shell 腳本啓用,然後再用 rsyncd-start
命令實際啓動。在從服務器上,snappuller-enable
shell 腳本必須在調用 snappuller
shell 腳本之前運行。
排除發佈故障
雖然,我們已經竭盡全力地對索引更新的發佈進行了優化,但還是有幾個常見的場景會爲 Solr 帶來問題:
- 優化大型索引可能會非常耗時,而且應該在索引更新不是很頻繁的情況下才進行。 優化會導致多個 Lucene 索引文件合併成一個單一文件。這就意味者從服務器必須要複製整個索引。然而,這種方式的優化還是比在每個從服務器上進行優化要好很多。這些服務器可能與主服務器不同步,導致新副本再次被檢索。
- 如果從主服務器中獲取新快照的頻率過高,則從服務器的性能可能會降低,這種降低源於使用
snappuller
複製更改的開銷以及在安裝新索引時的緩存預熱。有關頻繁的索引更新方面的性能均衡的詳細信息,請參見 參考資料 中的 「Solr Performance Factors」。
最終,向從服務器添加、提交和獲取更改的頻繁程度完全取決於您自己的業務需求和硬件能力。仔細測試不同的場景將會幫助您定義何時需要創建快照以及何時需要從主服務器中獲取這些快照。有關設置和執行 Solr 發佈和複製的更多信息,請參看 參考資料 中的 「Solr Collection and Distribution」 文檔。
定製 Solr
Solr 提供了幾個插件點,您可以在這裏添加定製功能來擴展或修改 Solr 處理。此外,由於 Solr 是開源的,所以如果需要不同的功能,您儘可以更改源代碼。有兩種方式可以向 Solr 添加插件:
- 打開 Solr WAR,在
WEB-INF/lib
目錄下添加新的庫,重新打包這些文件,然後將 WAR 文件部署到 servlet 容器。 - 將 JAR 放入 Solr Home
lib
目錄,然後啓動 servlet 容器。這種方法使用了定製ClassLoader
且有可能不適用於某些 servlet 容器。
接下來的幾個章節突出介紹了可能希望擴展 Solr 的幾個領域。
請求處理
若現有的功能不能滿足業務需求,Solr 允許應用程序實現其自身的請求處理功能。比如,您可能想要支持您自己的查詢語言或想要將 Solr 與您的用戶配置文件相集成來提供個性化的效果。SolrRequestHandler
接口定義了實現定製請求處理所需的方法。實際上,除了 第 1 部分所使用的那些默認的 「標準」 請求處理程序之外,Solr 還定義了其他幾個請求處理程序:
- 默認的
StandardRequestHandler
使用 Lucene Query Parser 語法處理查詢,添加了排序和層面瀏覽。 -
DisMaxRequestHandler
被設計用來通過更爲簡單的語法來跨多個Field
進行搜索。它也支持排序(使用與標準處理程序稍有不同的語法)和層面瀏覽。 -
IndexInfoRequestHandler
可以檢索有關索引的信息,比如索引中的文檔數或Field
數。
請求處理程序是由請求中的 qt
參數指定的。Solr servlet 使用參數值來查找給定的請求處理程序並將輸入用於請求處理程序的處理。請求處理程序的聲明和命名通過 solrconfig.xml 中的 <requestHandler>
標記指定。要添加其他的內容,只需實現定製的 SolrRequestHandler
線程安全的實例即可,將其添加到 上述 定義好的 Solr,並將其包括到 如前所述 的類路徑中,之後就可以通過 HTTP GET
或 POST
方法開始向其發送請求了。
響應處理
與請求處理類似,也可以定製響應輸出。必須要支持老式的搜索輸出或必須要使用二進制或加密輸出格式的應用程序可以通過實現QueryResponseWriter
來輸出所需的格式。 然而,在添加您自己的 QueryResponseWriter
之前,需要先深入研究一下 Solr 所自帶的實現,如表 4 所示:
表 4. Solr 的查詢響應書寫器
<requestHandler>
SolrRequestHandler
上述
如前所述
HTTP GET
POST
響應處理
與請求處理類似,也可以定製響應輸出。必須要支持老式的搜索輸出或必須要使用二進制或加密輸出格式的應用程序可以通過實現QueryResponseWriter
來輸出所需的格式。 然而,在添加您自己的 QueryResponseWriter
之前,需要先深入研究一下 Solr 所自帶的實現,如表 4 所示:
表 4. Solr 的查詢響應書寫器
查詢響應書寫器 | 描述 |
---|---|
XMLResponseWriter | 這個最爲常用的響應格式以 XML 格式輸出結果,如 第 1 部分 的博客應用程序所示。 |
XSLTResponseWriter | XSLTResponseWriter 將 XMLResponseWriter 的輸出轉換成指定的 XSLT 格式。請求中的 tr 參數指定了要使用的 XSLT 轉換的名稱。指定的轉換必須存在於 Solr Home 的 conf/xslt 目錄。有關 XSLT Response Writer 的更多內容,請參見 參考資料。 |
JSONResponseWriter | 用 JavaScript Object Notation (JSON) 格式輸出結果。JSON 是一種簡單、人類可讀的數據轉換格式,而且非常易於機器解析。 |
RubyResponseWriter | RubyResponseWriter 是對 JSON 格式的擴展以便在 Ruby 中安全地使用結果。若有興趣將 Ruby 和 Solr 結合使用,可以參考 參考資料 中給出的到 acts_as_solr 和 Flare 的鏈接。 |
PythonResponseWriter |