文本分析時(shí)搜索引擎的核心工作之一,,對(duì)文本包含許多處理步驟,比如:分詞,、大寫轉(zhuǎn)小寫,、詞干化、同義詞轉(zhuǎn)化等,。簡(jiǎn)單的說,,文本分析就說將一個(gè)文本字段的值轉(zhuǎn)為一個(gè)一個(gè)的token,然后被保存到Lucene的索引結(jié)構(gòu)中被將來搜索用,。當(dāng)然,,文本分析不僅在建立索引時(shí)有用,在查詢時(shí)對(duì)對(duì)所輸入的查詢串也一樣可以進(jìn)行文本分析,。在 Solr Schema設(shè)計(jì) 中我們介紹了許多Solr中的字段類型,,其中最重要的是solr.TextField,這個(gè)類型可以進(jìn)行分析器配置來進(jìn)行文本分析,。 接下來我們先來說說什么是分析器,。 分析器一個(gè)分析器可以檢查字段的文本信息,并且產(chǎn)生一個(gè) token 流,。
分析器是 schema.xml 中元素的一個(gè)子元素,,通常使用中,只有 solr.TextField 類型的字段會(huì)專門制定一個(gè)分析器,。最簡(jiǎn)單配置一個(gè)分析器的方式是使用<analyzer>元素,,制定這個(gè)元素的 class 屬性為一個(gè)完整的 Java 類名。這些類名必須源自 org.apache.lucene.analysis.Analyzer ,。
<fieldType name="nametext" class="solr.TextField"> <analyzer class="org.apache.lucene.analysis.WhitespaceAnalyzer"/> </fieldType> 在這個(gè)例子中,,WhitespaceAnalyzer 這個(gè)類負(fù)責(zé)分析文本字段的內(nèi)容并且產(chǎn)生出正確的 tokens,。如果只是簡(jiǎn)單的文本,例如“this is a pig",,像這樣的一個(gè)分析器的類足可以應(yīng)付了,,但是我們經(jīng)常需要對(duì)字段內(nèi)容做復(fù)雜的分析,這就需要把分析作為多個(gè)獨(dú)立的簡(jiǎn)單步驟來進(jìn)行處理了,。
以下是處理復(fù)雜分析的示例,,在<analyzer> 元素(不是類屬性)下添加分詞器和過濾器的工廠類:
<fieldType name="nametext" class="solr.TextField"> <analyzer> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.StopFilterFactory"/> </analyzer> </fieldType> 需要說明的話solr.前綴的包,其實(shí)是指向 org.apache.solr.analysis 這個(gè)包
在這個(gè)例子中,,在 <analyzer> 元素沒有指定分析器的類,,而是一系列的類共同承擔(dān)一個(gè)字段的分析器。文本首先傳到列表的第一個(gè)元素(solr.StandardTokenizerFactory),,然后再依次執(zhí)行filter,。簡(jiǎn)單的說就是經(jīng)過Tokenizer分詞之后,再繼續(xù)處理,,比如全轉(zhuǎn)成小寫,、時(shí)態(tài)處理、去掉語氣詞等,,產(chǎn)生出來的tokens 作為 terms 在字段的索引和查詢時(shí)使用,。
現(xiàn)在我們來看下Solr示例Schema配置中的text_en_splitting字段類型的定義,,看看它用了哪些分析組件。 <!-- A text field with defaults appropriate for English, plus aggressive word-splitting and autophrase features enabled. This field is just like text_en, except it adds WordDelimiterFilter to enable splitting and matching of words on case-change, alpha numeric boundaries, and non-alphanumeric chars. This means certain compound word cases will work, for example query "wi fi" will match document "WiFi" or "wi-fi". --> <fieldType name="text_en_splitting" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="true"> <analyzer type="index"> <!--<charFilter class="solr.MappingCharFilterFactory" mapping="mapping-ISOLatin1Accent.txt"/>--> <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. --> <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_en.txt" /> <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/> <filter class="solr.PorterStemFilterFactory"/> </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="lang/stopwords_en.txt" /> <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt"/> <filter class="solr.PorterStemFilterFactory"/> </analyzer> </fieldType> Type屬性可以指定為index或是query值,,分別表示是索引時(shí)用的分析器,,和查詢時(shí)所用的分析器,。如果在索引和查詢時(shí)使用相同的分析器,你可以不指定type屬性值,。 分析器的配置中可以選用一個(gè)或多個(gè)字符過濾器(character filter),,字符過濾器是對(duì)原始文本進(jìn)行字符流級(jí)別的操作。它通??梢杂糜诖笮戅D(zhuǎn)化,,去除字母上標(biāo)等等。在字符過濾器之后是分詞器(Tokenizer),,它是必須要配置的,。分析器會(huì)使用分詞器將字符流切分成詞元(Token)系列,通常用在空格處切分這種簡(jiǎn)單的算法,。后面的步驟是可選的,,比如token過濾器(Token Filter)會(huì)對(duì)token進(jìn)行許多種操作,最后產(chǎn)生的詞元會(huì)被稱為詞(Term),,即用于Lucene實(shí)際索引和查詢的單位,。 最后,,我有必須對(duì)autoGeneratePhraseQueries布爾屬性補(bǔ)充兩句,,這個(gè)屬性只能用于文本域。如果在查詢文本分析時(shí)產(chǎn)生了多個(gè)詞元,,比如Wi-Fi分詞為Wi和Fi,,那么默認(rèn)情況下它們只是兩個(gè)不同的搜索詞,它們沒有位置上的關(guān)系,。但如果autoGeneratePhraseQueries被設(shè)置,,那么這兩個(gè)詞元就構(gòu)造了一個(gè)詞組查詢,即“WiFi”,,所以索引中“WiFi”必須相鄰才能被查詢到,。在新Solr版本中,默認(rèn)它被設(shè)置為false,。我不建議使用它,。 在Admin上對(duì)字段進(jìn)行分析在我們深入特定分析組件的細(xì)節(jié)之前,有必要去熟悉Solr的分析頁面,,它是一個(gè)很好的實(shí)驗(yàn)和查錯(cuò)工具,絕對(duì)不容錯(cuò)過,。你將會(huì)用它來驗(yàn)證不同的分析配置,,來找到你最想要的效果,,你還可以用它來找到你認(rèn)為應(yīng)該會(huì)匹配的查詢?yōu)槭裁礇]有匹配。在Solr的管理頁面,,你可以看到一個(gè)名為[Analysis]的鏈接,,你進(jìn)入后,會(huì)看到下面的界面,。
界面上的第一個(gè)選項(xiàng)是必選的,,你可選擇直接通過字段類型名稱來選擇類型,你也可以間接地通過一個(gè)字段的名字來選擇自端類型,。在上面的示例中,我選擇了title字段 通過Schema Browser可以看到這個(gè)字段類型是 text_general
點(diǎn)擊灰色的 text_general,,可以看到這個(gè)字段的分析器中定義的分詞器和過濾器
接下來,你可以分析索引或是查詢文本,,也可以兩者同時(shí)分析,。你需要輸入些文本到文本框中以進(jìn)行分析,。將字段值放到Index文本框中,將查詢文本放入Query文本框中,點(diǎn)擊Analyze按鈕看到一下文本處理結(jié)果,,因?yàn)檫€沒有中文處理,,所以中文都被一個(gè)字一個(gè)字的分開處理了。
你可以選中verbose output來查看處理的詳細(xì)信息,,我希望你能自己試一下,。 上圖中每一行表示分析器處理鏈上的每一步的處理結(jié)果。比如第三個(gè)分析組件是LowerCaseFilter,,它的處理結(jié)果就在第三行,。前面的ST/SF/LCF應(yīng)該是分詞器和過濾器的簡(jiǎn)稱。 下面我們接著來詳細(xì)看看有哪些分詞器和過濾器吧,。 Character Filter字符過濾器在<charFilter>元素中定義,,它是對(duì)字符流進(jìn)行處理。字符過濾器種類不多,。這個(gè)特性只有下面第一個(gè)介紹的比較常見,。
Tokenization分詞器在<tokenizer>元素中定義,,它將一個(gè)字符流切分成詞元序列,大部分它會(huì)去除不重要的符號(hào),,比如空字符和連接符號(hào),。 一個(gè)分析器有且只應(yīng)有一個(gè)分詞器,你可選的分詞器如下:
還有用于其它語言的分詞器,,比如中文和俄語,還有ICUTokenizer會(huì)檢測(cè)語言,。另外NGramtokenizer會(huì)在后面討論,。可以在http://wiki./solr/AnalyzersTokenizersTokenFilters中找到更多內(nèi)容,。 WordDelimiterFilter它也許不是一個(gè)正式的分詞器,,但是這個(gè)名為WordDeilimiterFilter的詞元過濾器本質(zhì)上是一個(gè)分詞器。 <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1"/> 上面并沒有給出所有的選項(xiàng),,這個(gè)過濾器可以通過多種配置指定如切分和連接合成詞,,并有多種定義合成詞的方法,。這個(gè)過濾器通常與WhitespaceTokenizer配合,而不是StandardTokenizer,。這個(gè)過濾器的配置中1是設(shè)置,,0是重置。 WordDelimiterFilter先通過配置選項(xiàng)中的定義切分詞元:
此時(shí),如果下面的選項(xiàng)沒有設(shè)置,,上面這些切分后的詞都要被過濾掉,。因?yàn)槟J(rèn)下面的選項(xiàng)設(shè)置為false,你一般至少要設(shè)置下面其中一項(xiàng),。
下面是一個(gè)對(duì)上面選項(xiàng)的解釋的例子: WiFi-802.11b 切為 Wi,Fi,WiFi,802,11,80211,b,WiFi80211b, WiFi-802.11b
Stemming詞干化是去除詞尾變化或是有時(shí)將派生詞變回它們的詞干——基本形的過程,。比如,一種詞干化算法可能會(huì)將Riding和Rides轉(zhuǎn)化為Ride,。詞干化有助于提高結(jié)果召回率,,但是會(huì)對(duì)準(zhǔn)確率造成負(fù)影響。如果你是處理普通文本,,你用詞干化會(huì)提高你的搜索質(zhì)量,。但是如果你要處理的文本都是名詞,比如在MusicBrainz中的藝術(shù)家名字,,那么深度的詞干化可能會(huì)影響結(jié)果,。如果你想提高搜索的準(zhǔn)確率,并且不降低完整率,,那么你可以考慮將數(shù)據(jù)索引到兩個(gè)域,,其中一個(gè)進(jìn)行詞干化,另一個(gè)不進(jìn)行詞干化,在搜索時(shí)查找這兩個(gè)域,。 大多詞干器產(chǎn)生的詞干化的詞元都不再是一個(gè)拼寫合法的單詞,,比如Bunnies會(huì)轉(zhuǎn)化為Bunni,而不是Bunny,,Quote轉(zhuǎn)化為Quot,,你可以在Solr的文本分析頁面看到這些結(jié)果。如果在索引和查找時(shí)都進(jìn)行詞干化,,那么是不會(huì)影響搜索的,。但是一個(gè)域詞干化之后,就無法進(jìn)行拼寫檢查,,通配符匹配,,或是輸入提示,因?yàn)檫@些特性要直接用索引中的詞,。 下面是一些適用于英文的詞干器:
Correcting and augmenting stemming上面提到的詞干器都是使用算法進(jìn)行詞干化,,而不是通過詞庫(kù)進(jìn)行詞干化。語言中有許多的拼寫規(guī)則,,所以算法型的詞干器是很難做到完美的,有時(shí)在不應(yīng)該進(jìn)行詞干化的時(shí)候,也進(jìn)行了詞干化,。 如果你發(fā)現(xiàn)了一些不應(yīng)該進(jìn)行詞干化的詞,,你可以先使用KeywordMarkerFilter詞干器,并在它的protected屬性中指定不需要詞干化的詞元文件,,文件中一行一個(gè)詞元,。還有ignoreCase布爾選項(xiàng)。一些詞干器有或以前有protected屬性有相似的功能,,但這種老的方式不再建議使用,。 如果你需要指定一些特定的單詞如何被詞干化,就先使用StemmerOverrideFilter,。它的dictionary屬性可以指定一個(gè)在conf目錄下的UTF-8編碼的文件,,文件中每行兩個(gè)詞元,用tab分隔,,前面的是輸入詞元,,后面的是詞干化后的詞元。它也有ignoreCase布爾選項(xiàng),。這個(gè)過濾器會(huì)跳過KeywordMarkerFilter標(biāo)記過的詞元,,并且它會(huì)標(biāo)記它替換過的詞元,以使后面的詞干器不再處理它們,。 下面是三個(gè)詞干器鏈在分析器中配置的示例: <filter class="solr.KeywordMarkerFilterFactory" protected="protwords.txt" /> <filter class="solr.StemmerOverrideFilterFactory" dictionary="stemdict.txt" /> <filter class="solr.PorterStemFilterFactory" />
Synonyms進(jìn)行同義詞處理的目的是很好理解的,,在搜索時(shí)搜索所用的關(guān)鍵詞可能本身并不匹配文檔中的任何一個(gè)詞,但文檔中有這個(gè)搜索關(guān)鍵詞的同義詞,,但一般來講你還是想匹配這個(gè)文檔的,。當(dāng)然,同義詞并一定不是按字典意義上同義詞,,它們可以是你應(yīng)該中特定領(lǐng)域中的同義詞,。 這下一個(gè)同義詞的分析器配置: <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> synonyms的屬性值是在conf目錄下的一個(gè)文件。設(shè)置ignoreCase為true在查找同義詞時(shí)忽略大小寫,。 在我們討論expand選項(xiàng)前,,我們考慮一個(gè)例子。同義詞文件是一行行的,。下面是一個(gè)顯式映射的例子,,映射用=>符號(hào)表示: i-pod, i pod =>ipod 這表示如果在輸入詞元流中如果發(fā)現(xiàn)i-pod(一個(gè)詞元)或是i pod(兩個(gè)詞元),都會(huì)替換為ipod,。替換的同義詞也可以是多個(gè)詞元,。逗號(hào)是分隔多個(gè)同義詞之間的分隔符,同義詞的詞元間用空格分隔,。如果你要實(shí)現(xiàn)自定義的不用空格分隔的格式,,有一個(gè)tokenizerFactory屬性,,但它極少被使用。 你也可能看到配置文件里是這樣的格式: ipod, i-pod, i pod 配置文件里沒有=>符號(hào),,它的意義由expand參數(shù)來決定,,如果expand為true,它會(huì)被解釋為下面的顯式映射: ipod, i-pod, i pod =>ipod, i-pod, i pod 如果expand設(shè)置為false,,它就變?yōu)橄旅娴娘@式映射,,第一個(gè)同義詞為替換同義詞: ipod, i-pod, i pod =>ipod 在多行中指定多個(gè)詞替換為共一同義詞是允許的。如果一個(gè)源同義詞已經(jīng)被規(guī)則替換了,,另一個(gè)規(guī)則替換這個(gè)替換后詞,,則這兩個(gè)規(guī)則可以合并。 Index-time versus query-time, and to expand or not如果你要進(jìn)行同義詞擴(kuò)展,,你可以在索引時(shí)或是查詢時(shí)進(jìn)行同義處理,。但不要在索引和查詢時(shí)都處理,這樣處理會(huì)得到正確的結(jié)果,,但是會(huì)減慢處理速度,。我建議在索引時(shí)進(jìn)行擴(kuò)展,因?yàn)樵诓樵儠r(shí)進(jìn)行會(huì)有下面的問題:
但是任何在索引時(shí)進(jìn)行的分文本處理都是不靈活的。因?yàn)槿绻淖兞送x詞則需要完全重建索引才能看到效果,。并且,,如果在索引時(shí)進(jìn)行擴(kuò)展,索引會(huì)變大,,如果你使用WordNet類似的同義詞規(guī)則,,可能索引大到你不能接受,所以你在同義詞擴(kuò)展規(guī)則上應(yīng)該選擇一個(gè)合理的度,,但是我通常還是建議在索引時(shí)擴(kuò)展,。 你也許可以采用一種混合策略。比如,,你有一個(gè)很大的索引,,所以你不想對(duì)它經(jīng)常重建,但是你需要使新的同義詞迅速生效,,所以你可以將新的同義詞在查詢時(shí)和索引時(shí)都使用,。當(dāng)全量索引重建完成后,,你可以清空查詢同義詞文件。也許你喜歡查詢時(shí)進(jìn)行同義詞處理,,但你無法處理個(gè)別同義詞有空格的情況,,你可以在索引時(shí)處理這些個(gè)別的同義詞。 Stop WordsStopFilterFactory是一個(gè)簡(jiǎn)單的過濾器,,它是過濾掉在配置中指定的文件中的停詞(stop words),這個(gè)文件在conf目錄下,,可以指定忽略大小寫,。 <filter class="solr.StopFilterFactory" words="stopwords.txt" ignoreCase="true"/> 如果文檔中有大量無意義的詞,比如“the”,,“a”,,它們會(huì)使索引變大,并在使用短語查詢時(shí)降低查詢速度,。一個(gè)簡(jiǎn)單的方法是將這些詞經(jīng)常出現(xiàn)的域中過濾掉,,在包含多于一句(sentence)的內(nèi)容的域中可以考慮這種作法,但是如果把停詞過濾后,,就無法對(duì)停詞進(jìn)行查詢了,。所以如果你要使用,應(yīng)該在索引和查詢分析器鏈中都使用,。這通常是可以接受的,,但是在搜索“To be or not to be”這種句子時(shí),就會(huì)有問題,。對(duì)停詞理想的做法是不要去過濾它們,,以后介紹CommonGramsFilterFactory來解決這個(gè)問題。 Solr自帶了一個(gè)不錯(cuò)的英語停詞集合,。如果你在索引非英語的文本,,你要用自己指定停詞。要確定你索引中有哪些詞經(jīng)常出現(xiàn),,可以從Solr管理界面點(diǎn)擊進(jìn)入SCHEMA BROWSER,。你的字段列表會(huì)在左邊顯示,如果這個(gè)列表沒有立即出現(xiàn),,請(qǐng)耐心點(diǎn),,因?yàn)?span lang="EN-US">Solr要分析你索引里的數(shù)據(jù),所以對(duì)于較大的索引,,會(huì)有一定時(shí)間的延時(shí),。請(qǐng)選擇一個(gè)你知道包含有大量文本的域,你可以看到這個(gè)域的大量統(tǒng)計(jì),,包括出現(xiàn)頻率最高的10個(gè)詞,。 Phonetic sound-like analysis語音轉(zhuǎn)換(phonetic translation)可以讓搜索進(jìn)行語音相似匹配,。語音轉(zhuǎn)化的過濾器在索引和查詢時(shí)都將單詞編碼為phoneme。有五種語音編碼算法:Caverphone,,DoubleMetaphone,,Metaphone,RefinedSoundex和Soundex,。有趣的是,,DoubleMetaphone似乎是最好的選擇,即使是用在非英語文本上,。但也許你想通過實(shí)驗(yàn)來選擇算法,。RefinedSoundex聲稱是拼寫檢查應(yīng)用中最適合的算法。然而,,Solr當(dāng)前無法在它的拼寫檢查組件中使用語音分析,。 下面是在schema.xml里推薦使用的語音分析配置。 <!-- for phonetic (sounds-like) indexing --> <fieldType name="phonetic" class="solr.TextField" positionIncrementGap="100" stored="false" multiValued="true"> <analyzer> <tokenizer class="solr.WhitespaceTokenizerFactory"/> <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="0" catenateWords="1" catenateNumbers="0" catenateAll="0"/> <filter class="solr.DoubleMetaphoneFilterFactory" inject="false" maxCodeLength="8"/> </analyzer> </fieldType> 注意,,語音編碼內(nèi)部忽略大小寫,。 在MusicBrainz Schema中,有一個(gè)名為a_phonetic使用這個(gè)域類型,,它的域值是通過copyField拷貝的Artist名字,。第四章你會(huì)學(xué)習(xí)到dismax查詢解析器可以讓你對(duì)不同的域賦不同的boost,同時(shí)查找這幾個(gè)域,。你可以不僅僅搜索a_name域,,你還可以用一個(gè)較低的boost來搜索a_phonenic域,這樣就可以進(jìn)行兼顧語音搜索了,。 用Solr的分析管理頁面,,你可以看到這它將Smashing Pumpkins編碼為SMXNK|XMXNK PMPKNS(|表示兩邊的詞元在同一位置)。編碼后的內(nèi)容看起來沒什么意義,,實(shí)際它是為比較相似語音的效率而設(shè)計(jì),。 上面配置示例中使用的DoubleMetaphoneFilterFactory分析過濾器,它有兩個(gè)選項(xiàng):
如果要使用其它四個(gè)語音編碼算法,,你必須用這個(gè)過濾器: <filter class="solr.PhoneticFilterFactory" encoder="RefinedSoundex" inject="false"/> 其中encoder屬性值是第一段中的幾個(gè)算法之一。 Substring indexing and wildcards通常,,文本索引技術(shù)用來查找整個(gè)單詞,,但是有時(shí)會(huì)查找一個(gè)索引單詞的子串,或是某些部分,。Solr支持通配符查詢(比如mus*ainz),,但是支持它需要在索引時(shí)過行一定的處理。 要理解Lucene在索引時(shí)內(nèi)部是如何支持通配符查詢是很有用的,。Lucene內(nèi)部會(huì)在已經(jīng)排序的詞中先查詢非通配符前綴(上例中的mus),。注意前綴的長(zhǎng)度與整個(gè)查詢的時(shí)間為指數(shù)關(guān)系,前綴越短,,查詢時(shí)間越長(zhǎng)。事實(shí)上Solr配置Lucene中不支持以通配符開頭的查詢,,就是因?yàn)樾实脑?。另外,詞干器,,語音過濾器,,和其它一些文本分析組件會(huì)影響這種查找。比如,,如果running被詞干化為run,,而runni*無法匹配。 ReversedWildcardFilterSolr不支持通配符開頭的查詢,,除非你對(duì)文本進(jìn)行反向索引加上正向加載,,這樣做可以提高前綴很短的通配符查詢的效率。 下面的示例應(yīng)該放到索引文本分析鏈的最后: <filter class="solr.ReversedWildcardFilterFactory" /> 你可以在JavaDocs中了解一些提高效率的選項(xiàng),,但默認(rèn)的就很不錯(cuò):http://lucene./solr/api/org/apache/solr/analysis/ReversedWildcardFilterFactory.html Solr不支持查詢中同時(shí)有配置符在開頭和結(jié)尾,,當(dāng)然這是出于性能的考慮。 N-gramsN-gram分析會(huì)根據(jù)配置中指定的子中最小最大長(zhǎng)度,,將一個(gè)詞的最小到最大的子串全部得到,,比如Tonight這個(gè)單詞,如果NGramFilterFactory配置中指定了minGramSize為2,,maxGramSize為5,,那么會(huì)產(chǎn)生下面的索引詞:(2-grams):To, on , ni, ig, gh, ht,(3-grams):ton, oni, nig, ight, ght, (4-grams):toni, onig, nigh, ight, (5-grams):tonig,,onigh, night,。注意Tonight完整的詞不會(huì)產(chǎn)生,因?yàn)樵~的長(zhǎng)度不能超過maxGramSize,。N-Gram可以用作一個(gè)詞元過濾器,,也可以用作為分詞器NGramTokenizerFactory,,它會(huì)產(chǎn)生跨單詞的n-Gram。 下是是使用n-grams匹配子串的推薦配置: <fieldType name="nGram" class="solr.TextField" positionIncrementGap="100" stored="false" multiValued="true"> <analyzer type="index"> <tokenizer class="solr.StandardTokenizerFactory"/> <!-- potentially word delimiter, synonym filter, stop words, NOT stemming --> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.NGramFilterFactory" minGramSize="2" maxGramSize="15"/> </analyzer> <analyzer type="query"> <tokenizer class="solr.StandardTokenizerFactory"/> <!-- potentially word delimiter, synonym filter, stop words, NOT stemming --> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> </fieldType> 注意n-Gram只在索引時(shí)進(jìn)行,,gram的大小配置是根據(jù)你想進(jìn)行匹配子串的長(zhǎng)度而決定 的(示例中是最小是2,,最長(zhǎng)是15)。 N_gram分析的結(jié)果可以放到另一個(gè)用于匹配子串的域中,。用dismaxquery解析器支持搜索多個(gè)域,,在搜索匹配這個(gè)子串的域可以設(shè)置較小的boost。 另一個(gè)變形的是EdgeNGramTokenizerFactory和EdgeNGramFilterFactory,,它會(huì)忽略輸入文本開頭或結(jié)尾的n-Gram,。對(duì)過濾器來說,輸入是一個(gè)詞,,對(duì)分詞器來說,,它是整個(gè)字符流。除了minGramSize和maxGramSize之后,,它還有一個(gè)side參數(shù),,可選值為front和back。如果只需要前綴匹配或是后綴匹配,,那邊EdgeNGram分析是你所需要的了,。 N-gram costsn-Gram的代價(jià)很高,前面的例子中Tonight有15個(gè)子串詞,,而普通的文本分析的結(jié)果一般只有一個(gè)詞,。這種轉(zhuǎn)換會(huì)產(chǎn)生很多詞,也就需要更長(zhǎng)的時(shí)間去索引,。以MusicBrainz Schema為例,,a_name域以普通方式索引并stored,a_ngram域?qū)?span lang="EN-US">a_name中的值進(jìn)行n-Gram分析,,子串的長(zhǎng)度為2-15,。它不是一個(gè)stored域,因?yàn)?span lang="EN-US">Artist的名字已經(jīng)保存在a_name中了,。
上表給出了只索引a_name和索引a_name和a_ngram的統(tǒng)計(jì)信息,。注意索引時(shí)間增加了10倍,而索引大小增加了5倍,。注意,,這才只是一個(gè)域。 注意如果變大minGramSize的大小,,nGram的代價(jià)會(huì)小很多,。Edge nGraming也代價(jià)也會(huì)小,因?yàn)樗魂P(guān)心開頭或結(jié)尾的nGram?;?span lang="EN-US">nGram的分詞器無疑會(huì)比基于nGram的過濾器代碼要高,,因?yàn)榉衷~器將產(chǎn)生帶空格的詞,然而,,這種方式可以支持跨詞的通配符,。 Sorting Text通常,搜索結(jié)果是由神奇的score偽字段進(jìn)行排序的,,但是有時(shí)候也會(huì)根據(jù)某個(gè)字段的值進(jìn)行排序,。除了對(duì)結(jié)果進(jìn)行排序,它還有許多的作用,,進(jìn)行區(qū)間查詢和對(duì)Facet結(jié)果進(jìn)行排序,。 MusicBrainz提供了對(duì)Artist和Lable名稱進(jìn)行排序的功能。排序的版本會(huì)將原來的名字中的某些詞,,比如“The”移到最后,,用逗號(hào)分隔。我們將排序的名字域設(shè)置為indexed,,但不是stored,,因?yàn)槲覀円獙?duì)它進(jìn)行排序,但不進(jìn)行展示,,這與MusicBrainz所實(shí)現(xiàn)的有所不同。記住indexed和stored默認(rèn)設(shè)置為true,。因?yàn)橛行┪谋痉治鼋M件會(huì)限制text域的排序功能,,所以在你的Schema中要用于排序的文本域應(yīng)該拷貝到另一個(gè)域中。copyField功能會(huì)很輕松地完成這個(gè)任務(wù),。String類型不進(jìn)行文本分析,,所以它對(duì)我們的MusicBrainz情況是非常適合的。這樣我們就支持了對(duì)Artist排序,,而沒有派生任何內(nèi)容,。 Miscellaneous token filtersSolr還包括許多其它的過濾器:
|
|