天天看点

第四章 分词

1. Analyzer

       Lucene内置分词器SimpleAnalyzer、StopAnalyzer、WhitespaceAnalyzer、StandardAnalyzer

主要作用:

KeywordAnalyzer分词,没有任何变化;

SimpleAnalyzer对中文效果太差;

StandardAnalyzer对中文单字拆分;

StopAnalyzer和SimpleAnalyzer差不多;

WhitespaceAnalyzer只按空格划分。

2. TokenStream

分词器做好处理之后得到的一个流,这个流中存储了分词的各种信息,可以通过TokenStream有效的获取到分词单元信息

生成的流程

<a href="http://s3.51cto.com/wyfs02/M02/49/04/wKiom1QNXCjRDia8AAC0d1oqgS8802.jpg" target="_blank"></a>

在这个流中所需要存储的数据

<a href="http://s3.51cto.com/wyfs02/M00/49/05/wKioL1QNXD_D-wnJAADBZV4ljMM627.jpg" target="_blank"></a>

3. Tokenizer

主要负责接收字符流Reader,将Reader进行分词操作。有如下一些实现类

<a href="http://s3.51cto.com/wyfs02/M00/49/04/wKiom1QNXGHBgyjGAAFfL_LVWgc751.jpg" target="_blank"></a>

4. TokenFilter

将分词的语汇单元,进行各种各样过滤

<a href="http://s3.51cto.com/wyfs02/M01/49/05/wKioL1QNXH7Rb2ESAADkQpvbtrs160.jpg" target="_blank"></a>

5.扩展:TokenFilter各类介绍:

(1),TokenFilter

输入参数为另一个TokerStream的TokerStream,其子类必须覆盖incrementToken()函数。

(2),LowerCaseFilter

将Token分词转换为小写。

(3),FilteringTokenFilter

TokenFilters的一个抽象类,可能会删除分词。如果当前分词要保存,则需要实现accept()方法

并返回一个boolean值。incrementToken()方法将调用accept()方法来决定是否将当前的分词返回

给调用者。

(4),StopFilter

从token stream中移除停止词(stop words).

<code>protected</code> <code>boolean</code> <code>accept() {</code>

<code>     </code><code>return</code><code>!stopWords.contains(termAtt.buffer(), </code><code>0</code><code>, termAtt.length());</code><code>//返回不是stop word的分词</code>

<code> </code><code>}</code>

(5),TypeTokenFilter

从token stream中移除指定类型的分词。

<code>     </code><code>returnuseWhiteList == stopTypes.contains(typeAttribute.type());</code>

<code>}</code>

(6),LetterTokenizer

是一个编译器,将文本在非字母。说,它定义了令牌的最大字符串相邻的字母

(7),TokenFilter的顺序问题

此时停止词 the 就未被去除了。先全部转换为小写字母,再过滤停止词(The 转换成 the 才可以与停止词词组里的 the 匹配),如果不限制大小写,停止词的组合就太多了。

<code>import</code> <code>java.io.Reader;</code>

<code>import</code> <code>java.util.Set;</code>

<code>import</code> <code>org.apache.lucene.analysis.Analyzer;</code>

<code>importorg.apache.lucene.analysis.LetterTokenizer;</code>

<code>importorg.apache.lucene.analysis.LowerCaseFilter;</code>

<code>import</code> <code>org.apache.lucene.analysis.StopAnalyzer;</code>

<code>import</code> <code>org.apache.lucene.analysis.StopFilter;</code>

<code>import</code> <code>org.apache.lucene.analysis.TokenStream;</code>

<code>import</code> <code>org.apache.lucene.util.Version;</code>

<code>public</code> <code>class</code> <code>MyStopAnalyzer </code><code>extends</code> <code>Analyzer {</code>

<code>  </code><code>privateSet&lt;Object&gt; words;</code>

<code>  </code><code>publicMyStopAnalyzer(){}</code>

<code>  </code><code>publicMyStopAnalyzer(String[] words ){</code>

<code>     </code><code>this</code><code>.words=StopFilter.makeStopSet(Version.LUCENE_35,words, </code><code>true</code><code>);</code>

<code>     </code><code>this</code><code>.words.addAll(StopAnalyzer.ENGLISH_STOP_WORDS_SET)</code>

<code>  </code><code>}</code>

<code> </code> 

<code>  </code><code>@Override</code>

<code>  </code><code>publicTokenStream tokenStream(String fieldName, Reader reader) {</code>

<code>     </code><code>// TODO Auto-generatedmethod stub</code>

<code>     </code><code>return</code> <code>newStopFilter(Version.LUCENE_35,</code><code>new</code> <code>LowerCaseFilter(Version.LUCENE_35, newLetterTokenizer(Version.LUCENE_35,reader)),</code><code>this</code><code>.words);</code>

<code>public</code> <code>static</code> <code>void</code> <code>displayAllTokenInfo(Stringstr,Analyzer a) {</code>

<code>           </code><code>try</code><code>{</code>

<code>                 </code><code>TokenStreamstream = a.tokenStream(</code><code>"content"</code><code>,</code><code>new</code> <code>StringReader(str));</code>

<code>                 </code><code>//位置增量的属性,存储语汇单元之间的距离</code>

<code>                 </code><code>PositionIncrementAttributepia = </code>

<code>                                  </code><code>stream.addAttribute(PositionIncrementAttribute.</code><code>class</code><code>);</code>

<code>                 </code><code>//每个语汇单元的位置偏移量</code>

<code>                 </code><code>OffsetAttributeoa = </code>

<code>                                  </code><code>stream.addAttribute(OffsetAttribute.</code><code>class</code><code>);</code>

<code>                 </code><code>//存储每一个语汇单元的信息(分词单元信息)</code>

<code>                 </code><code>CharTermAttributecta = </code>

<code>                                  </code><code>stream.addAttribute(CharTermAttribute.</code><code>class</code><code>);</code>

<code>                 </code><code>//使用的分词器的类型信息</code>

<code>                 </code><code>TypeAttributeta = </code>

<code>                                  </code><code>stream.addAttribute(TypeAttribute.</code><code>class</code><code>);</code>

<code>                 </code><code>for</code><code>(;stream.incrementToken();){</code>

<code>                      </code><code>System.out.print(pia.getPositionIncrement()+</code><code>":"</code><code>);</code>

<code>                      </code><code>System.out.print(cta+</code><code>"["</code><code>+oa.startOffset()+</code><code>"-"</code><code>+oa.endOffset()+</code><code>"]--&gt;"</code><code>+ta.type()+</code><code>"\n"</code><code>);</code>

<code>                 </code><code>}</code>

<code>           </code><code>}</code><code>catch</code> <code>(Exception e) {</code>

<code>                 </code><code>e.printStackTrace();</code>

<code>           </code><code>}</code>

<code>      </code><code>}</code>

1.自定义Stop分词器

<code>package</code> <code>com.mzsx.analyzer;</code>

<code>      </code><code>privateSet&lt;Object&gt; words;</code>

<code>      </code><code>publicMyStopAnalyzer(){}</code>

<code>      </code><code>publicMyStopAnalyzer(String[] words ){</code>

<code>           </code><code>this</code><code>.words=StopFilter.makeStopSet(Version.LUCENE_35,words, </code><code>true</code><code>);</code>

<code>           </code><code>this</code><code>.words.addAll(StopAnalyzer.ENGLISH_STOP_WORDS_SET);</code>

<code>           </code> 

<code>      </code><code>@Override</code>

<code>      </code><code>publicTokenStream tokenStream(String fieldName, Reader reader) {</code>

<code>           </code><code>returnnew StopFilter(Version.LUCENE_35,</code><code>new</code> <code>LowerCaseFilter(Version.LUCENE_35, newLetterTokenizer(Version.LUCENE_35,reader)),</code><code>this</code><code>.words);</code>

<code>//测试代码</code>

<code>@Test</code>

<code>      </code><code>publicvoid myStopAnalyzer() {</code>

<code>           </code><code>Analyzera1 = </code><code>new</code> <code>MyStopAnalyzer(</code><code>new</code> <code>String[]{</code><code>"I"</code><code>,</code><code>"you"</code><code>,</code><code>"hate"</code><code>});</code>

<code>           </code><code>Analyzera2 = </code><code>new</code> <code>MyStopAnalyzer();</code>

<code>           </code><code>Stringtxt = </code><code>"how are you thank you I hate you"</code><code>;</code>

<code>           </code><code>AnalyzerUtils.displayAllTokenInfo(txt,a1);</code>

<code>           </code><code>//AnalyzerUtils.displayToken(txt,a2);</code>

2.简单实现同义词索引

<code>public</code> <code>interface</code> <code>SamewordContext {</code>

<code>      </code><code>publicString[] getSamewords(String name);</code>

<code>import</code> <code>java.util.HashMap;</code>

<code>import</code> <code>java.util.Map;</code>

<code>public</code> <code>class</code> <code>SimpleSamewordContext implementsSamewordContext {</code>

<code>      </code> 

<code>      </code><code>Map&lt;String,String[]&gt;maps = </code><code>new</code> <code>HashMap&lt;String,String[]&gt;();</code>

<code>      </code><code>publicSimpleSamewordContext() {</code>

<code>           </code><code>maps.put(</code><code>"中国"</code><code>,</code><code>new</code> <code>String[]{</code><code>"天朝"</code><code>,</code><code>"大陆"</code><code>});</code>

<code>           </code><code>maps.put(</code><code>"我"</code><code>,</code><code>new</code> <code>String[]{</code><code>"咱"</code><code>,</code><code>"俺"</code><code>});</code>

<code>           </code><code>maps.put(</code><code>"china"</code><code>,</code><code>new</code> <code>String[]{</code><code>"chinese"</code><code>});</code>

<code>      </code><code>publicString[] getSamewords(String name) {</code>

<code>           </code><code>returnmaps.get(name);</code>

<code>import</code> <code>java.io.IOException;</code>

<code>import</code> <code>java.util.Stack;</code>

<code>import</code> <code>org.apache.lucene.analysis.TokenFilter;</code>

<code>importorg.apache.lucene.analysis.tokenattributes.CharTermAttribute;</code>

<code>importorg.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;</code>

<code>import</code> <code>org.apache.lucene.util.AttributeSource;</code>

<code>public</code> <code>class</code> <code>MySameTokenFilter extendsTokenFilter {</code>

<code>      </code><code>privateCharTermAttribute cta = </code><code>null</code><code>;</code>

<code>      </code><code>privatePositionIncrementAttribute pia = </code><code>null</code><code>;</code>

<code>      </code><code>privateAttributeSource.State current;</code>

<code>      </code><code>privateStack&lt;String&gt; sames = </code><code>null</code><code>;</code>

<code>      </code><code>privateSamewordContext samewordContext;</code>

<code>      </code><code>protectedMySameTokenFilter(TokenStream input,SamewordContext samewordContext) {</code>

<code>           </code><code>super</code><code>(input);</code>

<code>           </code><code>cta= </code><code>this</code><code>.addAttribute(CharTermAttribute.</code><code>class</code><code>);</code>

<code>           </code><code>pia= </code><code>this</code><code>.addAttribute(PositionIncrementAttribute.</code><code>class</code><code>);</code>

<code>           </code><code>sames= </code><code>new</code> <code>Stack&lt;String&gt;();</code>

<code>           </code><code>this</code><code>.samewordContext= samewordContext;</code>

<code>      </code><code>publicboolean incrementToken() </code><code>throws</code> <code>IOException {</code>

<code>           </code><code>if</code><code>(sames.size()&gt;</code><code>0</code><code>){</code>

<code>                 </code><code>//将元素出栈,并且获取这个同义词</code>

<code>                 </code><code>Stringstr = sames.pop();</code>

<code>                 </code><code>//还原状态</code>

<code>                 </code><code>restoreState(current);</code>

<code>                 </code><code>cta.setEmpty();</code>

<code>                 </code><code>cta.append(str);</code>

<code>                 </code><code>//设置位置0</code>

<code>                 </code><code>pia.setPositionIncrement(</code><code>0</code><code>);</code>

<code>                 </code><code>returntrue;</code>

<code>           </code><code>if</code><code>(!</code><code>this</code><code>.input.incrementToken())</code><code>return</code> <code>false</code><code>;</code>

<code>           </code><code>if</code><code>(addSames(cta.toString())){</code>

<code>                 </code><code>//如果有同义词将当前状态先保存</code>

<code>                 </code><code>current= captureState();</code>

<code>           </code><code>returntrue;</code>

<code>      </code><code>privateboolean addSames(String name) {</code>

<code>           </code><code>String[]sws = samewordContext.getSamewords(name);</code>

<code>           </code><code>if</code><code>(sws!=</code><code>null</code><code>){</code>

<code>                 </code><code>for</code><code>(Stringstr:sws) {</code>

<code>                      </code><code>sames.push(str);</code>

<code>           </code><code>returnfalse;</code>

<code>import</code> <code>com.chenlb.mmseg4j.Dictionary;</code>

<code>import</code> <code>com.chenlb.mmseg4j.MaxWordSeg;</code>

<code>importcom.chenlb.mmseg4j.analysis.MMSegTokenizer;</code>

<code>public</code> <code>class</code> <code>MySameAnalyzer </code><code>extends</code> <code>Analyzer {</code>

<code>      </code><code>publicMySameAnalyzer(SamewordContext swc) {</code>

<code>           </code><code>samewordContext= swc;</code>

<code>           </code><code>Dictionarydic = Dictionary.getInstance(</code><code>"D:/luceneIndex/dic"</code><code>);</code>

<code>           </code><code>returnnew MySameTokenFilter(</code>

<code>                      </code><code>newMMSegTokenizer(</code><code>new</code> <code>MaxWordSeg(dic), reader),samewordContext);</code>

<code>      </code><code>publicvoid testSameAnalyzer() {</code>

<code>                 </code><code>Analyzera2 = </code><code>new</code> <code>MySameAnalyzer(</code><code>new</code> <code>SimpleSamewordContext());</code>

<code>                 </code><code>Stringtxt = </code><code>"我来自中国海南儋州第一中学,welcome to china !"</code><code>;</code>

<code>                 </code><code>Directorydir = </code><code>new</code> <code>RAMDirectory();</code>

<code>                 </code><code>IndexWriterwriter = </code><code>new</code> <code>IndexWriter(dir,</code><code>new</code> <code>IndexWriterConfig(Version.LUCENE_35, a2));</code>

<code>                 </code><code>Documentdoc = </code><code>new</code> <code>Document();</code>

<code>                 </code><code>doc.add(newField(</code><code>"content"</code><code>,txt,Field.Store.YES,Field.Index.ANALYZED));</code>

<code>                 </code><code>writer.addDocument(doc);</code>

<code>                 </code><code>writer.close();</code>

<code>                 </code><code>IndexSearchersearcher = </code><code>new</code> <code>IndexSearcher(IndexReader.open(dir));</code>

<code>                 </code><code>TopDocstds = searcher.search(</code><code>new</code> <code>TermQuery(</code><code>new</code> <code>Term(</code><code>"content"</code><code>,</code><code>"咱"</code><code>)),</code><code>10</code><code>);</code>

<code>                 </code><code>Documentd = searcher.doc(tds.scoreDocs[</code><code>0</code><code>].doc);</code>

<code>                 </code><code>System.out.println(</code><code>"原文:"</code><code>+d.get(</code><code>"content"</code><code>));</code>

<code>                 </code><code>AnalyzerUtils.displayAllTokenInfo(txt,a2);</code>

<code>           </code><code>}</code><code>catch</code> <code>(CorruptIndexException e) {</code>

<code>           </code><code>}</code><code>catch</code> <code>(LockObtainFailedException e) {</code>

<code>           </code><code>}</code><code>catch</code> <code>(IOException e) {</code>

本文转自 梦朝思夕 51CTO博客,原文链接:http://blog.51cto.com/qiangmzsx/1549902