您的位置:首页 > 其它

搜索那些事――细谈lucene(三)lucene核心API简介

2013-10-19 10:55 381 查看
经过前面的简单理论介绍,相信大家对搜索引擎lucene有个简单的了解。前面我们也提到过在lucene中主要包括索引和搜索这两大方面的组件。今天我们我们就通过一个简单的实例来看一下lucene给我们提供的有关这两个组件的简单用法。
一:创建索引在用lucene搜索之前,我们首先要做的就是是创建索引,只有有索引了,我们才有了搜索的对象,下面我们就根据一个创建索引的小demo来一步步分析一下创建索引的步骤:
public class Indexer {
private IndexWriter writer = null;
public Indexer(String indexDir) throws Exception {
Directory dir = FSDirectory.open(new File(indexDir));//打开保存索引目录
writer = new IndexWriter(dir, new StandardAnalyzer(Version.LUCENE_30),
true, IndexWriter.MaxFieldLength.UNLIMITED);//创建lucene IndexWriter,创建索引工具
}

public void close() throws Exception
{
writer.close();
}
public int index(String dataDir, FileFilter filter) throws Exception {
File[] files = new File(dataDir).listFiles();
for (File file : files) {//遍历文件目录下所有txt文件,把文件加入索引
if (!file.isDirectory() && !file.isHidden() && file.exists()
&& (filter == null || filter.accept(file))) {
indexFile(file);
}
}
return writer.numDocs();
}
private Document getDocument(File f) {
Document doc = new Document();
try {
doc.add(new Field("content", new FileReader(f)));
doc.add(new Field("fileName", f.getName(), Field.Store.YES,
Field.Index.NOT_ANALYZED));
doc.add(new Field("filePath", f.getCanonicalPath(),
Field.Store.YES, Field.Index.NOT_ANALYZED));
} catch (Exception e) {
e.printStackTrace();
}
return doc;
}
public void indexFile(File f) throws Exception {
System.out.println("make index file is " + f.getCanonicalPath());
Document doc = getDocument(f);//创建文件document
writer.addDocument(doc);//把当前文件document加入索引
}
public static void main(String[] args) throws Exception {
String indexDir = "d:\\";// 创建索引的目录
String dataDir = "d:\\a\\";// 创建文件目录
long begin = System.currentTimeMillis();
Indexer index = new Indexer(indexDir);
int numIndexed;
numIndexed = index.index(dataDir, new TextFilesFilter());
long end = System.currentTimeMillis();
index.close();
System.out.println("all make index num is:"+numIndexed+" use time :"+(end-begin));
}
}
class TextFilesFilter implements FileFilter
{
public boolean accept(File file)
{
return file.getName().toLowerCase().endsWith(".txt");
}
}


从上面demo中的注释中相信大家也差不多也能看懂大体意思。下面我们还是从main函数一步步的看一下吧1. 首先根据构造方法创建实例对象时创建索引器indexWriter。这是创建索引时用到的一个主要类,在下面我们会详细降到。2. 创建完索引器之后,根据指定的文件目录遍历所有符合要求的文件,然后对每一个文件创建一个Document对象。3. 把创建的document对象加入索引器进行索引。上面只是大体的介绍了一下整个索引步骤,有些细节我没有提到,相信大家也很容易看懂。比如床架文件过滤fiter之类的操作。Ok,写到这里,我们就来看一下运行这个创建索引程序能看到什么结果吧。



运行之后,我们会发现,在我们制定的索引文件夹下会多出以下几个文件:这几个文件具体是什么东东,其实我也不知道,也许以后慢慢的会研究到这些索引文件的内容:

二:搜索相关Ok,索引内容我们就简单介绍到这,下面我们来看一下lucene中搜索方面的简单实现,还是以一段简单的代码来认识一下:
public class Searcher {

public static void main(String[] args) throws Exception {
String indexDir = "d:\\index";// 创建索引的目录
System.out.println("请输入您要搜索的关键字:");
Scanner scanner = new Scanner(System.in);
String queryStr = scanner.next();
Search(indexDir,queryStr);
}
public static void Search(String indexDir, String queryStr) throws Exception
{
Directory dir = FSDirectory.open(new File(indexDir));
IndexSearcher searcher = new IndexSearcher(dir);
QueryParser parser = new QueryParser(Version.LUCENE_30,"content",new StandardAnalyzer(Version.LUCENE_30));
Query query = parser.parse(queryStr);
long begin = System.currentTimeMillis();
TopDocs hits = searcher.search(query, 10);
long end = System.currentTimeMillis();
System.out.println("search the word: "+queryStr+".  all search use time is:"+(end-begin)+"。 and get result num is : "+hits.totalHits);
for(ScoreDoc doc :hits.scoreDocs)
{
Document document = searcher.doc(doc.doc);
System.out.println(document.get("filePath"));
}
}
}
下面还是简单说一下实现的基本过程:1. 首先打开索引文件,然后输入要搜索的关键字2. 创建索引搜索器IndexSearcher,创建查询条件QueryParser3. 利用查询字符串解析字符串在索引返回Query对象。4. 调用indexsearcher的search方法进行查询,返回TopDocs对象。5. 遍历查询得到的结果。
运行一下这个searcher我们会得到以下结果:



当然了。我们这里只是做一个小小的demo来学习lucene的搜索组件,读者自己可以做成web应用程序类型或者桌面应用的类型。这里我们只是简单的实现后端代码。搜索过程就在控制台简单实现一下。有兴趣的读者可以美化一下。这里我们也只是简单的搜索了一个关键字,也没有进行分词之类的,在以后的文章中我们会慢慢完善,一点点与应用搜索引擎靠近。
三、索引过程中的核心类
1. IndexWriter(写索引)是索引过程中的核心类。这个类负责创建新索引或者打开已有索引,以及向索引中添加、删除或者更新被索引文档的信息。其实这个类可以这样理解,它就是对索引中的内容进行CRUD的。但不能进行读取或者搜索。可以改变索引里面的内容。2. Directrory类描述了lucene索引的存放位置。这个类是一个抽象类,它的子类负责实现指定具体的索引位置。在上面的例子中我们用FSDirectory.open方法来获取真实文件在文件系统的存储路径。3. Analyzer:IndexWriter不能直接索引文本,这需要先由Analyzer类将文本进行分词。我们看一下在Lucenein Action 这本书中对lucene的介绍:



4. Document:document对象是指一组域的集合,其实他是指一个虚拟的文档。这里的文档是我们从很多类型文件中(比如web页面,邮件内容)中提取相关信息组成的一些元数据。一个Document 对象由多个Field 对象组成的。可以把一个Document 对象想象成数据库中的一个记录,而每个Field 对象就是记录的一个字段。5. Filed索引中的每个文档都包含一个或多个不同命名的域。这些域都包含在field的类中。每个域都有一个域名和对应的域值。就和键值对类似。也就是说Field对象是用来描述一个文档的某个属性的,比如一封电子邮件的标题和内容可以用两个Field 对象分别描述。
四、搜索过程的核心类1. IndexSearcher:这个类类似于一个搜索组件的大管家,负责对索引的搜索。它只能以只读的方式打开一个索引,所以可以有多个IndexSearcher 的实例在一个索引上进行操作。利用其search方法可以把query类封装好的查询关键字和条件进行查询。一个典型的应用实例:



2. Term 是搜索的基本单位,这个类主要有查询域名和域值组成。一个Term 对象有两个String 类型的域组成。生成一个Term 对象可以有如下一条语句来完成:Term term = newTerm(“fieldName”,”queryWord”); 其中第一个参数代表了要在文档的哪一个 Field 上进行查找,第二个参数代表了要查询的关键词。3. Query:此类主要是一个查询类的综合,类中可以指定查询域和一些查询条件。这算是一个查询父类,它有很多子类。最常用的实现类是TermQuery。其余它还有一些BooleanQuery、TermRangeQuery、FiteredQuery等类。4. TermQuery:TermQuery 是抽象类 Query 的一个子类,它同时也是 Lucene 支持的最为基本的一个查询类。生成一个 TermQuery 对象由如下语句完成: TermQuerytermQuery = new TermQuery(new Term(“fieldName”,”queryWord”)); 它的构造函数只接受一个参数,那就是一个 Term 对象。5.Hits 是用来保存搜索的结果的。在搜索完成之后,需要把搜索结果返回并显示给用户,只有这样才算是完成搜索的目的。在lucene中,搜索的结果的集合是用hits类的实例来表示的。这里再提一下hits,这也是lucene比较精彩的地方,熟悉hibernate的朋友都知道hibernate有一个延迟加载的属性,同样,lucene也有。hits对象也是采用延迟加载的方式返回结果的,当要访问某个文档时,hits对象就在内部对lucene的索引又进行一次检索,最后
才将结果返回到页面显示。hits对象中主要方法有:
length(): 返回搜索结果的总数,下面简单的用法中有用到hit的这一个方法
doc(int n): 返回第n个文档
iterator(): 返回一个迭代器
6.TopDocs: 搜索结果的容器。TopFieldDocs是其派生类,也是存放搜索结果的容器。他是一个简单的指针容器。指针一般指向排名前N项的搜索结果。
OK,以上就是我们简单的对Lucene常用核心类的功能简单说了一下,在以后的文章中几乎每个类我们都会仔细的研究的,甚至应该会读一下他的源码。所以,有些内容弄不明白大家不用着急。欲知更多精彩内容,欢迎继续关注本博。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: