Api
Lucene
传入Lucene用于构建索引的纯文本,通常会进行令牌化(tokenization)的过程。令牌化是把输入文本拆分成多个小索引元素的过程,这些元素成为令牌(tokens)。输入文本被分解为令牌的方式在很大程度上影响后面如何搜索该文本。例如,可以识别语句的开头和结尾以提供更准确的短语和相似度搜索(Lucene不提供句子识别)。
在某些情况下,仅将输入文本拆分成令牌是不够的,可能需要更深入的分析。Lucene提供标记前和标记后的分析工具。
标记前工作,比如剥离HTML标签,转换、删除任意匹配的模式串。
笔记后的工作,比如:
Stemming 词干提取,使用词干替换单词。在语言形态学和信息检索中,词干提取是将变形的(或有时衍生的)词还原为词干,基词或词根形式(通常是书面词形式)的过程。
Stop Words Filtering 停用词过滤,减少索引量和噪音。停用词是在处理自然语言数据(文本)之前或之后过滤掉的词。
Text Normalization 文本规范化,是将文本转换为单一规范形式的过程。
Synonym Expansion 同义词扩展。
Packages
用于将文本转换为可可索引、可搜索标记的库,包括Analyzer
及相关类。analysis包提供了将Strings和Readers转换为Lucene可以索引的令牌的机制。该包包含四个主要类,所有分析过程由他们派生出来。
Analyzer
用于提供索引和搜索过程可消费的TokenStream
。CharFilter
CharFilter扩展了Reader在令牌化文本前的转换过程,同时为这些更改提供正确的字符偏移量。当索引令牌从CharFilter创建时,该能力允许高亮显示应用在原始文本上。修改后的文本,其偏移量与原始文本中的偏移量不同。多个CharFilter
可以串联,来执行多个令牌化前的修改操作。Tokenizer.setReader(java.io.Reader)
接受CharFilter
。TokenFilter
TokenFilter
是一个TokenStream
,用于修改Tokenizer创建的令牌。TokenFilter常见的修改操作有删除、词干提取、同义词注入。并不是所有的Analyzer
都需要TokenFilter。
定义抽象Analyzer
API,用于将Reader
转换为TokenStream
。多个TokenFilter
应用于Tokenizer
的输出组成TokenStream
。Tokenizers
和TokenFilters
绑定,和 Analyzer
一起使用。analyzers-common 提供了多种Analyzer实现,包括StopAnalyzer 和基于语法的 StandardAnalyzer。
TokenStream
罗列了一系列的token,来自Document
的Field
或者查询文本,TokenStream
是一个抽象类,具体的实现有两个,Tokenizer
和 TokenFilter
。Tokenizer
的输入来自Reader
, TokenFilter
的输入来自另外一个TokenStream。
提供了对倒排索引结构的编码和解码的抽象,以及可以根据应用程序需求选择的不同实现。
提供一个简单的Document类。Document只是一组命名字段,其值可以是字符串或Reader的实例。
提供了两个主要的类,IndexWriter
用于创建索引并将文档添加到索引;IndexReader
,用于访问索引中的数据。
提供用于查询的数据结构,比如TermQuery
用于别词,PhraseQuery
用于词组,BooleanQuery
用于查询的逻辑组合。IndexSearcher
将查询转换为 TopDocs
,提供多种 QueryParser 用于从字符串或者xml生成查询结构。
定义了抽象类 Directory
,用于持久保存数据,保存了文件名的集合,供IndexOutput
写或IndexInput
读。同时提供了多种实现 ,推荐使用 FSDirectory
,它尝试高效地使用系统磁盘缓冲区。
包含一些方便的数据结构和util类,比如 FixedBitSet
和 PriorityQueue
。
Steps
通过添加
Fields
创建Documents
创建
IndexWriter
,并通过addDocument
添加Document
调用 [QueryParser.parse()](https://lucene.apache.org/core/8_5_2/queryparser/org/apache/lucene/queryparser/classic/QueryParserBase.html#parse(java.lang.String)) 从字符串构造请求
创建
IndexSearcher
,将构造的请求对象通过search()
方法传入
Hints, Tips and Traps
Analyzer
、 CharFilter
、 Tokenizer
、 TokenFilter
的关系很容易迷惑。
Analyzer
是分析链的工厂,Analyzer
不处理文本,它构造用于处理文本的CharFilter
、Tokenizer
或者TokenFilter
。Analyzer有两个任务:创建TokenStream
,用于接受reader、产生tokens、包装或者预处理Reader对象。CharFilter是Reader的子类,它支持偏移量跟踪。
Tokenizer
仅负责将输入文本分解为tokens。TokenFilter
修改令牌流(stream of tokens)及其内容。Tokenizer
是TokenStream
,但Analyzer
不是。
如果想要使用特定的CharFilter
、Tokenizer
、TokenFilter
组合,最简单的事情是使用Analyzer
的匿名类,提供Analyzer.createComponents(String)
、 Analyzer.initReader(String, java.io.Reader)
。Lucene提供很多Analyzer提供有用的分析链,其中最常用的是StandardAnalyzer。analyzers-common库为多种语言提供了analyzers,同时允许配置自定义Analyzer。
除了StandardAnalyzer,Lucene包含多种组件,包括分析组件,他们在analysis文件夹下。其中一些支持特定语言,另一些集成外部组件。common文件夹有一些值得注意的通用分析器,包括 PerFieldAnalyzerWrapper,多数Analyzer
在所有的Field
上执行相同的操作。PerFieldAnalyzerWrapper可用于将不同的分析器与不同的字段关联。
分析器是构造索引缓慢的主要原因之一。
benchmark对测试分析进程效率非常有帮助。
Invoking the Analyzer
应用程序通常不需要调用分析器,交由Lucene来做。
索引构建阶段,
addDocument(doc)
时对索引有效的分析器会被调用,应用于添加的文档的每个索引字段。搜索阶段,QueryParser有可能在解析阶段调用Analyzer,有些搜索可能不会有分析操作。
应用可以这样执行分析器,用于测试或者其他目的。
Version matchVersion = Version.LUCENE_XY; // Substitute desired Lucene version for XY
Analyzer analyzer = new StandardAnalyzer(matchVersion); // or any other analyzer
TokenStream ts = analyzer.tokenStream("myfield", new StringReader("some text goes here"));
// The Analyzer class will construct the Tokenizer, TokenFilter(s), and CharFilter(s),
// and pass the resulting Reader to the Tokenizer.
OffsetAttribute offsetAtt = ts.addAttribute(OffsetAttribute.class);
try {
ts.reset(); // Resets this stream to the beginning. (Required)
while (ts.incrementToken()) {
// Use AttributeSource.reflectAsString(boolean)
// for token stream debugging.
System.out.println("token: " + ts.reflectAsString(true));
System.out.println("token start offset: " + offsetAtt.startOffset());
System.out.println(" token end offset: " + offsetAtt.endOffset());
}
ts.end(); // Perform end-of-stream operations, e.g. set the final offset.
} finally {
ts.close(); // Release resources associated with this stream.
}
Indexing Analysis vs. Search Analysis
选择正确的分析器对于搜索质量至关重要,也会影响索引、搜索性能。对于应用程序来说,正确的分析器取决于输入文本以及解决什么样的问题,这里有一些经验指导:
测试
过多的分析器可能会影响索引性能
索引、搜索过程从相同的分析器开始,否则搜索的时候可能不知道目的是什么...
在某些情况下,需要使用其他分析器进行索引和搜索
某些搜索需要过滤更多停用词
构造自己的分析器和分析组件
构造自己的分析器是最直接的,自定义分析器应该是Analyzer
的子类,它可以使用现有的分析组件CharFilter、Tokenizer、TokenFilter、自定义组件。
字段剖面边界
对相同的field多次调用 document.add(field)
,我们说每次调用创建会为该字段创建一个剖面(section),实际上针对这些切面,会单独调用tokenStream(field,reader)
。但是默认的Analyzer行为是把这些剖面当做一个大的剖面,这允许词组搜索和相似搜索可以无缝跨越这些剖面(sections)的边界。比如,像这样添加f
字段。
document.add(new Field("f","first ends",...);
document.add(new Field("f","starts two",...);
indexWriter.addDocument(document);
然后,词组搜索ends starts
会找到那篇文章。如果需要,可以通过在连续的字段剖面之间引入位置间隙来修改此行为,只需覆盖Analyzer.getPositionIncrementGap(fieldName)
即可。
Version matchVersion = Version.LUCENE_XY; // Substitute desired Lucene version for XY
Analyzer myAnalyzer = new StandardAnalyzer(matchVersion) {
public int getPositionIncrementGap(String fieldName) {
return 10;
}
};
Reference
最后更新于
这有帮助吗?