在 Lucene 中,不仅 TokenFilter 我们可以自定义,Analyzer 我们也可以自定义。本文介绍两个扩展 Analyzer 的例子,分别实现扩展停用词,实现字长过滤的功能。
自定义 Analyzer
自定义 Analyzer 只需要做到下面 3 步即可。
- 继承自 Analyzer 并覆写 createComponents(String) 方法
- 维护自己的停用词词典
- 重写 TokenStreamComponents,选择合适的过滤策略
class StopAnalyzerExtend extends Analyzer { private CharArraySet stopWordSet;//停止词词典 public CharArraySet getStopWordSet() { return this.stopWordSet; } public void setStopWordSet(CharArraySet stopWordSet) { this.stopWordSet = stopWordSet; } public StopAnalyzerExtend() { super(); setStopWordSet(StopAnalyzer.ENGLISH_STOP_WORDS_SET); } /** * @param stops 需要扩展的停止词 */ public StopAnalyzerExtend(List<String> stops) { this(); /**如果直接为stopWordSet赋值的话,会报如下异常,这是因为在StopAnalyzer中 有ENGLISH_STOP_WORDS_SET = CharArraySet.unmodifiableSet(stopSet); * ENGLISH_STOP_WORDS_SET 被设置为不可更改的set集合 * Exception in thread "main" java.lang.UnsupportedOperationException * at org.apache.lucene.analysis.util.CharArrayMap$UnmodifiableCharArrayMap.put(CharArrayMap.java:592) * at org.apache.lucene.analysis.util.CharArraySet.add(CharArraySet.java:105) * at java.util.AbstractCollection.addAll(AbstractCollection.java:344) * at MyAnalyzer.<init>(AnalyzerDemo.java:146) * at MyAnalyzer.main(AnalyzerDemo.java:162) */ //stopWordSet = getStopWordSet(); stopWordSet = CharArraySet.copy(getStopWordSet()); stopWordSet.addAll(StopFilter.makeStopSet(stops)); } @Override protected TokenStreamComponents createComponents(String fieldName) { Tokenizer source = new LowerCaseTokenizer(); return new TokenStreamComponents(source, new StopFilter(source, stopWordSet)); } public static void main(String[] args) throws IOException { ArrayList<String> strings = new ArrayList<String>() {{ add("小鬼子"); add("美国佬"); }}; Analyzer analyzer = new StopAnalyzerExtend(strings); String content = "小鬼子 and 美国佬 are playing together!"; TokenStream tokenStream = analyzer.tokenStream("myfield", content); tokenStream.reset(); CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class); while (tokenStream.incrementToken()) { // 已经过滤掉自定义停用词 // 输出:playing together System.out.println(charTermAttribute.toString()); } tokenStream.end(); tokenStream.close(); } }
扩展停用词可以过滤掉一些敏感词。
下面我们在来看另外一个例子。自定义 Analyzer 实现字长过滤。
class LongFilterAnalyzer extends Analyzer { private int len; public int getLen() { return this.len; } public void setLen(int len) { this.len = len; } public LongFilterAnalyzer() { super(); } public LongFilterAnalyzer(int len) { super(); setLen(len); } @Override protected TokenStreamComponents createComponents(String fieldName) { final Tokenizer source = new WhitespaceTokenizer(); //过滤掉长度<len,并且>20的token TokenStream tokenStream = new LengthFilter(source, len, 20); return new TokenStreamComponents(source, tokenStream); } public static void main(String[] args) { //把长度小于2的过滤掉,开区间 Analyzer analyzer = new LongFilterAnalyzer(2); String words = "I am a java coder! Testingtestingtesting!"; TokenStream stream = analyzer.tokenStream("myfield", words); try { stream.reset(); CharTermAttribute offsetAtt = stream.addAttribute(CharTermAttribute.class); while (stream.incrementToken()) { System.out.println(offsetAtt.toString()); } stream.end(); stream.close(); } catch (IOException e) { } } }
自定义 Analyzer 要注意,Analyzer 里面的两个 tokenStream 方法是不能重写的。因为这两个方法是 final 方法,不能被覆盖的。
Analyzer 是一个抽象类,它要这样的设计其实就是一个装饰器模式,方便我们扩展!
学习一个新的框架,照葫芦画瓢可能是最快捷的方式!
: » Lucene 实战教程第九章自定义 Analyzer
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/251965.html