第一章
一、簡介
solr是一個開源的,企業級搜尋伺服器。她已經是一個成熟的産品,用于強化網絡站點的搜尋功能,包括内部區域網路。
她是用java語言編寫。使用http和xml進行資料傳輸,java的掌握對于學習solr不是必須的。除了能傳回搜尋
結果外,還有包括高亮搜尋關鍵字,方位導航(已廣泛用于電子商務網站),查詢關鍵字拼寫校驗,自動查詢建議
和 “類似”查詢 幫助更好定位搜尋。
二、lucene,solr的基礎引擎
在相信介紹solr前,我們先從apache lucene開始,solr的核心基礎引擎。lucene是一個開源的,高效的
文本搜尋引擎。lucene是由doug cutting在2000年開發的,并且伴随着強大的線上社群不斷進化和成熟。
lucene不是一個伺服器,也不是一個網絡爬蟲。這一點非常重要,她沒有任何配置檔案。我們需要編寫代碼來
存貯和查詢在磁盤上的索引。
下面是lucene的一些主要特征:
通過建立基于文本的反向索引來快速查詢檔案。
通過豐富的文本分析器(analyzers),将字元串形式的文本資訊轉換為一系列terms,來聯系索引和搜尋。
一個查詢分析器,還有很多能 支援從簡單查詢到模糊查詢 的查詢類型(query types)
一個聽上去叫information retrieval(ir)的得分算法,以産生更多可能的候選結果,有很多靈活的方式來設定得分政策。
在上下文中高亮顯示被找到的查詢關鍵字
根據索引内容 來 檢查 查詢關鍵字拼寫(更多關于查詢關鍵字拼寫 可以參考lucene in action)
三、solr,是lucene的伺服器化産物
在對lucene的了解後,solr可以了解為lucene的伺服器化産品。但她不是對lucene的一次簡單封裝,solr的大多數特征都與lucene不同。solr 和 lucene 的界限經常是模糊的。以下是solr的主要特性:
通過http請求來 建立索引和搜尋索引
擁有數個緩存 來 加快搜尋速度
一個基于web的管理者控制台
運作時做性能統計,包括緩存 命中/錯過 率
查詢表單 來 搜尋索引。
以柱狀圖形式 展示 頻繁被查詢的關鍵字
詳細的“得分計算和文本解析”分析。
用xml檔案的方式 配置搜尋計劃和伺服器
通過配置xml 來添加和配置 lucene的文本分析庫
引入“搜尋字段類型”的概念(這個非常重要,然而在lucne中沒有)。類型用作表示日期和一些特殊的排序問題。
對最終使用者和應用成素,disjunction-max 查詢處理器比lucene基礎查詢器更實用。
查詢結果的分類
拼寫檢查用于尋找搜尋關鍵字 的類似詞,優化查詢建議
“更類似于”插件用以列出 于查詢結果類似的 備選結果。
solr支援分布式來應對較大規模的部署。
以上特征都會在下面的章節内詳述。
四、solr 于資料庫技術的比較
對于開發人員而言,資料庫技術(特别是關系資料庫)已經成為一個必須學習的知識。資料庫和lucene的搜尋索引并沒有顯著的不同。假設我們已經非常熟悉資料庫知識,現在來描述下她和lucene有什麼不同。(這裡來幫助更好了解solr)
最大的不同是,lucene可以了解為一個 隻有一張簡單表格 的資料庫,沒有任何的關系查詢(即joins)。這聽上去很瘋狂,不過記住索引隻是為了去支援搜尋,而不是去辨別一條資料。是以資料庫可以去遵守“第三範式”,而索引就不會如此,表格中盡可能多的包含會被搜尋到的資料而已。用來補充單表的是,一個域(列)中可以有多值。
其他一些顯著的不同:
更新(update):整個文檔可以被删除,然後再添加,但不能被更新。
子字元串搜尋與文本搜尋:例如“books”,資料庫的like比對出“cookbooks”、“mybooks”。lucene基于查詢分析器的配置,可以查到更多形式的詞比對“books”,比如book(這裡是大小寫被忽略),甚至發音相似的詞。運用ngram技術,她可以提取部分搜尋條件的詞幹進行比對。
結果打分:lucene的強大在于她可以根據結果的比對程度來打分。例如查詢條件中有部分是可選的(or search),那比對程度高的文檔會得到更多的分。有一些其他因素,可以調整打分的方式。然而,資料庫就沒有這個功能,隻是比對或不比對。lucene也可以在需要的時候對結果進行排序。
延遲送出:solr的搜尋速度通過建立緩存得以優化。當一個完成的文檔需要被送出,所有的緩存會重新建構,根據其他一些因素,這可能花費幾秒到一分鐘。
五、正式開始solr
solr是用java編寫的,不過我們不需要對java非常了解。如果需要擴充solr的功能,那我們需要了解java。
我們需要掌握的是指令行操作,包括dos和unix。
在正式開始前,我們可能需要安裝以下一些包:
a java development kit(jdk) v1.5 or later.
apache ant: any recent version
subversion or git for source control of solr: svn 或 git
any java ee servlet engine app-server:sole 已經自帶了jetty。
将最新的源代碼下載下傳到本地solr_svn目錄下。
solr 釋出包下的目錄結構:
client::包含特定的程式設計語言與solr通信。這裡其實隻有ruby的例子。java的用戶端在src/solrj
dist:這裡包含solr的jar包和war包
example:這裡有jetty安裝所需要的包(solr自帶jetty),包括一些樣本資料和solr的配置檔案。
example/etc:jetty的配置檔案。可以修改監聽端口(預設8983)
example/multicore:多核環境下,solr的根目錄(後面會具體讨論)
example/solr:預設環境下的solr根目錄
example/webapps:solr的war包部署在這裡
lib:所有solr依賴的包。一大部分是lucene,一些apache常用的工具包,和stax(xml處理相關)
src:各種源碼。可以歸為以下幾個重要目錄:
src/java:solr的源代碼,用java編寫。
src/scripts:unix的bash shell腳本,應用與在大型應用中部署多個solr服務。
src/solrj:solr java的用戶端。
src/webapp:solr web端的管理者使用者界面,包括servlets和jsp。這些其實也都是war中的内容。
注意:要看java源碼的話,src/java下是主要的solr源碼;src/common下是一部分通用類,供server端和solrj用戶端;src/test中是測試代碼;src/webapp/src下是servlet代碼;
六、solr的根目錄
solr的根目錄下包括solr的配置和運作solr執行個體需要的資料。
sole有一個樣例根目錄,在example/solr下,我們将會使用這個
另一個更技術層面的,在example/solr下,也是solr的一個根目錄不過是用在多核的環境下,稍後讨論。
讓我們來看下根目錄下有些什麼:
bin:如果想自己設定solr,這裡可以放腳本。
conf:配置檔案。下面的2個檔案很重要,這個檔案夾下還包括一些其他檔案,都是被這2個檔案引用,為了一些其他配置,比如文本分析的細節。
conf/schema.xml:這裡是索引的概要,包括 域類型(field type)定義和相關分析器鍊。
conf/sorconfig.xml:這是solr配置的主檔案。
conf/xslt:這個目錄薄厚一些xslt檔案,用來把solr搜尋結果(xml)轉換為其他形式,例如atom/rss。
data:包含lucene的索引資料,solr自動生成。這些都是二進制資料(binary),我們基本不會去動它,除非需要删除。
lib:一些額外的,可選的java jar包,solr會在啟動時調用。當你不是通過修改solr源碼 強化solr的一些功能,可以将包放在這裡。
七、solr如何找到自己的根目錄
solr啟動後的第一件事是從根目錄加載配置資訊。這可以通過好幾種方式來指定。
solr先從java的系統環境變量中搜尋 solr.solr.home這個變量。通常通過指令行設定,如啟動jetty時:java -dsolr.solr.home = solr/ -jar start .jar ;也可以用jndi 綁定路徑到java:comp/env/solr/home,可以設定web.xml來讓app-server維護這個變量(src/web-app/web/web-inf)
<env-entry>
<env-entry-name>solr/home</env-entry-name>
<env-entry-value>solr/</env-entry-value>
<env-entry-type>java.lang.string</env-entry-type>
</env-entry>
這裡修改了web.xml,需要使用ant dist-war重新打包部署。這裡僅僅如此還不夠,需要設定jndi,這裡就不深入了。
ps:jndi需要設定2個環境變量,具體檢視ejb相關筆記。
如果根目錄沒有設定在環境變量或jndi中,預設位址是 solr/。我們後面會沿用這個位址。(具體産品還是需要配置來設定,比較安全,可以使用絕對或相對路徑)
設定完根路徑後,在solr啟動中的log會顯示:
aug 7, 2008 4:59:35 pm org.apache.solr.core.config getinstancedir
info: solr home defaulted to 'null' (could not find system property or jndi)
aug 7, 2008 4:59:35 pm org.apache.solr.core.config setinstancedir
info: solr home set to 'solr/'
八、部署和運作solr
部署就是apach-solr-1.4.war。這裡不包含solr的根目錄。
這裡我們以自帶的jetty為例子,進入example目錄
cd example
java -jar start.jar
看到下面這句日志,即啟動完成:
2010-07-09 15:31:06.377::info: started socketconnector @ 0.0.0.0:8983
在控制台點選ctrl-c 可以關閉伺服器。
0.0.0.0表示她監聽來自任務主機的請求,8983是端口号。
九、簡單浏覽下solr
頂部灰色部分:
頭部資訊,當啟動多個solr執行個體時,可以幫助了解在操作哪個執行個體。ip位址和端口号都是可見的。
example(admin旁邊)是對這個schema的引用,僅僅是辨別這個schema。如果你有很多schema,可以用這個辨別去區分。
目前工作目錄(cwd) ,和solr的根目錄(solrhome)。
導航欄上的功能:
schema:顯示目前的schema的配置檔案。(不同浏覽器顯示可能不同,firefox會高亮顯示文法關鍵字)
config:顯示目前的solr config檔案。
analysis:她用來診斷潛在的 文本分析 的查詢/索引問題。這是進階功能,稍後做讨論。
schema browser:這是一個簡潔的 反映目前索引中實際存放資料的 視圖,稍後做讨論。
statistics:這裡是 時間和緩存命中率統計。稍後做讨論。
info:她列出了solr目前應用元件的版本資訊,不是很常用。
distribution:這裡包含了分布式/複制的狀态資訊,稍後讨論。
ping:可以忽略,她用來在分布式模式下提供健壯性檢查。
logging:可以在這裡設定solr不同部分的logging levels。在jetty下,輸出的資訊都在控制台。(solr使用slf4j)
java properties:列出了java系統環境變量。
thread dump:這裡顯示了java中的線程資訊,幫助診斷問題。
full interface:一個更多選擇的查詢表單,可以幫助診斷問題。這個表單也是能力有限的,隻能送出一小部分搜尋選項給solr
assistance 部分包括一些線上的幫助資訊。
十、裝在示例資料
solr有一些示例資料和裝載腳本,在example/exampledocs下。
進入example/exampledoce下,輸入:
java -jar post.jar *.xml (如果在unix環境下,就運作post.sh)
可以在控制台指令行中看到發送的檔案:
simpleposttool: posting file hd.xml
simpleposttool: posting file ipod_other.xml
simpleposttool: posting file ipod_video.xml
simpleposttool: posting file mem.xml
simpleposttool: posting file monitor.xml
simpleposttool: posting file monitor2.xml
simpleposttool: posting file mp500.xml
simpleposttool: posting file payload.xml
simpleposttool: posting file sd500.xml
simpleposttool: posting file solr.xml
simpleposttool: posting file utf8-example.xml
simpleposttool: posting file vidcard.xml
simpleposttool: committing solr index changes..
最後一行會執行commit操作,保證之前的文檔都被儲存,并可見。
理論上post.sh 和 post.jar是可以用在産品腳本上的,但這裡僅僅用作示例。
這裡取其中一個檔案monitor.xml 看下:
<add>
<doc>
<field name="id">3007wfp</field>
<field name="name">dell widescreen ultrasharp 3007wfp</field>
<field name="manu">dell, inc.</field>
<field name="cat">electronics</field>
<field name="cat">monitor</field>
<field name="features">30" tft active matrix lcd, 2560 x 1600,
.25mm dot pitch, 700:1 contrast</field>
<field name="includes">usb cable</field>
<field name="weight">401.6</field>
<field name="price">2199</field>
<field name="popularity">6</field>
<field name="instock">true</field>
</doc>
</add>
這個發送給solr的檔案非常簡單。這裡隻用了一些簡單的标簽,不過都是非常重要的。
<add>标簽中可以放置多個<doc>标簽(一個doc代表一個document),在大量資料裝載時這樣做能提高性能。
solr在每個post請求中都會收到一個<commit/>标簽。更多的一些特性會在之後介紹。
十一、一次簡單的搜尋。
在管理者界面,讓我們運作一次簡單的搜尋。
在管理者界面,點選查詢按鈕,或進入full interface再作更詳細的查詢。
在我們檢視xml輸出檔案之前,先看下url和參數資訊:
然後浏覽器中會顯示輸出的用xml辨別的搜尋結果,如下:
<?xml version="1.0" encoding="utf-8"?>
<response>
<lst name="responseheader">
<int name="status">0</int>
<int name="qtime">3</int><!--查詢耗時(毫秒)solr有一些緩存(儲存過去的搜尋結果),提高了搜尋效率-->
<lst name="params"><!--查詢的參數-->
<str name="indent">on</str><!--是否縮進xml檔案-->
<str name="rows">10</str><!--傳回的結果條數-->
<str name="start">0</str><!--搜尋結果的開始位置-->
<str name="q">monitor</str>
<str name="version">2.2</str><!--版本資訊-->
</lst>
</lst>
<!--numfound是找到幾條,start從第幾條開始顯示-->
<!--這裡并沒有顯示得分情況(非full interface),但結果其實已經按照得分排序了(solr預設)-->
<!--如果是full interface查詢,result會包括maxscore屬性,辨別最高得分-->
<result name="response" numfound="2" start="0">
<doc>
<!--如果是full interface查詢,這裡會有得分情況(預設)
<float name="score">0.5747526</float>
-->
<!--預設情況solr會列出所有存儲的fields
(不是所有field都需要存儲,雖然可能根據它來查索引,但不用包含在就結果中)
-->
<!--
注意,某些field是多值的,由arr标簽标記的
<arr name="cat"><str>electronics</str><str>monitor</str></arr>
<arr name="features"><str>30" tft active matrix lcd, 2560 x 1600,
.25mm dot pitch, 700:1 contrast</str></arr>
<str name="id">3007wfp</str>
<bool name="instock">true</bool>
<str name="includes">usb cable</str>
<str name="manu">dell, inc.</str>
<str name="name">dell widescreen ultrasharp 3007wfp</str>
<int name="popularity">6</int>
<float name="price">2199.0</float>
<str name="sku">3007wfp</str>
<arr name="spell"><str>dell widescreen ultrasharp 3007wfp</str>
</arr>
<date name="timestamp">2008-08-09t03:56:41.487z</date>
<float name="weight">401.6</float>
</doc>
...
</result>
</response>
這隻是一個簡單的查詢結果,可以加入例如高亮顯示等查詢條件,然後在result标記後會有更多資訊。
十二、一些統計資訊
在這裡,當我們沒有加載任何資料時,numdocs顯示0,而現在顯示19。
maxdocs的值取決于當你删除一個文檔但卻沒有送出。
可以關注以下的一些handler:
/update,standard。
注意:這些統計資訊都是實時的,不在磁盤上做儲存。
十三、solrconfig.xml
這裡包含很多我們可以研究的參數,現在先讓我們看下<requesthandler>下定義的 request handers。
<requesthandler name="standard" class="solr.searchhandler"
default="true">
<!-- default values for query parameters -->
<lst name="defaults">
<!--是否顯示參數,none(都不顯示),all(全顯示,可以看到一些隐藏參數)-->
<str name="echoparams">explicit</str>
<!--
<int name="rows">10</int>
<str name="fl">*</str>
<str name="version">2.1</str>
-->
</requesthandler>
當我們通過post通知solr(如索引一個文檔)或通過get搜尋,都會有個特定的request hander做處理。
這些handers可以通過url來注冊。之前我們加載文檔時,solr通過以下注冊的handler做處理:
<requesthandler name="/update" class="solr.xmlupdaterequesthandler" />
而當使用搜尋時,是使用solr.searchhandler(上面的xml定義了)
通過url參數或post中的參數,都可以調用這些request handler
也可以在solrconfig.xml中通過default,appends,invariants來指定。
這裡的一些參數等于是預設的,就像已經放在了url後面的參數一樣。
十四、一些重要的solr資源
十五、查詢參數
fl=*,score&q.op=and&start=0&rows=16&hl=true&hl.fl=merheading&hl.snippets=3&hl.simple.pre=<font color=red>&hl.simple.post=</font>&facet=true&facet.field=mercategory&q=+(merheading%3a%e4%bd%a0%e5%a5%bd+and+merheadingwithword%3a%e6%bd%98 ) +meractualendtime:[1239264030468 to 1240473630468]&sort=meractualendtime asc
fl表示索引顯示那些field(*表示所有field, score 是solr 的一個比對熱度)
q.op 表示q 中 查詢語句的 各條件的邏輯操作 and(與) or(或)
start 開始傳回條數
rows 傳回多少條
hl 是否高亮
hl.fl 高亮field
hl.snippets 不太清楚(反正是設定高亮3就可以了)
hl.simple.pre 高亮前面的格式
hl.simple.post 高亮後面的格式
facet 是否啟動統計
facet.field 統計field
q 查詢語句(類似sql) 相關詳細的操作還需lucene 的query 文法
sort 排序
十六、删除索引
post "<delete><id>42</id></delete>"
第二章
現在我們開始研究載入的資料部分(importing data)
這裡的資料都是免費的,一個大型開放社群提供。
musicbrainz每天都提供一個資料快照(snapshot)的sql檔案,這些資料可以被導入postgresql資料庫中。
一、字段配置(schema)
schema.xml位于solr/conf/目錄下,類似于資料表配置檔案,
定義了加入索引的資料的資料類型,主要包括type、fields和其他的一些預設設定。
1、先來看下type節點,這裡面定義fieldtype子節點,包括name,class,positionincrementgap等一些參數。
name:就是這個fieldtype的名稱。
class:指向org.apache.solr.analysis包裡面對應的class名稱,用來定義這個類型的行為。
<schema name="example" version="1.2">
<types>
<fieldtype name="string" class="solr.strfield" sortmissinglast="true" omitnorms="true"/>
<fieldtype name="boolean" class="solr.boolfield" sortmissinglast="true" omitnorms="true"/>
<fieldtype name="binary" class="solr.binaryfield"/>
<fieldtype name="int" class="solr.trieintfield" precisionstep="0" omitnorms="true"
positionincrementgap="0"/>
<fieldtype name="float" class="solr.triefloatfield" precisionstep="0" omitnorms="true"
<fieldtype name="long" class="solr.trielongfield" precisionstep="0" omitnorms="true"
<fieldtype name="double" class="solr.triedoublefield" precisionstep="0" omitnorms="true"
...
</types>
</schema>
必要的時候fieldtype還需要自己定義這個類型的資料在建立索引和進行查詢的時候要使用的分析器analyzer,包括分詞和過濾,如下:
<fieldtype name="text_ws" class="solr.textfield" positionincrementgap="100">
<analyzer>
<tokenizer class="solr.whitespacetokenizerfactory"/>
</analyzer>
</fieldtype>
<fieldtype name="text" class="solr.textfield" positionincrementgap="100">
<analyzer type="index">
<!--這個分詞包是空格分詞,在向索引庫添加text類型的索引時,solr會首先用空格進行分詞
然後把分詞結果依次使用指定的過濾器進行過濾,最後剩下的結果,才會加入到索引庫中以備查詢。
注意:solr的analysis包并沒有帶支援中文的包,需要自己添加中文分詞器,google下。
<!-- in this example, we will only use synonyms at query time
<filter class="solr.synonymfilterfactory" synonyms="index_synonyms.txt"
ignorecase="true" expand="false"/>
-->
<!-- case insensitive stop word removal.
add enablepositionincrements=true in both the index and query
analyzers to leave a 'gap' for more accurate phrase queries.
<filter class="solr.stopfilterfactory"
ignorecase="true"
words="stopwords.txt"
enablepositionincrements="true"
/>
<filter class="solr.worddelimiterfilterfactory" generatewordparts="1"
generatenumberparts="1" catenatewords="1" catenatenumbers="1"
catenateall="0" splitoncasechange="1"/>
<filter class="solr.lowercasefilterfactory"/>
<filter class="solr.snowballporterfilterfactory" language="english"
protected="protwords.txt"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.whitespacetokenizerfactory"/>
<filter class="solr.synonymfilterfactory" synonyms="synonyms.txt" ignorecase="true"
expand="true"/>
<filter class="solr.stopfilterfactory"
<filter class="solr.worddelimiterfilterfactory" generatewordparts="1"
generatenumberparts="1" catenatewords="0" catenatenumbers="0"
catenateall="0" splitoncasechange="1"/>
<filter class="solr.lowercasefilterfactory"/>
<filter class="solr.snowballporterfilterfactory" language="english"
protected="protwords.txt"/>
</analyzer>
2、再來看下fields節點内定義具體的字段(類似資料庫的字段),含有以下屬性:
name:字段名
type:之前定義過的各種fieldtype
indexed:是否被索引
stored:是否被存儲(如果不需要存儲相應字段值,盡量設為false)
multivalued:是否有多個值(對可能存在多值的字段盡量設定為true,避免建索引時抛出錯誤)
<fields>
<field name="id" type="integer" indexed="true" stored="true" required="true" />
<field name="name" type="text" indexed="true" stored="true" />
<field name="summary" type="text" indexed="true" stored="true" />
<field name="author" type="string" indexed="true" stored="true" />
<field name="date" type="date" indexed="false" stored="true" />
<field name="content" type="text" indexed="true" stored="false" />
<field name="keywords" type="keyword_text" indexed="true" stored="false" multivalued="true" />
<!--拷貝字段-->
<field name="all" type="text" indexed="true" stored="false" multivalued="true"/>
</fields>
3、建議建立一個拷貝字段,将所有的 全文本 字段複制到一個字段中,以便進行統一的檢索:
以下是拷貝設定:
<copyfield source="name" dest="all"/>
<copyfield source="summary" dest="all"/>
4、動态字段,沒有具體名稱的字段,用dynamicfield字段
如:name為*_i,定義它的type為int,那麼在使用這個字段的時候,任務以_i結果的字段都被認為符合這個定義。如name_i, school_i
<dynamicfield name="*_i" type="int" indexed="true" stored="true"/>
<dynamicfield name="*_s" type="string" indexed="true" stored="true"/>
<dynamicfield name="*_l" type="long" indexed="true" stored="true"/>
<dynamicfield name="*_t" type="text" indexed="true" stored="true"/>
<dynamicfield name="*_b" type="boolean" indexed="true" stored="true"/>
<dynamicfield name="*_f" type="float" indexed="true" stored="true"/>
<dynamicfield name="*_d" type="double" indexed="true" stored="true"/>
<dynamicfield name="*_dt" type="date" indexed="true" stored="true"/>
schema.xml文檔注釋中的資訊:
1、為了改進性能,可以采取以下幾種措施:
将所有隻用于搜尋的,而不需要作為結果的field(特别是一些比較大的field)的stored設定為false
将不需要被用于搜尋的,而隻是作為結果傳回的field的indexed設定為false
删除所有不必要的copyfield聲明
為了索引字段的最小化和搜尋的效率,将所有的 text fields的index都設定成field,然後使用copyfield将他們都複制到一個總的 text field上,然後對他進行搜尋。
為了最大化搜尋效率,使用java編寫的用戶端與solr互動(使用流通信)
在伺服器端運作jvm(省去網絡通信),使用盡可能高的log輸出等級,減少日志量。
2、<schema name="example" version="1.2">
name:辨別這個schema的名字
version:現在版本是1.2
3、filedtype
<fieldtype name="string" class="solr.strfield" sortmissinglast="true" omitnorms="true" />
name:辨別而已。
class和其他屬性決定了這個fieldtype的實際行為。(class以solr開始的,都是在org.appache.solr.analysis包下)
可選的屬性:
sortmissinglast和sortmissingfirst兩個屬性是用在可以内在使用string排序的類型上(包括:string,boolean,sint,slong,sfloat,sdouble,pdate)。
sortmissinglast="true",沒有該field的資料排在有該field的資料之後,而不管請求時的排序規則。
sortmissingfirst="true",跟上面倒過來呗。
2個值預設是設定成false
strfield類型不被分析,而是被逐字地索引/存儲。
strfield和textfield都有一個可選的屬性“compressthreshold”,保證壓縮到不小于一個大小(機關:char)
<fieldtype name="text" class="solr.textfield" positionincrementgap="100">
solr.textfield 允許使用者通過分析器來定制索引和查詢,分析器包括 一個分詞器(tokenizer)和多個過濾器(filter)
positionincrementgap:可選屬性,定義在同一個文檔中此類型資料的空白間隔,避免短語比對錯誤。
<tokenizer class="solr.whitespacetokenizerfactory" />
空格分詞,精确比對。
<filter class="solr.worddelimiterfilterfactory" generatewordparts="1" generatenumberparts="1" catenatewords="1" catenatenumbers="1"catenateall="0" splitoncasechange="1" />
在分詞和比對時,考慮 "-"連字元,字母數字的界限,非字母數字字元,這樣 "wifi"或"wi fi"都能比對"wi-fi"。
<filter class="solr.synonymfilterfactory" synonyms="synonyms.txt" ignorecase="true" expand="true" />
同義詞
<filter class="solr.stopfilterfactory" ignorecase="true" words="stopwords.txt" enablepositionincrements="true" />
在禁用字(stopword)删除後,在短語間增加間隔
stopword:即在建立索引過程中(建立索引和搜尋)被忽略的詞,比如is this等常用詞。在conf/stopwords.txt維護。
4、fields
<field name="id" type="string" indexed="true" stored="true" required="true" />
type:先前定義的類型。
indexed:是否被用來建立索引(關系到搜尋和排序)
stored:是否儲存
compressed:[false],是否使用gzip壓縮(隻有textfield和strfield可以壓縮)
mutivalued:是否包含多個值
omitnorms:是否忽略掉norm,可以節省記憶體空間,隻有全文本field和need an index-time boost的field需要norm。(具體沒看懂,注釋裡有沖突)
termvectors:[false],當設定true,會存儲 term vector。當使用morelikethis,用來作為相似詞的field應該存儲起來。
termpositions:存儲 term vector中的位址資訊,會消耗存儲開銷。
termoffsets:存儲 term vector 的偏移量,會消耗存儲開銷。
default:如果沒有屬性需要修改,就可以用這個辨別下。
<field name="text" type="text" indexed="true" stored="false" multivalued="true" />
包羅萬象(有點誇張)的field,包含所有可搜尋的text fields,通過copyfield實作。
<copyfield source="cat" dest="text" />
<copyfield source="name" dest="text" />
<copyfield source="manu" dest="text" />
<copyfield source="features" dest="text" />
<copyfield source="includes" dest="text" />
在添加索引時,将所有被拷貝field(如cat)中的資料拷貝到text field中
作用:
将多個field的資料放在一起同時搜尋,提供速度
将一個field的資料拷貝到另一個,可以用2種不同的方式來建立索引。
<dynamicfield name="*_i" type="int" indexed="true" stored="true" />
如果一個field的名字沒有比對到,那麼就會用動态field試圖比對定義的各種模式。
"*"隻能出現在模式的最前和最後
較長的模式會被先去做比對
如果2個模式同時比對上,最先定義的優先
<dynamicfield name="*" type="ignored" multivalued="true" />
如果通過上面的比對都沒找到,可以定義這個,然後定義個type,當string處理。(一般不會發生)
但若不定義,找不到比對會報錯。
5、其他一些标簽
<uniquekey>id</uniquekey>
文檔的唯一辨別, 必須填寫這個field(除非該field被标記required="false"),否則solr建立索引報錯。
<defaultsearchfield>text</defaultsearchfield>
如果搜尋參數中沒有指定具體的field,那麼這是預設的域。
<solrqueryparser defaultoperator="or" />
配置搜尋參數短語間的邏輯,可以是"and|or"。
二、solrconfig.xml
1、索引配置
mainindex 标記段定義了控制solr索引處理的一些因素.
usecompoundfile:通過将很多 lucene 内部檔案整合到單一一個檔案來減少使用中的檔案的數量。這可有助于減少 solr 使用的檔案句柄數目,代價是降低了性能。除非是應用程式用完了檔案句柄,否則 <code>false</code> 的預設值應該就已經足夠。
usecompoundfile:通過将很多lucene内部檔案整合到一個檔案,來減少使用中的檔案的數量。這可有助于減少solr使用的檔案句柄的數目,代價是降低了性能。除非是應用程式用完了檔案句柄,否則false的預設值應該就已經足夠了。
mergefacor:決定lucene段被合并的頻率。較小的值(最小為2)使用的記憶體較少但導緻的索引時間也更慢。較大的值可使索引時間變快但會犧牲較多的記憶體。(典型的 時間與空間 的平衡配置)
maxbuffereddocs:在合并記憶體中文檔和建立新段之前,定義所需索引的最小文檔數。段 是用來存儲索引資訊的lucene檔案。較大的值可使索引時間變快但會犧牲較多記憶體。
maxmergedocs:控制可由solr合并的 document 的最大數。較小的值(<10,000)最适合于具有大量更新的應用程式。
maxfieldlength:對于給定的document,控制可添加到field的最大條目數,進而階段該文檔。如果文檔可能會很大,就需要增加這個數值。然後,若将這個值設定得過高會導緻記憶體不足錯誤。
unlockonstartup:告知solr忽略在多線程環境中用來保護索引的鎖定機制。在某些情況下,索引可能會由于不正确的關機或其他錯誤而一直處于鎖定,這就妨礙了添加和更新。将其設定為true可以禁用啟動索引,進而允許進行添加和更新。(鎖機制)
2、查詢處理配置
query标記段中以下一些與緩存無關的特性:
maxbooleanclauses:定義可組合在一起形成以個查詢的字句數量的上限。正常情況1024已經足夠。如果應用程式大量使用了通配符或範圍查詢,增加這個限制将能避免當值超出時,抛出toomangclausesexception。
enablelazyfieldloading:如果應用程式隻會檢索document上少數幾個field,那麼可以将這個屬性設定為true。懶散加載的一個常見場景大都發生在應用程式傳回一些列搜尋結果的時候,使用者常常會單擊其中的一個來檢視存儲在此索引中的原始文檔。初始的現實常常隻需要現實很短的一段資訊。若是檢索大型的document,除非必需,否則就應該避免加載整個文檔。
query部分負責定義與在solr中發生的時間相關的幾個選項:
概念:solr(實際上是lucene)使用稱為searcher的java類來處理query執行個體。searcher将索引内容相關的資料加載到記憶體中。根據索引、cpu已經可用記憶體的大小,這個過程可能需要較長的一段時間。要改進這一設計和顯著提高性能,solr引入了一張“溫暖”政策,即把這些新的searcher聯機以便為現場使用者提供查詢服務之前,先對它們進行“熱身”。
newsearcher和firstsearcher事件,可以使用這些事件來制定執行個體化新searcher或第一個searcher時,應該執行哪些查詢。如果應用程式期望請求某些特定的查詢,那麼在建立新searcher或第一個searcher時就應該反注釋這些部分并執行适當的查詢。
query中的智能緩存:
filtercache:通過存儲一個比對給定查詢的文檔 id 的無序集,過濾器讓 solr 能夠有效提高查詢的性能。緩存這些過濾器意味着對solr的重複調用可以導緻結果集的快速查找。更常見的場景是緩存一個過濾器,然後再發起後續的精煉查詢,這種查詢能使用過濾器來限制要搜尋的文檔數。
queryresultcache:為查詢、排序條件和所請求文檔的數量緩存文檔 id 的有序集合。
documentcache:緩存lucene document,使用内部lucene文檔id(以便不與solr唯一id相混淆)。由于lucene的内部document id 可以因索引操作而更改,這種緩存不能自熱。
named caches:命名緩存是使用者定義的緩存,可被 solr定制插件 所使用。
其中filtercache、queryresultcache、named caches(如果實作了org.apache.solr.search.cacheregenerator)可以自熱。
每個緩存聲明都接受最多四個屬性:
class:是緩存實作的java名
size:是最大的條目數
initialsize:是緩存的初始大小
autowarmcount:是取自舊緩存以預熱新緩存的條目數。如果條目很多,就意味着緩存的hit會更多,隻不過需要花更長的預熱時間。
對于所有緩存模式而言,在設定緩存參數時,都有必要在記憶體、cpu和磁盤通路之間進行均衡。統計資訊管理頁(管理者界面的statistics)對于分析緩存的 hit-to-miss 比例以及微調緩存大小的統計資料都非常有用。而且,并非所有應用程式都會從緩存受益。實際上,一些應用程式反而會由于需要将某個永遠也用不到的條目存儲在緩存中這一額外步驟而受到影響。
第三章
一、在tomcat中安裝運作solr
下載下傳solr包,找到dist檔案夾中的appache-solr-1.4.0.war。将它拷貝到tomcat的webapps下,改名為solr.war(之後通路的路徑為/solr)。
在webapp下建立同war包名一樣的檔案夾(這裡就是solr),将example/solr下的所有檔案拷貝到這個目錄下(這裡是一些樣例的配置)
在tomcat的conf/catalina/localhost檔案夾下面建立solr.xml,設定solr的根目錄。
<!--其中的路徑都是相對于tomcat的bin目錄-->
<context docbase="../webapps/solr.war" debug="0" crosscontext="true" >
<environment name="solr/home" type="java.lang.string"
value="../webapps/solr" override="true" />
</context>
二、運作多個solr
1、在/webapps/solr下建立solr.xml
<?xml version="1.0" encoding="utf-8" ?>
<solr persistent="false">
<cores adminpath="/admin/cores">
<core name="core0" instancedir="core0" />
<core name="core1" instancedir="core1" />
</cores>
</solr>
2、在/webapps/solr下,建立對應的core0,core1檔案夾。
拷貝conf(示例的配置檔案,正常産品中自己配置schema.xml等)到core0和core1中。
預設情況下索引檔案将儲存在同一個目錄中(各自根目錄的data中),也可以配置:
<core name="core0" instancedir="core0" >
<property name="datadir" value="/data/core0"/>
</core>