Lucene  create Index & (search Index)

上篇文章(Lucene (created Index) & search Index, http://blog.sina.com.cn/s/blog_740c74b20101ggho.html )已经介绍了Lucene建立索引的所有过程了,这章将介绍如何搜索(Search)。
涉及到的类是IndexSearcher,同样的你首先需要知道你之前建立索引的具体位置,然后通过搜索索引来找到你需要的信息。因此,在Search过程中你仍需要构建Directory,以及Directory阅读器(DirectoryReader),通过调用DirectoryReader将Directory的信息读入,以用于之后的搜索。当然你也需要分析器(Analyzer),用于对你输入的关键词进行解析。

一、 查询(Query)
在做完这些基础设置之后,接下来我们将进行对关键字的查询(query),你可以直接使用这个类进行查询,具体代码如下:
QueryParser parser = new QueryParser(Version.LUCENE_40,"FieldID", analyzer);
Query query = parser.parse("keyWord");
PS: QueryParser类是用来设置你所要进行搜索的Field(e.g. new Field("FieldID","Value")),以及采用什么样的分析器(Analyzer)进行解析。换句话讲,类似于Mysql语句查询,QueryParser是在定义你搜索的属性范围,即搜索某一列数据,以及相应的分析方法。

二、 其他查询方式
除了上述方法外,Lucene还有其他一些Query类,如:TermQuery,BooleanQuery,RangeQuery以及WildcardQuery等。
1、TermQuery
TermQuery是Lucene里面最基本的一种原子查询。一般可以通过它来检索索引中含有指定词条的Document。具体代码如下:
Term term = new Term("FieldID","keyWord");
Query termQuery = new TermQuery(term);
2、BooleanQuery
顾名思义,就是可附带逻辑关系的查询方法,你可以选择“或”,“与”之类的逻辑来查询你的关键字。具体代码如下:
Term term1 = new Term("FieldID","keyword1");
Term term2 = new Term("FieldID","keyword2");
TermQuery termquery1 = new TermQuery(term1);
TermQuery termquery2 = new TermQuery(term2);
BooleanQuery blquery = new BooleanQuery();
blquery.add(termquery1,BooleanClause.Occur.MUST);
blquery.add(termquery2,BooleanClause.Occur.MUST);
上面这串代码的意思就是两个关键字必须同时出现。
PS: 其中对于逻辑的选择除了 BooleanClause.Occur.MUST 外还有BooleanClause.Occur.MUST_NOT,
BooleanClause.Occur.SHOULD等等。
3、RangeQuery
也是顾名思义,范围查询,即在一定范围内进行查询,比如1~10范围,或者什么,当然你也可以尝试两段文字之间的范围查询(笔者没有尝试过)。下面是具体代码:
Term term1 = new Term("FieldID","keyword1");
Term term2 = new Term("FieldID","keyword2");
RangeQuery query = new RangeQuery(term1,term2,true);
PS: 这里解释一下RangeQuery构造函数最后一个参数的意义。它指的是是否包含边界值。

三、 Score相关介绍及查询结果展示
在介绍完查询方式之后,我们就可以对关键词进行相应的搜索了,在这里笔者特意想向大家介绍一下Lucene的一个特别有用的东西,即Score。对于每一条搜索的结果,Lucene都对其做出了相应的打分,以评价该搜索结果与关键词有多大的相关性(这是一个非常重要的功能)。打分的具体函数如下:



coord(q,d):  评分因子,是基于文档中出现查询项的个数。越多的查询项在一个文档中,说明该文档的匹配程序越高。默认是出现查询项的百分比。 
queryNorm(q):  查询的标准查询,使不同查询之间可以比较。此因子不影响文档的排序,因为所有有文档都会使用此因子。
tf(t in d):   查询的词在文档中出现的次数, 默认取根号值。
idf(t):  表示反转文档频率, 文档频率指出现查询词 的文档数。文档数越少 idf 就越高,但在同一个查询下些值是相同的。
t.getBoost():  激励因子,可以通过setBoost方法设置(通过field和doc都可以设置),即给查询词加权(一般不怎么使用)。
norm(t,d):  压缩几个索引期间的加权和长度因子。

PS:说白了就是一种打分机制:单个文档中出现的频率越高相关性越大,多个文档中都出现的话就没什么重要性了。

具体应用代码如下:
Hits hits = isearcher.search(query);
if(hits.length>0){
for(int i=0;i
Document hitDoc = hits.doc(i);
System.out.println("Score:"+hits.score(i)+"/"+hitDoc.get("FieldID"));
}
}

PS: 
(1)  isearcher 是 IndexSearcher 的一个对象,query就是之前定义的Query的一个对象。
(2) hits 中存储的是所有的搜索结果(其实还有另外一种表示方式,最后提供的全套代码里采用的就是另外一种方式)。
(3) hits.score(i)的意思就不用多说了吧~
(4) hitDoc.get("FieldID"),调用这个函数就能显示你所搜索的含有 关键词 的相关文段。


下面是完整代码:
package lxwo.lucenecore;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

public class SearchIndex {


private Analyzer analyzer;
private IndexSearcher isearcher;
private int MaxFieldsNum;

@SuppressWarnings("deprecation")
public SearchIndex(String path1, String path2) throws Exception {
// step1: initiate the directory of Index
Directory directoryHD = FSDirectory.open(new File(path1));
// step2: initiate the analyzer
analyzer = new StandardAnalyzer(Version.LUCENE_40);

// ============start searching=================================
// step1: initiate the IndexSearcher
DirectoryReader ireader = DirectoryReader.open(directoryHD);
isearcher = new IndexSearcher(ireader);

BufferedReader br = new BufferedReader(new FileReader(new File(path2)));
String strLine = null;
if ((strLine = br.readLine()) != null) 
this.MaxFieldsNum = Integer.valueOf(strLine);
br.close();
}

public void search(String keyWord) throws Exception {
// step2: initiate the QueryParser
for (int index = 0; index < this.MaxFieldsNum; index++) {
@SuppressWarnings("deprecation")
QueryParser parser = new QueryParser(Version.LUCENE_40,
index+"", analyzer);
// step3: customize the search query
Query query = parser.parse(keyWord);

// step4: searching
ScoreDoc[] hits = isearcher.search(query, 10000000).scoreDocs;
if(hits.length>0){
System.out.println("Fields:"+index+"/Hits: "+hits.length);
for(int i=0;i
Document hitDoc = isearcher.doc(hits[i].doc);
System.out.println("Score: "+hits[i].score+"/"+hitDoc.get(index+""));
}
}
}

}
public void searchAndWrite(String keyWord,File file) throws Exception {
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
// step2: initiate the QueryParser
for (int index = 0; index < this.MaxFieldsNum; index++) {
@SuppressWarnings("deprecation")
QueryParser parser = new QueryParser(Version.LUCENE_40,
index+"", analyzer);
// step3: customize the search query
Query query = parser.parse(keyWord);

// step4: searching
ScoreDoc[] hits = isearcher.search(query, 100000000).scoreDocs;
if(hits.length>0){
bw.append("Fields:"+index+"/Hits: "+hits.length);
bw.newLine();
for(int i=0;i
Document hitDoc = isearcher.doc(hits[i].doc);
bw.append("Score: "+hits[i].score+"/PMID: "+hitDoc.get("0")+"/Title: "+hitDoc.get("1"));
bw.newLine();
bw.append("Sentence: "+hitDoc.get(index+""));
bw.newLine();
}
}
}
bw.close();
}

}



big - PS:有些关键词例如:“AB/C”,“NOT”等等可能Lucene不好解析,需要再做一些处理,这里就暂时提一句,日后再详细解说。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值