Solr 03 - 解讀Solr的schema.xml文件 (Solr的模式設計與優化)

1 關於schema.xml文件

Solr將數據以結構化的形式存儲到文件系統中, 在存儲的過程當中對數據創建索引 —— 經過模式文件schema.xml文件來定義這個結構.apache

schema.xml文件位於Solr安裝包的 example/solr/collection1/conf/目錄下, 主要用於配置Solr的域(Field)以及域的類型(FieldType).服務器

說明事項:併發

Solr中Field相關內容要先配置再使用;dom

schema.xml文件的名稱不能夠更改;性能

在使用中也應該位於SolrHome/conf/ 下 或者位於 Solr Web 應用的類加載器能夠加載到的位置.優化

這裏演示的schema.xml文件是Solr 4.10.4版本中的模式文件.ui

2 解讀schema.xml文件

文件示例:this

<?xml version="1.0" encoding="UTF-8" ?>
<schema name="user" version="1.5">
   <field name="_version_" type="long" indexed="true" stored="true"/>
   <field name="_root_" type="string" indexed="true" stored="false"/>
   <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
   <field name="name" type="text_general" indexed="true" stored="true"/>
   <uniqueKey>id</uniqueKey>

   <fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
   <fieldType name="string" class="solr.StrField" sortMissingLast="true" />
   <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100">
      <analyzer type="index">
        <tokenizer class="solr.StandardTokenizerFactory"/>
      </analyzer>
      <analyzer type="query">
        <tokenizer class="solr.StandardTokenizerFactory"/>
      </analyzer>
    </fieldType>
</schema>

(1) 根元素是schema, name屬性值用來展現, 能夠任意配置, version是Solr模式語法和語義的版本號, Solr 4.10版本中使用1.5版本.編碼

1.0版本: multiValued屬性不存在, 全部字段本質上都是多值的;
1.1版本: 引入了multiValued屬性, 默認爲false;
1.2版本: 引入了omitTermFreqAndPositions屬性, 默認爲true, 文本字段除外;
1.3版本: 刪除了可選的字段壓縮功能;
1.4版本: autoGeneratePhraseQueries屬性, 用於在單個字符串生成多個標記時驅動QueryParser行爲. 1.4及以上的版本默認關閉;
1.5版本: 對於原始字段類型(如int, float, boolean, string...), omitNorms默認爲true.

(2)根元素下主要有field和fieldType兩個標籤, 分別用來定義域和域的類型.

2.1 field - 配置域

<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />

field 相似於MySQL中數據表的字段, 屬性包括name, type(就是以前定義過的fieldType)等等, 具體屬性說明以下:

(1)必需屬性:

name: 域的名稱, 以字母或下劃線開頭, 不能由數字開頭;
type: 下面將定義的fieldType域的類型;
indexed: 若是此字段須要被檢索和排序, 就設置爲true;
stored: 若是這個字段在查詢的時候須要顯示出來, 就要設置爲true, 表示存儲它的原始值, 若是在檢索的時候不須要顯示原始值, 就儘可能設置爲false, 尤爲是值比較大的字段;
required: 代表該字段是必填字段, 相似於MySQL中的not null. 若設置爲true, 在建立索引時, 就必須包含該字段的值, 如過不存在, 就會拋出錯誤;
multiValued: 是否有多個值(在Solr中容許一個域保存多個值, 相似於MySQL中一個用戶能夠存儲多個好友, 一件商品有多個細節圖片).

原配置文件中的英文說明:

Although it would make indexing slightly slower and the index bigger, it would also make the index faster to load, more memory-efficient and more NRT-friendly.
大概意思是: 雖然它會使索引略微變慢、索引文件變得更大, 但它卻能使得索引更快被加載, 內存使用效率更高, 而且更友好的NRT(近實時搜索).

(2)可選屬性:

docValues: 是否爲當前field添加一個名爲docValues的field --- 這對facet查詢、group分組、排序、function查詢有好處.

a) 不足: 會使得索引過程略慢, 且索引文件更大;

b) 優勢: 能加快索引數據的加載, 對NRT(近實時搜索)也更加友好, 並且更節省內存;

c) 限制: 目前docValues只支持strField、UUIDField、Trie*Field; 要求字段的值是單值, 而且此field的值必須存在或具備默認值.

compressed: 是否使用gzip壓縮(只有TextField和StrField能夠壓縮), 默認爲false;

omitNorms(專業屬性): 是否忽略掉Norm, 若是設置爲true, 將忽略與此字段相關聯的規範 (這將禁用字段的長度規範化和檢索時文檔權重分的提高, 並節省一些內存空間). 只有全文本的field和須要檢索時提高權重的field須要norm; 只有全文本類型的字段, 或者須要在檢索時對當前字段的權重進行設置時, 才須要相關規範, 此時須要將其設置爲false. 默認狀況下, 原始(未分析)類型的規範將被忽略.

termVectors: 默認false, 爲true時會存儲當前字段的term vector(術語向量), 使用MoreLikeThis時, 用來做爲類似性匹配的field的stored應該設置爲true, 以提升性能;

termPositions: 使用term vector存儲位置信息, 這會增大存儲成本;

termOffsets: 使用term vector存儲偏移量信息, 這會增大存儲成本;

default: 設置當前字段的默認值, 若是在添加文檔時沒有爲該字段指定值, 將使用此默認值.

(3)注意事項:

name="_version_" 的字段必須添加, 用來記錄Solr中文檔的版本. 若是刪除此字段, 則必須禁用solrconfig.xml文件中的更新日誌, 不然Solr將沒法啓動. SolrCloud須要_version_和更新日誌.

name="_root_" 的字段用來指向嵌套文檔塊的根文檔, 有嵌套文檔時就必需存在此字段, 不然嵌套文檔可能會被刪除.

③ 幾乎全部的Solr文檔中都存在<uniqueKey>id</uniqueKey> —— 主鍵爲id, 若是沒有充分的理由, 請不要刪除id字段. ⇒ 固然能夠根據實際狀況配置符合自身業務的主鍵.

2.2 fieldType - 配置域類型

fieldType供Solr內部使用, 不支持自定義域類型. 原始FieldType定義示例:

<fieldType name="text_general" class="solr.TextField" positionIncrementGap="100">
    <analyzer type="index">
        <tokenizer class="solr.StandardTokenizerFactory" />
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
        <!-- in this example, we will only use synonyms at query time <filter class="solr.SynonymFilterFactory" 
             synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/> -->
        <filter class="solr.LowerCaseFilterFactory" />
    </analyzer>
    
    <analyzer type="query">
        <tokenizer class="solr.StandardTokenizerFactory" />
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
        <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true" />
        <filter class="solr.LowerCaseFilterFactory" />
    </analyzer>
</fieldType>

(1)必需屬性:

name: 域類型的名稱, 是field中的type;
class: 域類型對應的Solr的標準Java類, 以"Solr"開頭的class是org.apache.solr.analysis包中的Java類;
③ analyzer: 定義索引和搜索使用的分詞器, **是核心配置 --- 使用的分析器不一樣, 索引和檢索也將不一樣**; ④type: index(索引流程)和query(檢索流程); ⑤tokenizer: 指定具體使用的分詞器; ⑥filter`: 指定使用的過濾器;

(2)可選屬性:

positionIncrementGap: 當multiValued="true" 時使用, 定義在同一個文檔中此類型數據的空白間隔, 即設置多個值之間的虛擬空白的數量, 避免短語匹配錯誤.

autoGeneratePhraseQueries: 有點相似找近義詞或者自動糾錯, 例如能夠將 "wi fi" 自動轉爲 "wifi" 或 "wi-fi", 若是不設置這個屬性則須要在查詢時強制加上引號, 如 'wi fi';

sortMissingLast / sortMissingFirst: 對查詢結果進行排序的過程當中, 若是發現這個字段的值不存在, 就排在前面/後面, 忽略排序的條件. 使用方式以下:

a) 默認值均爲false, 將使用Lucene內部的排序規則: 將沒有該字段的文檔放在升序中, 最後放在降序結果中. ;

b) sortMissingLast="true", 對該字段進行排序時, 沒有該字段的文檔將排在有該字段的文檔的後面, 忽略請求時的排序規則(asc或desc);

c) sortMissingFirst="true", 與sortMissingLast做用相反.

(3)常見域類型(class):

solr.StrField:

<fieldType name="string" class="solr.StrField" sortMissingLast="true" />

此類型不會被分詞, 而是被逐字索引/存儲. 它支持docValues域, 若是使用此fieldType的field添加了docValues字段, 則要求該field只能是單值域且該域必須存在或者該域有默認值.

solr.BoolField:

<fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/>

boolean域, 對應true/false.

solr.Trie*Field: 默認的數字域類型:

<fieldType name="int" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="float" class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="long" class="solr.TrieLongField" precisionStep="0" positionIncrementGap="0"/>
<fieldType name="double" class="solr.TrieDoubleField" precisionStep="0" positionIncrementGap="0"/>

這些字段支持docValues, 但它們要求field爲單值, 而且要麼是必需的, 要麼具備默認值.

solr.Trie*Field: 更快的範圍查詢的數字域類型:

若是須要更快的範圍查詢, 請考慮 tint / tfloat / tlong / tdouble 類型:

<fieldType name="tint" class="solr.TrieIntField" precisionStep="8" positionIncrementGap="0"/>
<fieldType name="tfloat" class="solr.TrieFloatField" precisionStep="8" positionIncrementGap="0"/>
<fieldType name="tlong" class="solr.TrieLongField" precisionStep="8" positionIncrementGap="0"/>
<fieldType name="tdouble" class="solr.TrieDoubleField" precisionStep="8" positionIncrementGap="0"/>

此類型 以多種精度級別對每一個值建立不一樣的索引 , 用來加速範圍兩端間距較大時的範圍查詢.

precisionStep: 通常用於數字範圍查詢, 其值越小(以位爲單位), 索引時該域的值分出的token個數越多 ⇒ 索引體積會稍大(slightly larger index size) ⇒ 但這能加快數字範圍檢索的響應速度.

precisionStep="0"將禁用不一樣精度級別的索引.

positionIncrementGap: 若是當前域是多值域時, 多個值之間的間距. 該屬性在單值域上無心義.

solr.TrieDateField: 日期域類型:

<fieldType name="date" class="solr.TrieDateField" precisionStep="0" positionIncrementGap="0"/>

日期字段只支持格式爲1995-12-31T23:59:59Z的日期, 最後的 Z 表示UTC時間, 而且必須是UTC時間.
其中, 只有秒數能夠選用小數: 1995-12-31T23:59:59.999Z, 其餘部分都是必需且格式不能改變的.

日期表達式也可用於表示相對於"NOW"(當前時刻)的時間, 如:

NOW/HOUR ⇒ 回到當前小時的開始時間;
NOW-1DAY ⇒ 剛好在前一天;
NOW/DAY+6MONTHS+3DAYS ⇒ 從當天開始, 未來6個月零3天的時刻.

注意: 對於更快的範圍的查詢和日期分面的需求, 請考慮使用tdate類型.

<fieldType name="tdate" class="solr.TrieDateField" precisionStep="6" positionIncrementGap="0"/>

solr.BinaryField:

<fieldtype name="binary" class="solr.BinaryField"/>

通過Base64編碼的字符串域類型, 就是說須要把數據進行Base64編碼, 而後再發送/檢索.

solr.RandomSortField:

<fieldType name="random" class="solr.RandomSortField" indexed="true" />

隨機排序域類型, 不用於存儲或搜索任何數據, 能夠在模式中聲明此類型的字段, 以實現文檔的僞隨機排序.

⇒ 根據字段名稱和索引的版本生成排序. 只要索引的版本_version_不變, 而且重用相同的字段名稱, 文檔的順序就會一致.
⇒ 若是須要不一樣的僞隨機文檔排序, 對於相同版本的索引, 請使用dynamicField並更改請求中的字段名稱.

solr.TextField:

使用最多的一種域類型, 須要分詞, 通常須要用戶配置分析器來定製索引和查詢, 分析器包括一個分詞器(tokenizer)和多個過濾器(filter). 示例:

<!-- 空格分詞器, 精確匹配: 
     在向索引庫添加text類型的索引時, Solr會首先用空格進行分詞, 
     而後把分詞結果依次使用指定的過濾器進行過濾, 
     最後剩下的結果纔會加入到索引庫中以備查詢. 
     注意: Solr的analysis包並無支持中文的包, 須要本身添加中文分詞器.
-->
<fieldType name="text_ws" class="solr.TextField" positionIncrementGap="100">
   <analyzer>
      <tokenizer class="solr.WhitespaceTokenizerFactory" />
   </analyzer>
</fieldType>

(4)常見的過濾器(filter):

① 分隔符過濾器:

<!-- 在分詞和匹配時, 考慮 "-"連字符, 字母數字的界限, 非字母數字字符, 
     這樣"wifi"或"wi fi"都能匹配"Wi-Fi". 
-->
<filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" 
        generateNumberParts="1" catenateWords="1" catenateNumbers="1" 
        catenateAll="0" splitOnCaseChange="1" />

② 同義詞過濾器:

<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" 
        ignoreCase="true" expand="true" />

③ 停詞(禁用詞)過濾器:

<!-- 在禁用字(stopword)刪除後, 在短語間增長間隔stopword: 
      即在創建索引過程當中(創建索引和搜索)被忽略的詞, 好比is this等經常使用詞. 
      在conf/stopwords.txt文件中設置維護. 
-->
<filter class="solr.StopFilterFactory" ignoreCase="true" 
        words="stopwords.txt" enablePositionIncrements="true" />

2.3 copyField - 配置複製域

Solr容許將多個域的值, 複製給一個域, 目的是方便搜索.

好比: 搜索含有"Solr"的文檔, 須要把標題、摘要信息、正文中含有"Solr"的文檔都查詢出來, 有了copyField域, 就只須要搜索copyField域, 而不須要寫全標題、摘要信息、正文三個域的值.

在建立索引的時候, Solr會將源域的內容, 複製給目標域.

<copyField source="cat" dest="text"/>

(1)屬性說明:

source: 源域的名稱;
dest: 目標域的名稱, 搜索時指定目標域爲默認搜索域, 可提升查詢效率.

(2)使用注意事項:

目標域的定義, 必需要指定multiValued="true".
② 只複製單個域, 若是被複制域自己就是多值域, 那麼目標域也是多值域 ⇒ 無實際意義;
③ 若複製多個域, 只要其中有一個域是多值域, 那麼目標域就必定是多值域.

2.4 dynamicField - 配置動態域

動態域經過通配符, 實現了域的模糊匹配, 可以有效避免頻繁地修改schema.xml文件.
⇒ 修改schema.xml文件後, Solr程序須要從新加載配置文件, 較爲繁瑣.

dynamicField(動態域) 和 copyField (複製域)是Solr擴展的域, 在Lucene中沒有與之相關的概念.

<dynamicField name="*_i" type="int" indexed="true" stored="true"/>

(1)屬性說明:

name: 動態域的名稱, 是一個表達式:

a) *表示匹配任意字符, 只能出如今模式的最前或最後;

b) 較長的模式會先作匹配;

c) 若是2個模式同時匹配上, 最早定義的優先匹配.

(2)使用說明:

使用時, 只須要域的名稱與表達式匹配便可. 如 "product_i":"筆記本" , 直接使用product_i就能夠, 不須要再作其餘定義.
若是經過上面的匹配都沒找到, 能夠設置下述類型的配置, 而後定義一個type看成String處理. 通常不會發生, 但若不定義, 找不到匹配就會報錯.

<dynamicField name="*_i" type="ignored" multiValued="true"/>

2.5 uniqueKey - 配置惟一標識

Solr經過uniqueKey來指定文檔的主鍵, 默認的, id域被做爲主鍵, 所以id域是必須的.

⇒ 固然用戶能夠自定義主鍵.

<uniqueKey>id</uniqueKey>

Solr中被標記爲required="true"的字段, 必需要由<uniqueKey>做惟一標識, 不然創建索引時將報錯.

Solr將根據<uniqueKey>標識的field (默認就是id) 來決定增量導入時是否重複導入: 若是id相同, 就不會重複導入;

2.6 其餘配置說明

(1) 默認搜索域:

<defaultSearchField>text</defaultSearchField>

若是搜索參數中沒有指定具體的field, 這將做爲默認的域進行搜索.

Solr 6.x版本中已經移除了此參數.

(2) Solr查詢解析器:

<!-- 從Solr 6.6版本開始, 再也不支持defaultOperator -->
<solrQueryParser defaultOperator="OR"/>

配置搜索參數短語間的邏輯, 能夠是AND|OR.

3 關於schema.xml的優化

3.1 field的配置技巧

(1) 將全部只用於搜索、而不須要做爲結果返回原始值的field(特別是比較大的field)設置爲 stored="false";

(2) 將不須要被用於搜索、而只是做爲結果返回的field設置爲 indexed="false";

(3) 刪除全部沒必要要的copyField;

(4) 爲了最小化索引字段、提升搜索效率, 將爲全部的text field 都設置 index="false", 而後使用copyField將它們都複製到一個總的text field上, 對該text field進行搜索;

(5) 爲了最大化搜索性能, 使用ConcurrentUpdateSolrServer Java客戶端與Solr交互(使用併發修改服務);

(6) 在服務器端運行JVM, 即設置使用-server服務端模式, 性能更好; 並使用盡量高級別的Log輸出等級, 避免記錄每一個請求, 減小日誌量.

3.2 field的配置示例

分詞 搜索 存儲 示例
網頁的標題、內容
X 網頁的發佈時間
X X 引用的圖片位置
網頁標題、內容

不存在不須要索引、不須要分詞、也不須要存儲的字段, 由於這樣的字段在Lucene中無心義.

參考資料

Solr:Schema設計
Solr Wiki - SchemaXml

版權聲明

做者: 馬瘦風(https://healchow.com)

出處: 博客園 馬瘦風的博客(https://www.cnblogs.com/shoufeng)

感謝閱讀, 若是文章有幫助或啓發到你, 點個[好文要頂👆] 或 [推薦👍] 吧😜

本文版權歸博主全部, 歡迎轉載, 但 [必須在文章頁面明顯位置標明原文連接], 不然博主保留追究相關人員法律責任的權利.

相關文章
相關標籤/搜索