阅读了开源的搜索引擎Lucene的c++版本,这里将笔记比较粗的列举一下,详细的剖析过程,会逐步的整理贴上来.
处理输入:
(1).streambase.h
template <class T>
class StreamBase {};
(2).inputstreambuffer.h
template <class T>
class InputStreamBuffer {};
(3).bufferedstream.h
template <class T>
class BufferedInputStream : public StreamBase<T> {};
(4).fileinputstream.h
class FileInputStream : public BufferedInputStream<char> {};
(5).Reader.h
class Reader;
class StringReader: public Reader {};
class SimpleInputStreamReader: public jstreams::BufferedInputStream<TCHAR>{};
class FileReader: public Reader{};
处理分词:
(1).CharTokenizer是一个抽象类,它主要是对西文字符进行分词处理的.常见的英文中,是以空格、标点为分隔符号的,在分词的时候,就是以这些分隔符
作为分词的间隔符的.
(2).实现CharTokenizer的具体类有3个,分别为:LetterTokenizer、WhitespaceTokenizer;
LetterTokenizer类:只要读取到非字符的符号,就分词;
(3).TokenFilter是一个抽象类,定义了对一个经过分词(Tokenizer)后的TokenStream进行过滤的功能;
(4).不同的Lucene分析器Analyzer,它对TokenStream进行分词的方法是不同的,这需要根据具体的语言来选择。比如英文,一般是通过空格来分割词条,
而中文汉字则不能通过这种方式,最简单的方式就是单个汉字作为一个词条。
TokenStream是通过从设备或者其他地方获取数据源而构造的一个流,我们要执行分词的动作,应该对这个TokenStream进行操作.TokenStream也可以
不是直接通过数据源构造的流,可以是经过分词操作之后读入TokenFilter的一个分词流。
文档与字段:
(1).class Field;
(2).class DocumentFieldEnumeration;
(3).class DocumentFieldList;
(4).class Document;
建立索引辅助工具:
IndexInput.h IndexOutput.h Directory.h FSDirectory.h RAMDirectory.h
class Directory
(1).管理锁工厂及其锁实例;
(2).管理Directory目录实例的基本属性,主要是通过文件名称进行管理;
(3).管理与操作该目录相关的一些流对象;
(4).管理索引文件的拷贝。
class FSDirectory:public Directory
class IndexInput
class MMapIndexInput: public IndexInput
class BufferedIndexInput: public IndexInput
class FSIndexInput:public BufferedIndexInput
class IndexOutput
class BufferedIndexOutput : public IndexOutput
class FSIndexOutput: public BufferedIndexOutput
(1).锁工厂的获取及其管理;
(2).对文件系统目录下索引文件的输入流和输出流的管理;
(3).获取FSDirectory类实例;
(4).获取锁工厂实例后,可以创建一个新的FSDirectory类实例,在此之前先要完成一些初始化工作;
(5).继承自Directory抽象类,自然可以实现索引文件的的拷贝操作。
(6).FSDirectory类中实现了很多静态内部类,这使得只能在FSDirectory类内部访问这些静态类,对外部透明
class RAMFile
class RAMIndexOutput: public BufferedIndexOutput
class RAMIndexInput: public BufferedIndexInput
class RAMLock
因为RAMDirectory是与内存相关的目录,所以它不是永久存在的,不像FSDirectory,所以实例化一个RAMDirectory可以从一个FSDirectory的实例来完成.
RAMDirectory的特点决定了,对目录Directory进行复杂的操作时,都要把这些操作转移到内存中来处理。通过拷贝目录的方式也可以实例化一个RAMdirectory.
将指定的dir目录拷贝到当前的内存中,即实例化一个RAMDirectory。这里,closeDir是一个很重要的状态变量,指定了拷贝完成后,源目录dir是否关闭。
如果实例化一个RAMDirectory完成后就关闭源目录dir,可能会因为处理的时间非常短,而需要再次打开源目录dir,持久化到文件系统目录,开销可能会
比直接操作源目录dir要大,这点要权衡.
public void seek(long pos):输出缓冲区的内容,然后将文件指针定位到long所指示的文件位置.
建立索引:
IndexWriter.h IndexReader.h
class IndexWriter
class IndexReader
class DocumentWriter
class FieldInfos
class FieldsWriter
class FieldsReader
class Term
class TermInfo
class SegmentInfo
class SegmentReader
class SegmentTermPositions
class TermDocs
class TermPositions
class TermInfosReader
class TermInfosWriter
class SegmentInfos
class SegmentMerger
索引的过程:
(1).构造函数
IndexWriter::IndexWriter(const char* path, Analyzer* a, const bool create, const bool _closeDir):
directory( FSDirectory::getDirectory(path, create) ),analyzer(a),egmentInfos (_CLNEW SegmentInfos),
closeDir(_closeDir)
{
_IndexWriter ( create );
}
//create indicates if the indexWriter must create a new index located at path or just open it
void IndexWriter::_IndexWriter(const bool create)
{
//建立一个TransactionalRAMDirectory对象,该对象包含一个事务取消时的删除文件列表及恢复文件列表
//同时还包含一个当前文件列表恢复文件列表自动删除key和value,删除文件列表和当前文件列表则不自动删除
ramDirectory = _CLNEW TransactionalRAMDirectory;
}
(2).Document* doc = FileDocument( path ); ===>doc->add(*_CLNEW Field(_T("path"), tf, Field::STORE_YES | Field::INDEX_UNTOKENIZED ) );
doc->add(*_CLNEW Field(_T("contents"),str.getBuffer(), Field::STORE_YES | Field::INDEX_TOKENIZED) );
(3).writer->addDocument( doc ); ===>一个writer会加入多个doc,因此会有多个segmentName
void IndexWriter::addDocument(Document* doc, Analyzer* analyzer)
{
ramDirectory->transStart();
char* segmentName = newSegmentName();
DocumentWriter* dw = _CLNEW DocumentWriter(ramDirectory, analyzer, this ); (a)
dw->addDocument(segmentName, doc); (b)
//Create a new SegmentInfo instance about this new segment.
SegmentInfo* si = _CLNEW SegmentInfo(segmentName, 1, ramDirectory);
segmentInfos->add(si);
maybeMergeSeg