分析(Analysis),在lucene中指的是将Field文本转换成最基本的索引表示单元——项(Term)的过程。
分析器对分析操作进行了若干封装。它通过执行若干操作,将文本转换成语汇单元,这些操作可能包括:提取单词、去除标点符号、去掉字母上面的音调符号、将字母转换为小写(也称为规范化)、去除常用词、将单词还原为词干形式(词干还原),或者将单词转换成基本形式(词性归并lemmatization)。这个处理过程也称为语汇单元化过程(tokenization),而从文本流中提取的文本块称为语汇单元(token)。语汇单元和它的域名结合后,就形成了项。
使用分析器
分析操作会出现在两个时间点:建立索引期间和使用QueryParser对象进行搜索时。
如果在搜索结果中高亮显示被搜索的内容,可能也用到分析操作。
WhitespaceAnalyzer 分析器通过空格来分割文本信息,而并不对生成的语汇单元统一为小写形式。
SimpleAnalyzer 首先通过非字母字符分割文本信息,然后将语汇单元统一为小写形式。需要注意的是,该分析器会去掉数字类型的字符。
StopAnalyzer: 该分析器功能与SimpleAnalyzer类似,区别在于,前者会去除常用单词(停用词)。
StandardAnalyzer:这是Lucene最复杂的核心分析器。它包含大量的逻辑操作来识别某些种类的语汇单元,比如公司名称、Email地址以及主机名称等。还会将语汇单元转换成小写形式,并去除停用词和标点符号。
索引过程中的分析
可以为每个文档指定分析器
QueryParser分析
解析VS分析:分析器何时不再适用
分析器:将域文本单元化
剖析分析器
Analyzer类是一个抽象类,是所有分析器的基类。它通过TokenStream类以一种很好的方式将文本逐渐转换为语汇单元流。
TokenStream类是什么样的?
有什么作用?
TokenStream 后续再回头看。
语汇单元的组成
语汇单元流是分析过程所产生的基本单元。在索引时,Lucene使用特定的分析器来处理需要被语汇单元化的域,而每个语汇单元相关的重要属性随即被编入索引中。
起点偏移量是指语汇单元文本的起始字符在原始文本中的位置,而终点偏移量则表示语汇单元文本终止字符的下一个位置。
偏移量对于在搜索结果中用高亮显示匹配的语汇单元非常有用。
一个语汇单元还有多个选择标志;一个标志即32比特数据集(以int型数值保存),Lucene内置的分析器不使用这些标志,但你自己设计的搜索程序是可以使用它们的。
此外,每个语汇单元都能以byte[]数组形式记录在索引中,用以指向有效负载。
语汇单元转换为项
当文本在索引过程中进行过分析后,每个语汇单元都作为一个项被传递给索引。位置增量、起点和终点偏移量和有效负载是语汇单元携带到索引中的唯一附加元数据。语汇单元的类型和标志位都被抛弃了——它们只在分析过程中使用。
位置增量
位置增量使得当前语汇单元和前一个语汇单元在位置上关联起来。一般来说位置增量为1,表示每个单词存在于域中唯一且连续的位置上。位置增量因子会直接影响短语查询和跨度查询,因为这些查询需要知道域中各个项之间的距离。
如果位置增量大于1,则允许语汇单元之间有空隙,可以用这个空隙来表示被删除的单词。
位置为0的语汇单元表示将语汇单元放置在前一个语汇单元的位置上。同义词分析器可以通过0增量来表示插入的同义词。
语汇单元流揭秘
Tokenizer对象通过java.io.reader对象读取字符串并创建语汇单元
TokenFilter则负责处理输入的语汇单元,然后通过新增、删除或修改属性的方式来产生新的语汇单元。
分析器链以一个Tokenizer对象开始,通过reader对象读取字符并产生初始语汇单元,然后用任意数量链接的TokenFilter对象修改这些语汇单元。
Lucene核心API提供的分析器构建模块
类名 | 描述 |
TokenStream | 抽象Tokenizer基类 |
Tokenizer | 输入参数为Reader对象的TokenStream子类 |
CharTokenizer | 基于字符的Tokenizer父类,包含抽象方法isTokenChar()。当isTokenChar()为true时输出连续的语汇单元块。该类还能将字符规范化处理(如转换为小写形式)。输出的语汇单元所包含的最大字符数为255 |
WhitespaceTokenizer | isTokenizer()为true时的CharTokenizer类,用于处理所有非空格字符 |
KeywordTokenizer | 将输入的整个字符串作为一个语汇单元 |
LetterTokenizer | isTokenizer()为true,并且Charater.isLetter为true时CharTokenizer类 |
SinkTokenizer | |
StandardTokenizer | |
TokenFilter | |
LowerCaseFilter将语汇单元转换成小写形式 | |
StopFilter | |
PorterStemFilter | |
TeeTokenFilter | |
ASCIIFoldingFilter | |
CachingTokenFilter | |
LengthFilter | |
StandardFilter | |
观察分析器
TermStream staream = analyzer.tokenStream("contents", new StringReader(text));//由分析器得到词法分析器
TermAttribute term = stream.addAttribute(TermAttribute.class);//打印语汇单元
while(stream.incrementToken()){//递归所有语汇单元
System.out.println("[" + term.term() + "]");
}
TokenStream stream = analyzer.tokenStream("contents", new StringReader(text));
TermAttribute term = stream.addAttribute(TermAttribute.class);
PositionIncrementAttribute posIncr = stream.addAttribute(PositionIncrementAttribute.class);
OffsetAttribute offset = stream.addAttribute(OffsetAttribute.class);
TypeAttribute type = stream.addAttribute(TypeAttribute.class);
属性
需要注意的是,TokenStream永远不会显式创建包含所有语汇单元属性的单元对象。
语汇单元属性接口 | 描述 |
TermAttribute | 语汇单元对应的文本 |
PositionIncrementAttribute | 位置增量 |
OffsetAttribute | 起始字符和终止字符的偏移量 |
TypeAttribute | 语汇单元类型(默认为单词) |
FlagsAttribute | 自定义标志位 |
PlayloadAttribute | 每个语汇单元的byte[ ]类型有效负载 |
语汇单元过滤器:过滤顺序的重要性
使用内置分析器
分析器 | 内部操作步骤 |
WhitespaceAnalyzer | 根据空格拆分语汇单元 |
SimpleAnalyzer | 根据非字母字符拆分文本,并将其转换为小写形式 |
StopAnalyzer | 根据非字母字符拆分文本,然后小写化,并移去停用词 |
KeywordAnalyzer | 将整个文本作为一个单一语汇单元处理 |
StandardAnalyzer |
StopAnalyzer
StandardAnalyzer
应当采用哪种核心分析器
solrconfig.xml文件中以xml格式直接定义分析链表达式。
近音词查询
同义词、别名和其他表示相同意义的词
词干分析
StopFilter保留空位
合并词干操作和停用语移除操作
域分析
多值域分析
继承Analyzer 重写getPositionIncrementGap
特定域分析 //针对特定域指定分析器
PerFieldAnalyzerWapper analyzer = new PerFieldAnalyzerWrapper(new SimpleAnalyzer());
anzlyzer.addAnalyzer("body", new StandardAnalyzer(Version.LUCENE_30))
搜索未被分析的域
多值域需要设置位置增量空隙,以避免程序误对各个值域连接处的文本进行匹配操作
PerFieldAnalyzerWapper则让我们能够自定义为各个域分配对应的分析器
语言分析
Unicode与字符编码
非英语语种分析
字符规划化处理
亚洲语种分析
有关非英语语种分析的其他的问题
Nutch分析