如何在SOLR中嵌入自己的分词系统

SOLR虽然为我们提供了分词的接入方法,但很显然并不奏效,搜遍了大江南北,也没有什么可参考的,大部分都是使用的IK或庖丁之类的分词~~,难 不成就这样永远活在别人的阴影中??答案是"NO!",如果是这样那就意味着屏蔽词管理,词典实时更新,实时持久化等多个个性化的产品需求得以在这些分词 系统上半路杀入,老鸟应该都明白这种做法的成本是太高了。

       SOLR推荐但失败的分词接入方法是在schema.xml字段配置文件中写入以下配置:

      

       编写自己的TokenFactory ,该类继成自 SOLR的BaseTokenizerFactory ,找到以下配置节点,并将 tokenizer的 class类 :替换掉。

    

  1. <tokenizer class="org.apache.lucene.analysis.cn.SolrTokenFactory"/>    
  2. <analyzer type="index">  
  3.   
  4.             <!-- <tokenizer class="org.apache.lucene.analysis.cn.SolrTokenFactory"/>   
  5. ->  
  6.   
  7. <tokenizer class="org.apache.lucene.analysis.cn.SolrTokenFactory"/>          
  8.        <!-- in this example, we will only use synonyms at query time  
  9.        <filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>  
  10.        -->  
  11.        <!-- Case insensitive stop word removal.  
  12.          add enablePositionIncrements=true in both the index and query  
  13.          analyzers to leave a 'gap' for more accurate phrase queries.  
  14.        -->  
  15.        <filter class="solr.StopFilterFactory"  
  16.                ignoreCase="true"  
  17.                words="stopwords.txt"  
  18.                enablePositionIncrements="true"  
  19.                />  
  20.        <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="1" catenateNumbers="1" catenateAll="0" splitOnCaseChange="1"/>  
  21.        <filter class="solr.LowerCaseFilterFactory"/>  
  22.      </analyzer>  
  23.      <analyzer type="query">  
  24.        <tokenizer class="org.apache.lucene.analysis.cn.SolrTokenFactory"/>   
  25.           
  26. <!-- <tokenizer class="org.wltea.analyzer.solr.IKTokenizerFactory14"/> -->   
  27.              <filter class="solr.StopFilterFactory"  
  28.                ignoreCase="true"  
  29.                words="stopwords.txt"  
  30.                enablePositionIncrements="true"  
  31.                />  
  32.        <filter class="solr.WordDelimiterFilterFactory" generateWordParts="1" generateNumberParts="1" catenateWords="0" catenateNumbers="0" catenateAll="0" splitOnCaseChange="1"/>  
  33.        <filter class="solr.LowerCaseFilterFactory"/>  
  34.      </analyzer>  

    把IK的源代码翻了个底朝天,也没看出自己的分词器和它的接入方法有什么区别,不是QUERY分词失败,就是写入的索引没有分词效果,一气之下就钻到SOLR的源代码里,经过一番苦战,终于苦尽甘来~,彻底搞定!

    废话少说,来解决方案:

    说明:因为修改了SOLR的部分代码,所以分词器在SCHEMA.xml的配置是彻底失效了,但是其他字段设定都沿用schema.xml.

   

    在这之前先说下SOLR加载schema.xml的步骤:

    调用栈:

   org.apache.solr.core.SolrCore 520行

    schema = new IndexSchema(config, IndexSchema.DEFAULT_SCHEMA_FILE, null);

    org.apache.solr.schema.IndexSchema 103行

      readSchema(lis);

  SOLR主要是通过 private void readSchema(InputStream is)  这个函数对分词解析器进行初始化,及对schema.xml中的各种类型进行实例化,同时写入到 :protected final HashMap<String, Analyzer> analyzers ,供外部系统调用。

   这次我们开到的函数就是 org.apache.solr.schema.IndexSchema  的 readSchema()函数。

     因为我们要将自己的分词解析器半路插进去,因此在这个函数的这个位置插入以下语句:

  

  1. try{  
  2.                 AbstractPluginLoader<FieldType> fieldLoader = new AbstractPluginLoader<FieldType>(  
  3.                         "[schema.xml] fieldType", true, true) {  
  4.   
  5.                     @Override  
  6.                     protected FieldType create(ResourceLoader loader, String name,  
  7.                             String className, Node node) throws Exception {  
  8.                         FieldType ft = (FieldType) loader.newInstance(className);  
  9.                         ft.setTypeName(name);  
  10.   
  11.                         String expression = "./analyzer[@type='query']";  
  12.                         Node anode = (Node) xpath.evaluate(expression, node,  
  13.                                 XPathConstants.NODE);  
  14.                         Analyzer queryAnalyzer = readAnalyzer(anode);  
  15.   
  16.                         // An analyzer without a type specified, or with  
  17.                         // type="index"  
  18.                         expression = "./analyzer[@type='index']";  
  19.                         anode = (Node) xpath.evaluate(expression, node,  
  20.                                 XPathConstants.NODE);  
  21.                         Analyzer analyzer = readAnalyzer(anode);  
  22.   
  23.                         if (queryAnalyzer == null)  
  24.                             queryAnalyzer = analyzer;  
  25.                         if (analyzer == null)  
  26.                             analyzer = queryAnalyzer;  
  27.                         if (analyzer != null) {  
  28.                             if(ft!=null && className.equals("solr.TextField")){  
  29.                                 ft.setAnalyzer(AnalyzerManager.getAnalyzer());  
  30.                                 ft.setQueryAnalyzer(AnalyzerManager.getAnalyzer());  
  31.                             }else{  
  32.                                 ft.setAnalyzer(analyzer);  
  33.                                 ft.setQueryAnalyzer(analyzer);  
  34.                             }  
  35.                                   
  36.                         }  
  37.                         return ft;  
  38.                     }  

在 protected FieldType create(ResourceLoader loader, String name,
       String className, Node node) throws Exception { 

 这个函数体中,判断 className 的类名,因为我们需要对solr.TextField类型做重写,即改写text类型的分词器,所以需要加入以下判断:

  

  1. if (analyzer != null) {  
  2.                             if(ft!=null && className.equals("solr.TextField")){  
  3.                                 ft.setAnalyzer(AnalyzerManager.getAnalyzer());  
  4.                                 ft.setQueryAnalyzer(AnalyzerManager.getAnalyzer());  
  5.                             }else{  
  6.                                 ft.setAnalyzer(analyzer);  
  7.                                 ft.setQueryAnalyzer(analyzer);  
  8.                             }  
  9.                                   
  10.                         }  

OK,重启SOLR,试试看,是不是奏效了??

posted @ 2010-03-19 23:23  searchDM  阅读(510)  评论(0编辑  收藏  举报