schema.xml用來定義文檔的結(jié)構(gòu)。一個(gè)文檔有一個(gè)或多個(gè)域組成,而域又需要由不同的域類型進(jìn)行定義。并且在創(chuàng)建索引的過程中,solr又需要對(duì)域進(jìn)行分詞。以下講一一對(duì)以上內(nèi)容進(jìn)行說明。schema還分為三種:手動(dòng)模式,自動(dòng)模式和無schema模式。
域類型
域類型定義了應(yīng)該如何從域中解析數(shù)據(jù)以及域是怎樣被查詢的。
- name: 域類型的名稱,強(qiáng)制性必須指定的,且必需保證同一個(gè)schema文件內(nèi)唯一性;
- class:域類型對(duì)應(yīng)的Java類,強(qiáng)制性必須指定的,如果是solr內(nèi)置的域類型,使用solr.類名方式指定即可,如果是自定義的域類型,必須指定類的完整路徑;
- positionIncrementGap: 配置多值之間的間隙,用于組織偽短語匹配,此配置適用于多值域;
- autoGeneratePhraseQueries:若設(shè)置為true,solr會(huì)自動(dòng)為相鄰的term生成短語查詢,若設(shè)置false,term必須被一對(duì)雙引號(hào)包裹才能被認(rèn)為是一個(gè)短語查詢,此設(shè)置針對(duì)TextField;
- docValuesFormat:配置DocValuesFormat實(shí)現(xiàn),這個(gè)配置需要提前在solrconfig.xml中配置SchemaCodecFactory;
- postingsFormat:postingFormat表示用于編/解碼term,postings,數(shù)據(jù)的實(shí)現(xiàn)類,這個(gè)配置需要提前在solrconfig.xml中配置SchemaCodecFactory;
- 配置域類型為TextField,則還需要配置<analyzer>元素來指定分詞器;
- 域類型屬性依賴于具體實(shí)現(xiàn)類;
<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>
Solr內(nèi)置預(yù)定義域類型
- BinaryField:表示經(jīng)過base64編碼的字符串域類型,你需要吧binary數(shù)據(jù)進(jìn)行base64編碼才能被solr進(jìn)行索引;
- BoolField:表示boolean類型的數(shù)據(jù),除了true,false,第一個(gè)字符是“1”,“t”,“T”也會(huì)被認(rèn)為true;
- CollationField:支持Unicode排序規(guī)則進(jìn)行排序和區(qū)間范圍查詢,當(dāng)你使用ICU4J時(shí),選擇使用ICUCollationField是更好的選擇;
- CurrencyField:支持貨幣以及貨幣兌換和貨幣匯率換算;
- DateRangeField:支持對(duì)日期范圍進(jìn)行索引,從而支持日期范圍查詢;
- ExternalFileField:對(duì)外部文件進(jìn)行索引的域類型,他支持從外部硬盤上讀取指定文件的內(nèi)容創(chuàng)建索引;
- EnumField:對(duì)枚舉進(jìn)行索引的域類型;
- ICUCollationField:支持Unicode排序規(guī)則進(jìn)行排序和區(qū)間范圍查詢;
- LatLonType:用于對(duì)經(jīng)緯度數(shù)據(jù)進(jìn)行索引,經(jīng)緯度數(shù)據(jù)格式必須為latitude,longitude,緯度在前,經(jīng)度在后,兩者之間用逗號(hào)隔開,且兩者之間不能有空格等其他字符,且不支持多值。適用于solr中spatial search(空間查詢);
- PointType:支持對(duì)N個(gè)緯度的坐標(biāo)定數(shù)據(jù)的索引,比如數(shù)學(xué)里的二維坐標(biāo)x,y,甚至立體幾何的三位坐標(biāo)x,y,z,但不支持多值;
- PreAnalyzedField:即預(yù)分詞域,他提供一個(gè)序列化的token stream傳遞給solr,這樣solr 在對(duì)PreAnalyzed-Field創(chuàng)建索引時(shí)不需要進(jìn)行分詞了,因?yàn)槿绾畏衷~處理已經(jīng)提前在序列化的token stream中定義好了;
- RandomSortField:這個(gè)域類型不包含域值,他用于查詢時(shí),根據(jù)RandomSortField排序時(shí),將會(huì)對(duì)返回結(jié)果進(jìn)行隨機(jī)排序,一般與dynamicField搭配使用;
- SpatialRecursivePrefixTreeFieldType:用于深度便利前綴樹的FieldType,主要用于獲取lucene中的RecursivePrefixTreeStrategy。這個(gè)域用于solr中的Spatial Search(空間查詢);
- StrField:對(duì)UTF-8編碼的字符串或者Unicode字符進(jìn)行索引,StrField不會(huì)分詞,且StrField有個(gè)硬性限制,字符大小必須小于32KB。他支持docValues域,但當(dāng)為其添加了docValues域,則要求只能是單值域且該域必須存在或者該域有默認(rèn)值;
- TextField:用于對(duì)長文本進(jìn)行索引,域StrField最大區(qū)別是,TextField會(huì)分詞且無長度限制;
- TrieDateField:Date域類型,表示一個(gè)毫秒精度對(duì)時(shí)間點(diǎn),啟用precisionStep=“0”會(huì)提升Date域?qū)ε判蛐阅懿⒆畲笙薅鹊臏p少索引大小,配置precisionStep=“8”會(huì)提升Date域的范圍區(qū)間查詢性能;
- DateRangeField:用于對(duì)日期范圍進(jìn)行索引,并且兼容TrieDateField;
- TrieDoubleField:Double域類型,precisionStep=“0”會(huì)提升Double域的排序性能并最大限度減少索引大小,配置precisionStep=”8“會(huì)提升Double域的范圍查詢性能;
- TrieFloatField:Float域類型,同TrieDoubleField類似;
- TrieIntField:Integer域類型,同TrieDoubleField類似;
- TrieLongField:Long域類型,同TrieLongField類似;
- TrieField:如果你使用這個(gè)域,那么還需要指定一個(gè)type屬性,他的可選值為integer,long,float,double,date。使用這個(gè)域跟使用TrieXXXField是一樣的;
- UUIDField:UUID域,如果域值為空字符串,或者null或者字符串“NEW”,那么solr會(huì)自動(dòng)生成UUID字符串并創(chuàng)建索引,如果用戶設(shè)置了域值,那么solr會(huì)首先檢查域是否符合UUID規(guī)范,如果不符合,會(huì)拋出異常,否則會(huì)將域值轉(zhuǎn)換為小寫形式,最后穿件索引。在solrcloud環(huán)境下,配置一個(gè)UUIDField并且指定域值為“NEW”是不建議的,此時(shí)建議是用UUIDUpdateProcessorFactory來代替;
幾個(gè)重點(diǎn)域類型講解
- CurrencyField:
提供對(duì)貨幣值的支持,solr可以在查詢時(shí)使用他完成貨幣的兌換和貨幣匯率換算,該域支持以下功能:
- 區(qū)間范圍查詢
- Function區(qū)間范圍查詢
- 排序
- 貨幣代號(hào)以及貨幣符號(hào)(比如美元的$,人民幣的¥)的解析
- 支持對(duì)稱和非對(duì)稱匯率
配置案例1:通過FileExchangeRateProvider加載currencyConfig.xml配置文件
schema.xml配置
<fieldType name="currency" class="solr.CurrencyField" precisionStep="8" defaultCurrency="USD" currencyConfig="currency.xml" />
currency.xml內(nèi)容
<currencyConfig version="1.0">
<rates>
<!-- Updated from http://www.exchangerate.com/ at 2011-09-27 -->
<rate from="USD" to="ARS" rate="4.333871" comment="ARGENTINA Peso" />
<rate from="USD" to="AUD" rate="1.025768" comment="AUSTRALIA Dollar" />
<rate from="USD" to="EUR" rate="0.743676" comment="European Euro" />
<rate from="USD" to="BRL" rate="1.881093" comment="BRAZIL Real" />
<rate from="USD" to="CAD" rate="1.030815" comment="CANADA Dollar" />
<rate from="USD" to="CLP" rate="519.0996" comment="CHILE Peso" />
<rate from="USD" to="CNY" rate="6.387310" comment="CHINA Yuan" />
<rate from="USD" to="CZK" rate="18.47134" comment="CZECH REP. Koruna" />
<rate from="USD" to="DKK" rate="5.515436" comment="DENMARK Krone" />
<rate from="USD" to="HKD" rate="7.801922" comment="HONG KONG Dollar" />
<rate from="USD" to="HUF" rate="215.6169" comment="HUNGARY Forint" />
<rate from="USD" to="ISK" rate="118.1280" comment="ICELAND Krona" />
...
</rates>
</currencyConfig>
配置案例2:通過OpenExchangeRatesOrgProvider調(diào)用遠(yuǎn)程接口獲取匯率數(shù)據(jù)
<fieldType name="currency" class="solr.CurrencyField" precisionStep="8" providerClass="solr.OpenExchangeRatesOrgProvider" refreshInterval="60" ratesFieldLocation="http://www.openexchangerates.org/api/latest.json?appid=your-personalAppIdKey"/>
- providerClass:表示provider實(shí)現(xiàn)類,內(nèi)置的provider只需以solr.開頭來代替默認(rèn)包名即可,如果自定義實(shí)現(xiàn)的provider類,則需要指定完整包路徑;
- refreshInterval:表示每間隔多少分鐘在重新從遠(yuǎn)程接口獲取一次匯率數(shù)據(jù);
- ratesFileLocation:獲取貨幣匯率數(shù)據(jù)的遠(yuǎn)程接口URL;
- TrieDateField:
用于對(duì)日期時(shí)間類型數(shù)據(jù)進(jìn)行索引,日期時(shí)間類型數(shù)據(jù)在Java里可以使用java.util.Date,Long,Integer來表示,Long、Integer類型可以表示毫秒數(shù);使用時(shí)需要遵循以下格式約束:YYYY-MM-DDThh:mm:ssZ
- YYYY表示年份
- MM表示月份,兩位數(shù)字表示
- DD表示日期,兩位數(shù)字表示
- hh表示小時(shí)數(shù),24小時(shí)制
- mm表示分鐘數(shù)
- ss表示秒數(shù)
- Z表示UTC時(shí)區(qū)
solr對(duì)于日期時(shí)間存儲(chǔ)只能精確到毫秒,任何超出毫秒經(jīng)度部分的數(shù)據(jù)將會(huì)被丟棄,因此如果需要精確到毫秒,那么日期時(shí)間數(shù)據(jù)格式應(yīng)該類似如下:
1972-05-20T17:33:18.772Z
1972-05-20T17:33:18.77Z
1972-05-20T17:33:18.7Z
可以通過以下代碼將以上日期時(shí)間轉(zhuǎn)換成Date對(duì)象:
String input = "1972-05-20T17:33:18.772Z";
TimeZone utc = TimeZone.getTimeZone("UTC");
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
f.setTimeZone(utc);
GregorianCalendar cal = new GregorianCalendar(utc);
cal.setTime(f.parse(input));
Date date = cal.getTime();
一個(gè)TrieDateField域類型完整配置如下:
<field name="Date" class="solr.TrieDateField" datetimeformat="yyyy=MM-dd'T' HH:mm:ss.sss'Z'" indexed="true" multivalued="false" stored="true" precisionStep="6" type="date">
</field>
- name:表示域類型的名稱
- class:表示域類型的實(shí)現(xiàn)類
- detetimeformat:表示TrieDateField域的與之最終現(xiàn)實(shí)的字符串格式
- indexed:表示是否對(duì)當(dāng)前TrieDateField域創(chuàng)建索引
- multivalued:表示是否為多值域
- stored:表示是否存儲(chǔ)域值
- type:表示TrieDateField域的原始域值的數(shù)據(jù)類型,可選值:INTEGER,LONG,FLOAT,DOUBLE,DATE
- precisisonStep:該屬性值越大,生成的term個(gè)數(shù)越少,索引體積也會(huì)小,但區(qū)間范圍查詢性能也越低;反之,生成的term個(gè)數(shù)越多,索引體積越大,范圍區(qū)間查詢性能越高。如類型為Integer,則占4個(gè)字節(jié)32位,步長precisionStep=4時(shí),那么生成這些term,前4bit,前8bit,前12bit,前16bit...直到32bit。
- DateRangeField:
該域類型與TrieDateField類似,唯一的區(qū)別在于,該類型會(huì)以String類型暴露域值而非Date類型。
使用該域類型時(shí),日期范圍字符串必須類似如下:[2000 TO 2014-05-21T17:33:18.772Z],并支持日期范圍的多值域索引。
案例:查詢出某個(gè)時(shí)間段內(nèi)正開放經(jīng)營的餐廳。需要注意的是,每個(gè)餐廳在一天之內(nèi)可以有多個(gè)開放時(shí)間,而且每天的開放時(shí)間不固定。
<field name="openingHours" type="date_range" indexed="true" stored="true" multiValued="true"/>
<fieldType name="date_range" class="solr.DateRangeField"/>
date_range域的數(shù)據(jù):
[
"[2016-02-01T03:00Z TO 2016-02-01T15:00Z]",
"[2016-02-02T03:00Z TO 2016-02-02T15:00Z]",
"[2016-02-03T03:00Z TO 2016-02-03T15:00Z]",
"[2016-02-04T03:00Z TO 2016-02-04T15:00Z]",
"[2016-02-05T03:00Z TO 2016-02-05T16:00Z]",
"[2016-02-06T03:00Z TO 2016-02-06T16:00Z]"
]
可以通過如下查詢:facet.range=openingHours&f.openingHours.facet.range.start=NOW&f.openingHours.facet.range.end=NOW%2B6HOUR&f.openingHours.facet.range.gap=%2B1HOUR
- facet.range:表示你需要對(duì)哪個(gè)域進(jìn)行區(qū)間查詢
- facet.range.start:表示查詢區(qū)間的起始值
- facet.range.end:表示查詢區(qū)間的結(jié)束值
- facet.range.gap:表示區(qū)間遞增的間隙
4.EnumField:
該域類型用于對(duì)枚舉類型的數(shù)據(jù)進(jìn)行索引。
public enum LogLevel {
INFO,
DEBUG,
WARING,
ERROR
}
EnumField配置
<fieldType name="logLevelType" class="solr.EnumField" enumsConfig="enums-Config.xml" enumName="logLevel"
- enumsConfig:用于指定枚舉配置文件,在其中定義支持的所有枚舉值
- enumName:表示枚舉名稱,他必須域枚舉配置文件中配置的某一個(gè)<enum>元素的name屬性保持一致
<?xml version="1.0"?>
<enumsConfig>
<enum name="logLevel">
<value>INFO</value>
<value>DEBUG</value>
<value>WARNING</value>
<value>ERROR</value>
</enum>
<enum name="priority">
<value>HIGH</value>
...
</enum>
...
</enumsConfig>
- ExternalFileField:
該域類型支持為某個(gè)域指定域值,而該域值是從外部文件加載得到的。也就是說,某個(gè)域的與之不需要存儲(chǔ)到Solr中,可以從外部文件獲取。ExternalFileField是不支持查詢的,它只能用于function query或者顯示。
案例:假設(shè)你的Document有一個(gè)views域,而這個(gè)views域可能表示的是一篇博客的瀏覽量,由于瀏覽量可能每分每秒都在改變,你可能希望每個(gè)1分鐘或者半小時(shí)單獨(dú)更新下views表示瀏覽量的域,而文檔其他域的值可能更新并不是那么頻繁。
<fieldType name="viewsFile" keyField="id" defVal="0" stored="false" indexed="false" class="solr.ExternalFileField" valType="pfloat"/>
- keyField:定義唯一性標(biāo)示域的名稱,它通常示Document的唯一主鍵域,但并不是必須的,只要keyField能唯一標(biāo)示一個(gè)Document即可
- defValue:表示當(dāng)某個(gè)Document在外部文件中不存在示,ExternalFileField的域值采用defVal定義的默認(rèn)值
- valType:定義需要在外部文件里加載的域值的時(shí)機(jī)數(shù)據(jù)類型,可選值為pfloat,float,tfloat,這個(gè)屬性示可選的,可以不用配置
- ExternalFileField依賴的外部文件默認(rèn)需要存放在$SOLR_HOME/data目錄下,文件名稱應(yīng)該滿足如下規(guī)則:external_filename或者external_fileanme.*
eg.external_entryRankFile或者external_entryRankFile.txt。如果匹配到多份文件,以最后一份為準(zhǔn)。
文件內(nèi)容如下:
1=1000
2=20000
3=999
左邊表示keyField參數(shù)表示的域的域值,右邊表示需要存儲(chǔ)到外部文件而且經(jīng)常需要更新的域的域值。至此,我們只需要在field定義里通過type=“viewsFile”來應(yīng)用ExternalFileField,之后更新veiews域的域值就不需要更新每一份Document而只需周期性更新外部文件的鍵值和對(duì)應(yīng)的數(shù)值即可。
- UUIDField:
使用場景:
- 當(dāng)你需要增量式的添加索引文檔,索引文檔可能會(huì)重復(fù)添加,而你不希望索引文檔出現(xiàn)初伏
- 當(dāng)你的索引的數(shù)據(jù)很大,可能不會(huì)把它存儲(chǔ)到solr索引中,但有希望后續(xù)能夠根據(jù)索引中的某個(gè)域從外部數(shù)據(jù)源再次加載該數(shù)據(jù)
- 當(dāng)你希望更簡便的使用唯一主鍵來刪除一個(gè)文檔,而不是每次都繁瑣的使用query來匹配待刪除文檔
- 當(dāng)你是用DistributedSearch(分布式查詢)時(shí),需要一個(gè)唯一鍵來過濾多個(gè)分片上返回的重復(fù)文檔,因?yàn)槟悴幌M麑⒅貜?fù)的文檔返回給用戶。
UUID配置:
<!--schema.xml-->
<fieldType name="uuid" class="solr.UUIDField" indexed="true" />
<field name="id" type="uuid" indexed="true" stored="true" multiValued="false" required="true"/>
經(jīng)過上面步驟,我們的UUIDField域已經(jīng)配置好了,但solr還提供了一個(gè)自動(dòng)更新UUIDField的處理器,也就是使用它UUIDUpdateProcessorFactory,我們就不需要關(guān)心如何創(chuàng)建和更新UUIDField域了,全權(quán)交給UUIDUpdateProcessorFactory處理就行了。
<!--solrconfig.xml-->
<updateRequestProcessorChain name="dispup">
<processor class="solr.UUIDUpdateProcessorFactory">
<str name="fieldName">id</str>
</processor>
<processor class="solr.LogUpdateProcessorFactory"/>
<processor class="solr.DistributedUpdateProcessorFactory"/>
<processor class="solr.RunUpdateProcessorFactory"/>
</updateRequestProcessorChain>
<requestHandler name="/update" class="solr.UpdateRequestHandler">
<lst name="defaults">
<str name="update.chain">dispup</str>
</lst>
</requestHandler>