Lucene中的Analyzer
为了更好地搜索中文,先通过图4-2了解一下在Lucene中通过WhitespaceTokenizer、WordDelimiter Filter、LowercaseFilter处理英文字符串的流程。
图4-2 Lucene处理英文字符串流程 |
Lucene中的StandardAnalyzer对于中文采用了单字切分的方式,这样的结果是单字匹配,如搜索"上海",可能会返回和"海上"有关的结果。
CJKAnalyzer采用了二元覆盖的方式实现。小规模搜索网站可以采用二元覆盖的方法,这样可以解决单字搜索"上海"和"海上"混淆的问题。采用中文分词的方法适用于中大规模的搜索引擎。猎兔搜索提供了一个基于Lucene接口的Java版中文分词系统。
可以对不同的索引列使用不同的Analyzer来切分。例如可以对公司名采用CompanyAnalyzer来分析;对地址列采用AddressAnalyzer来分析。这样可以通过更细分化的切分方式来实现更准确合适的切分效果。
例如把"唐山聚源食品有限公司"拆分成如表4-1所示的结果。
表4-1 公司名拆分结果表
词 |
开始位置 |
结束位置 |
标注类型
扫描二维码关注公众号,回复:
618338 查看本文章
|
唐山 |
0 |
2 |
City |
聚源 |
2 |
4 |
KeyWord |
食品 |
4 |
6 |
Feature |
有限公司 |
6 |
10 |
Function |
这里的开始位置和结束位置是指词在文本中的位置信息,也叫做偏移量。例如"唐山"这个词在"唐山聚源食品有限公司"中的位置是0-2。OffsetAttribute属性保存了词的位置信息;TypeAttribute属性保存了词的类型信息。
切分公司名的流程如图4-3所示。
图4-3 Lucene处理公司名流程 |
专门用来处理公司名的CompanyAnalyzer实现代码如下所示:
- public class CompanyAnalyzer extends
- Analyzer {
- public TokenStream tokenStream
- (String fieldName, Reader reader) {
- //调用ComTokenizer切分公司名
- TokenStream stream = new
ComTokenizer(reader); - //调用ComFilter后续加工
- stream = new ComFilter (stream);
- return stream;
- }
- }
对不同的数据写了不同用途的分析器,需要在同一个索引中针对不同的索引列使用。一般情况下只使用一个分析器。为了对不同的索引列使用不同的分析器,可以使用PerFieldAnalyzerWrapper。在PerFieldAnalyzerWrapper中,可以指定一个默认的分析器,也可以通过addAnalyzer方法对不同的列使用不同的分析器,例如:
- PerFieldAnalyzerWrapper aWrapper =
- new PerFieldAnalyzerWrapper(new CnAnalyzer());
- aWrapper.addAnalyzer("address", new AddAnalyzer());
- aWrapper.addAnalyzer("companyName",
new CompanyAnalyzer());
在这个例子中,将对所有的列使用CnAnalyzer,除了地址列使用AddAnalyzer且公司名称列使用CompanyAnalyzer。像其他分析器一样,PerFieldAnalyzerWrapper可以在索引或者查询解析阶段使用。