天天看點

Eulerproblem 10 for python

前面一篇開始學習solr的時候,做了個入門的示例http://blog.csdn.net/zjc/article/details/24414271 。雖然可以檢索出内容,但總和想象的結果有差異——比如,檢索“天龍”兩個字,按正常了解,就應該隻出來《天龍八部》才對,可是竟然也會把《倚天屠龍記》檢出來。後來研究了一下,發現系統是這樣處理的:無論是抽索引時還是分析檢索詞時,都把所有文字按單字拆開。這樣,剛好《倚天屠龍記》裡包含“天”和“龍”。于是對照solr的配置檔案schema.xml做了一些分析和驗證。下面來看一下:

在schema.xml裡,對檢索結果有最直接影響的有這麼幾項:

<solrQueryParserdefaultOperator="OR"/>

這一行在檔案較靠後的位置,但我最先拿出來說。這表示,對拆分後的檢索詞是按照“且”還是“或”的關系標明結果。預設是OR,可以改成AND。象前面例子,如果再有一本《天天向上》,也一樣會被檢索出來。因為包含了“天”字。那就差的更遠了。是以如果采用這個預設的單字拆分法,那最好是用AND,否則結果就太亂了。

好了,假定我們改成了AND,那麼結果是《天天向上》沒有了,但《倚天屠龍記》還在的。因為既有“天”又有“龍”,說明單字拆分法有不足之處。

決定這個單字拆分法的是誰呢?仔細檢查檔案,我們發現這一行:

<field name="name"type=" text_general" indexed="true"stored="true"/>

表示name這個字段是text_general類型的。這就靠譜了,多半text_general類型的處理方式就是單字拆分。

有沒有更好的分詞方法呢,當然有,而且肯定不止一種。我按照網上的例子采用了mmseg4j。使用方法很簡單,把解壓後的幾個jar檔案放到classpath目錄下。然後在schema.xml裡增加下面幾行:

<fieldType name="textComplex"class="solr.TextField" positionIncrementGap="100" >

<analyzer>

<tokenizerclass="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory"mode="complex" dicPath="./dic"/>

<filter class="solr.LowerCaseFilterFactory"/>

</analyzer>

 </fieldType>

 <fieldTypename="textMaxWord" class="solr.TextField"positionIncrementGap="100" >

      <analyzer>

            <tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory"mode="max-word" dicPath="./dic"/>

            <filterclass="solr.LowerCaseFilterFactory"/>

      </analyzer>

</fieldType>

<fieldType name="textSimple"class="solr.TextField" positionIncrementGap="100" >

<tokenizerclass="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory"mode="simple" dicPath="./dic"/>

這裡定義了三種fieldType,分别是textComplex、textMaxWord、textSimple。名稱無所謂,重要的是子元素定義了分詞器和過濾器使用的類:com.chenlb.mmseg4j.solr.MMSegTokenizerFactory、solr.LowerCaseFilterFactory。其實三種用的類是相同的,隻是後面有個mode不同。

這裡隻是定義了分詞類型,我們要把這個分詞類型應用到我們的資料裡才行。是以,要把<field name="name" type="textSimple"indexed="true" stored="true"/> ——我這裡改成了textSimple 。在fieldType和fieldname的共同作用下,我們終于可以完成中文習慣上的分詞了。當然要重新運作代碼,重新抽索引才行,而且字段name裡得有東西(參考上一篇的代碼)。

搜尋“name:天龍”,結果為空。這又是怎麼回事呢?難道又錯了?其實如果想看分詞效果,solr的管理端有個分析工具很好用。

進到分析頁面,上面輸入字段名稱name,下面輸入文本,看一下它倒底是怎麼分的

原來textSimple方式把“天龍八部”作為一個整詞了,難怪我們搜“天龍”沒結果,再搜“天龍八部”,有結果了。暈,這也太不符合習慣了。少字沒結果,多字反倒有結果。接着,我們再換一種試試:

<field name="name" type="textMaxWord"indexed="true" stored="true"/> name字段用textMaxWord類型,這表示采用最大化分詞的方式。再來分析一下:

這回差不多了,“天龍八部”被分成“天龍”“八”“部”三個詞。搜尋這三個詞都有結果了,而且是唯一結果。

換個搜尋寫法:

不寫name:天龍,直接寫天龍。暈死,倚天屠龍記又出來了。接着看schema.xml:

<defaultSearchField>text</defaultSearchField>

這表示預設搜尋字段,如果前面什麼都不寫,就到text裡去查找。而text怎麼定義的呢?再找:

<field name="text" type="text_general"indexed="true" stored="false"multiValued="true"/>

果然,又回到text_general來了,還是單字拆分法。

等等,回憶一下,我們并沒有text這個字段啊(參考上一篇代碼),我們隻錄入了三個字段id、name、price,這個text是誰?繼續找,在這裡——

<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"/>

這幾行表示,把cat、name、manu、features、includes都作為text看待(一般是為提供通用檢索或簡單檢索功能用的),text是text_general類型的,還是預設的。是以不寫條件時當然又回到單字查找法了。

總結一下:

這5個元素互動作用,最終共同影響着搜尋結果。

fieldType:定義了可選的類型,當然定義了未必就用

field:定義了某個字段具體是什麼fieldType的

copyField:提供了一個同時查找多個字段的簡便方法

defaultSearchField:定義了不寫字段條件時的查找範圍

solrQueryParser defaultOperator:定義了各分詞之間采用什麼邏輯組合

繼續閱讀