一、字段配置(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"
positionIncrementGap="0"/>
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" omitNorms="true"
positionIncrementGap="0"/>
<fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" omitNorms="true"
positionIncrementGap="0"/>
...
</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下。
-->
<tokenizer class="solr.WhitespaceTokenizerFactory"/>
<!-- 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"
ignoreCase="true"
words="stopwords.txt"
enablePositionIncrements="true"
/>
<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>
</fieldType>
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名字
<schema name="example" version="1.2">
- name:標識這個schema的名字
- version:現在版本是1.2
3、filedType
<fieldTypename="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:可選屬性,定義在同一個文檔中此類型數據的空白間隔,避免短語匹配錯誤。
<tokenizerclass="solr.WhitespaceTokenizerFactory" />
空格分詞,精確匹配。
<filterclass="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1" />
在分詞和匹配時,考慮 "-"連字符,字母數字的界限,非字母數字字符,這樣 "wifi"或"wi fi"都能匹配"Wi-Fi"。
<filterclass="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true" />
同義詞
<filterclass="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true" />
在禁用字(stopword)刪除後,在短語間增加間隔
stopword:即在建立索引過程中(建立索引和搜索)被忽略的詞,比如is this等常用詞。在conf/stopwords.txt維護。
4、fields
<fieldname="id" type="string" indexed="true" stored="true" required="true" />
- name:標識而已。
- 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:如果沒有屬性需要修改,就可以用這個標識下。
<fieldname="text" type="text" indexed="true" stored="false" multiValued="true" />
包羅萬象(有點誇張)的field,包含所有可搜索的text fields,通過copyField實現。
<copyFieldsource="cat" dest="text" />
在添加索引時,將所有被拷貝field(如cat)中的數據拷貝到text field中
作用:
- 將多個field的數據放在一起同時搜索,提供速度
- 將一個field的數據拷貝到另一個,可以用2種不同的方式來建立索引。
<dynamicFieldname="*_i" type="int" indexed="true" stored="true" />
如果一個field的名字沒有匹配到,那麼就會用動態field試圖匹配定義的各種模式。
- "*"只能出現在模式的最前和最後
- 較長的模式會被先去做匹配
- 如果2個模式同時匹配上,最先定義的優先
<dynamicFieldname="*" type="ignored" multiValued="true" />
如果通過上面的匹配都沒找到,可以定義這個,然後定義個type,當String處理。(一般不會發生)
但若不定義,找不到匹配會報錯。
5、其他一些標籤
<uniqueKey>id</uniqueKey>
文檔的唯一標識, 必須填寫這個field(除非該field被標記required="false"),否則solr建立索引報錯。
<defaultSearchField>text</defaultSearchField>
如果搜索參數中沒有指定具體的field,那麼這是默認的域。
<solrQueryParserdefaultOperator="OR" />
配置搜索參數短語間的邏輯,可以是"AND|OR"。
三、solrconfig.xml
1、索引配置
mainIndex 標記段定義了控制Solr索引處理的一些因素.
-
useCompoundFile:通過將很多 Lucene 內部文件整合到單一一個文件來減少使用中的文件的數量。這可有助於減少 Solr 使用的文件句柄數目,代價是降低了性能。除非是應用程序用完了文件句柄,否則
false
的默認值應該就已經足夠。 - 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 比例以及微調緩存大小的統計數據都非常有用。而且,並非所有應用程序都會從緩存受益。實際上,一些應用程序反而會由於需要將某個永遠也用不到的條目存儲在緩存中這一額外步驟而受到影響。