如果您想了解Lucene搜索流程(2.IndexReader)的相关知识,那么本文是一篇不可错过的文章,我们将对lucene搜索原理进行全面详尽的解释,并且为您提供关于IndexReader.getF
如果您想了解Lucene搜索流程(2.IndexReader)的相关知识,那么本文是一篇不可错过的文章,我们将对lucene搜索原理进行全面详尽的解释,并且为您提供关于IndexReader.getFieldNames Lucene 4、Lucene 4.x 之 IndexReader、lucene Creating an Index、Lucene index and search的有价值的信息。
本文目录一览:- Lucene搜索流程(2.IndexReader)(lucene搜索原理)
- IndexReader.getFieldNames Lucene 4
- Lucene 4.x 之 IndexReader
- lucene Creating an Index
- Lucene index and search
Lucene搜索流程(2.IndexReader)(lucene搜索原理)
上一篇说到了Directory为我们搜索提供了基础,下面我们就要开始打开这个Directory了。
用IndexReader打开一个Directory还是包含了不少细节的,下面我们一起来探讨下
首先IndexReader其实是一个abstract的类,所以我们打开不可能实例化这个类,那我们打开一个FSDreictory究竟打开的是啥呢?看看下面这断代码就明了了
public static IndexReader open(final Directory directory) throws CorruptIndexException, IOException {
return DirectoryReader.open(directory, null, null, true, DEFAULT_TERMS_INDEX_DIVISOR);
}
IndexReader里面还有很多个open方法的重载版本,其实就是调用了DirectoryReader.open了,这个DirectoryReader是个啥玩意呢,我们去探探究竟。看名字就很简单,这个DirectoryReader就是用来打开一个Directory的嘛,但是有的童鞋要问了,lucene里面的索引不都是保存在Directory里面吗?不就是用DirectoryReader就行了么?
这个嘛,其实lucene在搜索的时候为了将搜索任务细分到不同的Reader(比如并行搜索),因此在DirectoryReader里面其实是有很多的子Reader的,这里就是SegmentReader(段索引Reader)了,这个就是最终的底层Reader了,所有的操作都是通过它来进行的,在open一个目录的时候,会读取索引文件里面的segment_*这个文件的相关信息,得出这个目录里面的索引断详细信息,然后每个段都会打开一个SegmentReader,单独负责这个断的信息读取,我们最终的所有的索引搜索操作就都是由他们完成了,这样做的目的前面我也说了,我们可以用一个线程池,然后再每个断上用一个线程对其进行搜索,然后将结果合并起来,这样是不是提高了很大的效率,其实lucene就用这样的功能的,这个等我们说到IndexSearcher的时候再细说。
然后根据是否可以用这个Reader可以进行索引写操作,还有ReaderOnlySegmentReader。我们知道可以通过IndexReader来删除文档,用了ReaderOnly的IndexReader的话就相当于将这一操作给禁止了,相信用过luke的童鞋都知道luke有个以只读模式打开索引的选项,其实就是用的这个IndexReader,这里啰嗦一句,其实我也建议大家不要用IndexReader对索引进相关的操作,因为涉及到了锁和并发各方面的原因,结果也许会出现不可预想的后果(比如索引损坏),那个时候就只有哭了T_T,而且读和写分开,对我们的程序的设计有很大的方便,听说在4.0里面已经不能再IndexReader里面删除了,不知道是不是真的?
下面来介绍几个IndexReader的重要方法:
public TermEnum terms();
这个方法的作用是获取一个所有索引里面保存的词的一个枚举,通过这个枚举我们可以用类似while循环获取这个索引里面保存的所有的分词信息(不是保存的信息,是一个字段通过分词器分词后的词信息),这个方法有大用,以后我们讲查询的时候详细再说。
public TermEnum terms(Term t) throws IOException ;
这个方法和上面的类似,但是这个方法可以通过一个词(Term)对要获取的词进行定位,比如索引中存在如下词
Field:0
Field:1
Field:2
Field:3
Field:4
如果这里我们传入一个new Term("Field","3")的话,就可以获得一个从(Filed:4)开始的词枚举。
如果传入的词不存在呢?如果不存在。Lucene会找到一个比我们传入的词大的词,这个大是怎么解释呢,其实就是Term实现了Comparable接口,然后compareTo返回大于或等于1的就行了,这个方法也是非常重要的,对查询重写有很大的意义,这里暂时也还是不讲。
下面看看这两个方法:
public TermDocs termDocs() throws IOException
public TermDocs termDocs(Term term) throws IOException;
这两个方法的作用从词义上将就是获取一个文档枚举器,我们当然同样可以通过这个枚举获取这个Reader里面读取的文档ID号,这里为啥不是目录而是Reader里面的呢?因为我们知道文档ID只有在索引打开的时候存在,只存在于运行时,并不是一个持久化的标示符。上面那个方法和下面那个方法的区别在于,上面的方法或得得TermDocs并不能直接使用,因为是未定位的(unposition),在使用前我们要先使用seek来定位,下面则可以直接通过一个词来定位指定的文档,Lucene的索引保存方式是以倒排表的方式来存储的,因此可以通过这个词来快速定位包含这个词的文档,这个方法就是这种倒排表的体现,另外这两个方法获取出来的文档都是不包含已经删除的文档的哦。
public int maxDoc();
public int numDocs()
这两个方法也是两兄弟,上面按个方法是获取比当前索引中的最大的那个文档号还要大1的一个int值,下面那个下面按个一般来说就是调用上面那个方法然后减去已经删除掉的文档的数量,就是这个索引包含的全部的文档的数量,两个的区别在于定义上上面一个是获取最大的文档号,下面只是获取文档的数量。
最后两个方法
public abstract Document document(int n, FieldSelector fieldSelector) throws CorruptIndexException, IOException;
public final Document document(int n) throws CorruptIndexException, IOException ;
最后两个方法也是我们的重中只重了,光能搜索不行,我们还要获取我们保存在索引里面的相关信息,这个两个方法就是通过一个文档ID来获取指定文档保存的信息,下面那个方法是final的,其实就是调用了上面的方法的一个重载,关于那个FieldSelctor说明下,这个是一个接口,相当于一个过滤器,用来过滤我们获取文档里面的数据的时候对字段进行一些过滤操作(也不完全是过滤,但是包含过滤),这个接口里面定义了一个单独的方法:
FieldSelectorResult accept(String fieldName);
就是Lucene读取到指定的字段的时候会调用这个方法,然后根据返回的FieldSelectorResult来进行不同的操作,这个等到后面我们说到document的时候在详解。
OK,今天这篇博文先写到这里,如果有什么看不懂或者不妥的地方欢迎联系我,最近人都变懒了,还有最近本人在追北京青年这部电视剧,每天差不多都是2点去了。。。。表示很累啊(T_T),更新都比较慢,希望能够对大家学习Lucene的过程中有所帮助!
IndexReader.getFieldNames Lucene 4
我们正在这里从Lucene 3.3.0升级到Lucene
4.2.1,我似乎找不到旧的IndexReader.getFieldNames方法的替代品。Googling提出了这张票证,其中提到了一个新的IndexReader.getFieldInfos方法,但是那是实验性的,并且似乎不再存在-
步履蹒跚。
如何在Lucene 4中复制IndexReader.getFieldNames的行为?
答案1
小编典典您可以使用AtomicReader.getFieldInfos()获得FieldInfos。
类似于以下内容:
for (FieldInfo info : atomicReader.getFieldInfos().iterator()) { String name = info.name; //Whatever you need to do with the name.}
查看《迁移指南》以了解更多信息,其中有一个有关IndexReader->
AtomicReader的部分。如果您还不熟悉该更改,则可能会发现有用的信息。
Lucene 4.x 之 IndexReader
Lucene 4.x 之 IndexReader 博客分类: 搜索引擎,爬虫 java在Lucene 3.x时代,《Lucene In Action》是一本相当不错的参考书,书中详细介绍了Lucene各种高级使用技术,对于开发者来说非常实用。但是近期Lucene升级到了4.x版本,在性能等各方面有了很大的提高,值得在新项目中使用。然而Lucene 4.x中的API相比3.x来说有了很大的改变,《Lucene In Action》中的很多内容都已经过时了,并且由于4.x推出的时间不长,还没有比较好的文档来对用法进行说明,这个系列文章就是想记录下自己使用Lucene 4.x的经验体会,供大家参考使用。
由于现在网络搜索都希望达到实时搜索的效果,用户上传文章后,希望立即在搜索结果中可见,这就要求我们必须使用Lucene的准实时搜索功能,使我们在不影响性能的情况下达到近实时搜索的效果。然而准实时搜索API在4.x版本中已经与3.x版本完全不同了。
首先来看怎样获取准实时搜索的Reader实例,大家都知道,由于性能等方面原因,基于Lucene的应用一般都采用共享Lucene的Writer和Reader及Searcher的方案,我们这里也不例外:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
indexPathname =
"D:/aproject/xincaigu/work/index"
;
analyzer =
new
MMSegAnalyzer();
IndexWriterConfig iwc =
new
IndexWriterConfig(Version.LUCENE_41, analyzer);
iwc.setOpenMode(OpenMode.CREATE_OR_APPEND);
try
{
indexDir = FSDirectory.open(
new
File(indexPathname));
writer =
new
IndexWriter(indexDir, iwc);
// writer和reader整个程序共用
reader = DirectoryReader.open(writer,
true
);
//reader = writer.getReader();
}
catch
(CorruptIndexException e) {
}
catch
(LockObtainFailedException e) {
}
catch
(IOException e) {
}
|
熟悉Lucene 3.x的朋友一定注意到了,获取准实时搜索所用的Reader已经改用DirectoryReader.open方法,而不是3.x当中的writer.getReader()方法了。
同样,在3.x中,为了可以看到刚刚添加的新文章,Reader需要进行reopen操作,这是一种节省资源的方式,可以获取新加入索引的文章,而不需要将改动保存到磁盘上,然后重新打开索引的方式来进行了。但是reopne在4.x也被新API所取代,具体的用法如下所示:
1
2
3
4
5
6
7
8
9
10
|
try
{
IndexReader newReader = DirectoryReader.openIfChanged((DirectoryReader)reader, writer,
false
);
//reader.reopen(); // 读入新增加的增量索引内容,满足实时索引需求
if
(newReader !=
null
) {
reader.close();
reader = newReader;
}
searcher =
new
IndexSearcher(reader);
}
catch
(CorruptIndexException e) {
}
catch
(IOException e) {
}
|
这里首先利用新APIDirctoryReader.openIfChanged来获取Reader,如果有新内容,则返回新的Reader,这时我们需要关闭老的Reader。
通过以上代码,我们就可以利用Lucene 4.x的准实时搜索功能了。但是Lucene 4.x中API的变动远不止这些,在进行索引时,原来定义Field的方式已经过时,取而代之的是更加灵活的FieldType机制,下篇文章中我们将详细探讨如何在文本索引中使用这一新的机制。
http://my.oschina.net/MrMichael/blog/220723
lucene Creating an Index
我也是头一次接触,不对的地方多多指教。
创建一个索引,其中包括要索引的本地目录,和一个存放索引信息的路径
String indexDir = "E:\\ 帮助文档 \\LUCENE\\index";// 索引信息存放的目录String dataDir = "E:\\ 帮助文档 \\LUCENE\\lucene-3.5.0";// 要被索引的目录
Directory dir = FSDirectory.open(new File(indexDir));//3
IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(Version.LUCENE_35, new StandardAnalyzer(Version.LUCENE_35)));//4
注释 3 处分析一下,查看源码
org.apache.lucene.store.FSDirectory 是一个抽象类,继承了抽象类 org.apache.lucene.store.Directory,
而 org.apache.lucene.store.Directory 只实现了一个接口 java.io.Closeable (java 标准库),这个接口只有一个 close 方法
看一下 FSDirectory 的
public static FSDirectory open(File path) throws IOException {
return open(path, null);
}
这个方法调用
public static FSDirectory open(File path, LockFactory lockFactory) throws IOException {
if ((Constants.WINDOWS || Constants.SUN_OS || Constants.LINUX)
&& Constants.JRE_IS_64BIT && MMapDirectory.UNMAP_SUPPORTED) {
return new MMapDirectory(path, lockFactory);
} else if (Constants.WINDOWS) {
return new SimpleFSDirectory(path, lockFactory);
} else {
return new NIOFSDirectory(path, lockFactory);
}
}
这个方法根据系统信息返回不同的 Directory,不过 MMapDirectory、SimpleFSDirectory、NIOFSDirectory 都继承了 FSDirectory,所以也间接的继承了 org.apache.lucene.store.Directory。
所以 lucene 的继承结构如下
MMapDirectory、SimpleFSDirectory、NIOFSDirectory 继承 FSDirectory 继承 org.apache.lucene.store.Directory。
其实我们经常用的就是 FSDirectory 类,根据系统环境不同,此类会帮我们自动选择适合系统坏境的处理类 MMapDirectory、SimpleFSDirectory、NIOFSDirectory,不必关心这些细节
其实注释 3 处就是对绑定一个索引存放的路径,如果路径不存在,则会帮我们去创建这个目录,用来存放一些索引的信息
注释 4 处是生成一个 lucene 的写入类,用于写入索引信息。
org.apache.lucene.index.IndexWriter 类的一些方法,先写点代码
File[] files = new File(dataDir).listFiles();
for (File f : files) {
if (!f.isDirectory() && !f.isHidden() && f.exists() && f.canRead()) {
//System.out.println ("文件:"+f);
indexFile(f);
}
}
System.out.println(writer.numDocs());
private void indexFile(File f) throws Exception {
System.out.println("Indexing " + f.getCanonicalPath());
Document doc = getDocument(f);
writer.addDocument(doc);
}
protected Document getDocument(File f) throws Exception {
//3333333333333333333333333333333333333
Document doc = new Document();
doc.add(new Field("contents", new FileReader(f)));
doc.add(new Field("filename", f.getName(), Field.Store.YES,
Field.Index.NOT_ANALYZED));
doc.add(new Field("fullpath", f.getCanonicalPath(), Field.Store.YES,
Field.Index.NOT_ANALYZED));
//333333333333333333333333333333333
return doc;
}
介绍 IndexWriter 之前,先看看这个类 org.apache.lucene.document.Document。
这个类主要是构造索引文件,然后交由 IndexWriter 的 addDocument (doc) 方法来使用此索引文件
打开源码看一眼,此类只有一个无参构造方法
/** Constructs a new document with no fields. */
public Document () {},构造器没有任何动作。
看下他的重要方法
public final void add(Fieldable field);
此方法接收一个 fieldalble 参数,通过源码查看时一个接口
public interface Fieldable extends Serializable ,
它的实现类为 org.apache.lucene.document.Field,
此实现类有很多构造方法,几乎能满足用户创建 Field 的各种需求,从字面意思看是创建搜索用的域,
更多的 Field 方法和属性就先不看了,先往下看
注释 33333333 之间是为每一个文件都创建文件索引信息(可以创建不同形式的索引方式,此处为三种,区别还不太清楚呢,等做搜索的时候在看把),以便于搜索
IndexWriter 的 addDocument (doc) 方法,把每个文件的索引信息都写到了磁盘上作为缓存用。如果不清缓存则索引信息一直存在。
IndexWriter 的 numDocs () 方法,返回索引文件中的文档数量。
到这里,简单的索引创建已经完成了
Lucene index and search
Class | Responsibility |
Directory | 存放索引文件的目录 |
Analyzer | 它对要索引的文本进行词组化(文本分解成词组). 先分解成raw tokens,然后再使用TokenFilter过滤 |
IndexWriter | 真正生成索引文件的Writer |
Document | 要索引的文档, 里面像二维表意义, 有field 和value. |
IndexWriterConfig | IndexWriter的配置 |
Search
Class | Responsibility |
Directory | 索引文件存放的目录 |
IndexSearcher | 搜索任务的主要执行者 |
Query | 要搜索的内容, 可能是一个关键字, 也可能是一些组合 |
TopDocs | 搜索返回的结果集 |
QueryParser | 查询条件的解析者, 产出Query, 它要使用Analyzer |
今天的关于Lucene搜索流程(2.IndexReader)和lucene搜索原理的分享已经结束,谢谢您的关注,如果想了解更多关于IndexReader.getFieldNames Lucene 4、Lucene 4.x 之 IndexReader、lucene Creating an Index、Lucene index and search的相关知识,请在本站进行查询。
本文标签: