您的位置:首页 > 其它

lucene学习笔记之Analyzer和Search

2012-09-12 15:49 411 查看
为应用程序添加搜索功能

Lucene主要的搜索API



目的

IndexSearcher

所有搜索通过IndexSearcher进行,它们会调用该类中重载的search方法

Query(及其子类)

Query实例将被传递给IndexSearcher的search方法

QueryParser

将用户输入的查询表达式处理成具体的Query对象

TopDocs

保持有IndexSearcher.search()返回的较高评分的顶部文档

ScoreDoc

提供对TopDocs中每条搜索结果的访问接口

3.1.2 解析用户输入的查询表达式:QueryParser



如图QueryParser类需要一个分析器把查询语句分割成多个项。

3.2 使用IndexSearcher类

Directory dir = FSDirectory.open(new File("/path/to/index"));

IndexReader reader = IndexReader.open(dir);

IndexSearcher searcher = new IndexSearcher(reader);

Directory类负责提供文件属性的抽象API,IndexReader使用该API与存储与索引中的索引文件进行交互,并提供底层API以供IndexSearcher用于搜索,IndexSearcher的API接受Query对象以用于搜索,并返回TopDocs对象以展现搜索结果。需要注意的是,由于IndexReader完成了打开所有索引文件和提供底层reader API等繁重的工作,需要较大的系统开销,所以最好是在所有搜索期间都重复使用同一个IndexReader实例。

3.2.2 实现搜索功能

3.2.3使用TopDocs类

TopDocs方法或属性

返回值

totalHits()

匹配搜索条件的文档数量

scoreDocs

包含搜索结果的ScoreDoc对象数组

getMaxScore()

如果已完成排序则返回最大评分

3.3 理解lucene评分机制

3.3.1 lucene如何评分



分值计算方式为查询语句(q)中每个项(t)与文档(d)的匹配分值之和

评分公式中的因子:

评分因子

描述

tf(t in d)

文档d中出现t的频率

idf(t)

反文档频率

boost(t.field in d)

域和文档的加权,索引期间可以对域或文档进行静态加权

lengthNorm(t.field in d)

域的归一化值

coord(q,d)

协调因子(Coordination factor)

queryNorm(q)

每一个查询的归一化值,指每一个查询权重的平方和

3.5解析查询表达式:QueryParser

Lucene分析过程

4.1 使用分析器

对lucene核心来说分析操作会出现在两个时间点:建立索引期间和使用QueryParser对象进行搜索时。

WhitespaceAnalyzer:通过空格来分割文本,而不对生成的语汇单元进行其他的规范化处理。

SimpleAnalyzer:该分析器首先通过非字母字符来分割文本信息,然后将语汇单元同意为小写,该分析器会去掉数字类型的字符,但会保留其他字符。

StopAnalyzer:与上面类似,但它会去掉常用单词(the ,a )

StandardAnalyzer:它包含大量的逻辑操作来识别某些种类的语汇单元,它还会将语汇单元转换成小写形式,并去掉停用词和标点符号。

4.1.1索引过程中的分析

在用IndexWriter实例索引文档时,一般通过默认的分析器来分析文档中的每个域,也可根据某个文档需要用特殊分析器,IndexWriter类的addDocument方法和updateDocument方法都允许为某个文档选择对应的分析器。

4.1.2 QueryParser分析

在实例化QueryParser对象时,同样需要传入一个分析器对象:

QueryParser parser = new QueryParser(Version.LUCENE_30,"contents",analyzer);

Query query = parser.parse(expression);

分析器会接收表达式中连续的独立文本片段,但不会接收整个表达式。如:"president obama" + harvard + professor

QueryParser会3次调用分析器,首先处理文本“president obama”然后是文本“harvard”,最后是“professor”,对全部文本进行的是同样的分析。

分析器不能用于从文档中分离和提取域,因为它的职责是每次处理一个域,所以为了对域进行分离,就要在分析之前预先解析这些文档。

4.2.2 语汇单元流揭秘

TokenStream是一个能在被调用后产生语汇单元序列的类,但它有两个不同的类型:Tokenizer类和TokenFilter类,前者通过java.io.Reader对象读取字符并创建语汇单元,而TokenFilter负责处理输入的语汇单元,然后通过新增,删除或修改属性的方式来产生新的语汇单元。





分析链以一个Tokenizer对象开始,通过Reader对象读取字符并产生初始语汇单元然后用任意数量链接的TokenFilter对象修改这些语汇单元。

4.2.3观察分析器

语汇单元所携带的属性:

项(term),位置增量(position-Increment),偏移量(offset),类型(type),标志位(flags),和有效负载。

属性:

TokenStream继承了类AttributeSource并生成了子类,AttributeSource是一个使用方法,他能在程序非运行期间提供增强类型并且能够完全扩展的属性操作。

语汇单元属性接口

描述

TermAttribute

语汇单元对应的文本

PositionIncrementAttribute

位置增量

offsetAttribute

起始字符和终止字符的偏移量

TypeAttribute

语汇单元类型(默认为单词)

FlagsAttribute

自定义标志位

PayloadAttribute

每个语汇单元的byte[]类型有效负载

首先可以通过调用addAttribute方法来获取需要的属性,该方法会返回一个实现对应接口的具体类,然后,你可以通过调用TokenStream.incrementToken()方法来递归访问所有的语汇单元,然后你就可以与先前获取的属性对象进行交互来得到针对每个语汇单元的属性值,代码如下:

Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_36);
TokenStream ts = analyzer.tokenStream("text", new StringReader(s));
TermAttribute ta = ts.addAttribute(TermAttribute.class);
PositionIncrementAttribute tb = ts.addAttribute(PositionIncrementAttribute.class);
OffsetAttribute tc = ts.addAttribute(OffsetAttribute.class);
TypeAttribute td = ts.addAttribute(TypeAttribute.class);
while(ts.incrementToken()){
System.out.print(ta.term()+" "+tb.toString()+" "+tc.toString()+" "+td.type());
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: