??xml version="1.0" encoding="utf-8" standalone="yes"?>
首先来看analysis包,q个包主要是提供一些简单的词汇化处?br />
?span style="color: #339966">Tokenizerl尾的类是将要处理的字符串进行分割成Token,而根据分割的依据的又产生了以下几个Tokenizerc?br />
首先TokenizercL所?span style="color: #000000">以Tokenizerl尾的类的基c?br />
然后是CharTokenizerQ所有的?span style="color: #339966">Tokenizerl尾的类都是从这个类l承?br />
q个cM有一个抽象方?br />
protected abstract boolean isTokenChar(char c);
另外一个需要被子类覆写的方?br />
protected char normalize(char c) {}Q?/span>
是对单个字符q行处理的方法譬如说英文字母全部{化ؓ写
q有一个变?br />
protected Reader input;
q个d器是q些cL处理的数据的 数据?br />
输入一个Reader Q生一个Token?/span>
q个Ҏ(gu)是是否进行切分的依据Q依ơ读取char,然后用这个方法对每个charq行,如果q回false则将预先存储?br />
词汇~冲Z的char数组作ؓ一个Tokenq回
LetterTokenizer Q?/span>
protected boolean isTokenChar(char c) {
return Character.isLetter(c);
}
WhitespaceTokenizerQ?/span>
protected boolean isTokenChar(char c) {
return !Character.isWhitespace(c);
}
LowerCaseTokenizer extends LetterTokenizerQ?/span>
protected char normalize(char c) {
return Character.toLowerCase(c);
}
在构造函C调用super(in);q行?nbsp;LetterTokenizer同样的操作,但是在词汇化之前所有的词都转化为小写了
然后是以Filterl尾的类Q这个类主要是对已l词汇化的Token进行进一步的处理
输入是Token?, 输出仍然是Token?br />
TokenFilter extends TokenStream 是所有这些类的父c?br />
protected TokenStream input;
在TokenFilter 中有一个TokenStream 变量Q是Filtercȝ处理的数据源Q而Filtercȝ又是l承了TokenStream cȝ
有一个public final Token next()Ҏ(gu),q个Ҏ(gu)以TokenStream.next()产生的Token?为处理源Q生的仍然是Token?br />
只不q中间有一些处理的q程
LowerCaseFilterQ将所有的Token的转化为小?br />
t.termText = t.termText.toLowerCase();
StopFilterQ过滤掉一些停止词Q这些停止词由构造函数指?/span>
for (Token token = input.next(); token != null; token = input.next())
if (!stopWords.contains(token.termText))
return token;
比较一下Tokenizercȝ和FiltercȝQ可以知?br />
Tokenizercȝ主要是对输入的Reader,实际上是字符按照一定的规则q行分割Q生出Token?br />
其输入是字符串的ReaderŞ式,输出是Token?br />
Filtercȝ主要是对输入的Token进行更q一步的处理Q如去除停止词,转化为小?br />
主要Z些格式化操作?br />
׃Filtercȝ的输入输出相同,所以可以嵌套几个不同的Filterc,以达到预期的处理目的?br />
前一个Filtercȝ输出作ؓ后一个Filtercȝ输入
而Tokenizercȝ׃输入输出不同Q所以不能嵌?br />
.fnm的文件格式: QField的信息)
int: Field的个敎ͼ最ؓ1Q最有一个Field("",false)Q在初始化的时候写?暂时不知道原?; 名称为空字符Ԍ未烦引, ?nbsp; ?nbsp; 量化。readVInt()d
String: byte String?nbsp;Field的名U?nbsp; byte指示该Field 是否被烦引,是否向量?Q值有Q?1Q?0Q?1Q第一?代表被烦引,W二个代表被向量?br />
String: byte Field 同上
.fdx的文件格式:主要是提供对.fdt中存储的document的随卌?br />
long : W一个document?fdt文g中的位置
long: W二个document?fdt文g中的位置
.fdt的文件格式: .fdt文g存储了一pddocument的信?br /> VInt: 该document中的isStored属性ؓtrue的域的个?br /> (VInt:) 如果该field的isStored属性ؓtrue则得到该field的fieldNumberQ暂时不知道q个fieldNumber是怎么产生的,有什么用Q初步估计是按照field创徏的顺序生的Q每ơ再上一个field的fieldNumber基础上加1?br /> byte: 如果该field的isTokenized属性ؓtrue写入1否则写入false?br /> String: 该field的stringValue()倹{?br /> 一个documentl束Q下面的数据会开始一个新的documentQ每个新的document的开始点的文件位|都会在.fdx中有记蝲Q便于随卌?/span>
try {
//DataInputStream fis = new DataInputStream(new FileInputStream("C:\\sf\\snow\\segments"));
FSDirectory dir=FSDirectory.getDirectory("C:/sf/snow", false);
InputStream input = dir.openFile("segments");
System.out.println("Format:"+input.readInt()); //得到文g标志Q是否ؓ正常的segments文g
System.out.println("version:"+input.readLong()); //得到版本?br />
System.out.println("name:"+input.readInt()); //得到用来重命名新D늚intQ暂时不知道有什么用
int n=input.readInt(); //D늚数目
System.out.println("SegmentNum:"+n);
for(int i=0;i<n;i++) { //用@环打印出所有段的信?名称和长?br />
System.out.println("segment "+i+" - name:"+input.readString()+" num:"+input.readInt());
}
} catch (Exception e) {
}
当然,该类提供了更为复杂的讉K和更新segments文g的方?br />
final void read(Directory directory) 所有的D信息保存在本vector?br />
final void write(Directory directory) 跟新该segment文g的内容,主要是ؓ了添加段Q?br />
主要是更?版本?D늚数目Q跟新完q些后即可往segment文g后添加新D늚信息?br />
import org.apache.lucene.store.Directory;
final class SegmentInfo {
public String name; //在烦引目录中唯一的名U?nbsp;
public int docCount; // 该段中doc的数?br />
public Directory dir; // 该段所存在的Dirrectory
public SegmentInfo(String name, int docCount, Directory dir) {
this.name = name;
this.docCount = docCount;
this.dir = dir;
}
}
public void flushBuffer(byte[] src, int len) {
int bufferNumber = pointer/BUFFER_SIZE; //buffer序列Q即当前所写Buffer在RAMFile中的Vector中的序列?br />
int bufferOffset = pointer%BUFFER_SIZE; //偏移量,卛_前所写字节在当前Buffer中的偏移量?br />
int bytesInBuffer = BUFFER_SIZE - bufferOffset; //当前Buffer的剩余可写字节数
//bytesToCopy是实际写入的字节敎ͼ如果当前Bufer的剩余字节数大于需要写的字节的L则写入所有字?br />
//否则Q将当前Buffer写满卛_Q剩余的字节写入下一个Buffer
int bytesToCopy = bytesInBuffer >= len ? len : bytesInBuffer;
if (bufferNumber == file.buffers.size())
file.buffers.addElement(new byte[BUFFER_SIZE]); //在RAMFile中添加新的byte[1024]元素
byte[] buffer = (byte[])file.buffers.elementAt(bufferNumber);
System.arraycopy(src, 0, buffer, bufferOffset, bytesToCopy);
if (bytesToCopy < len) { // not all in one buffer,
int srcOffset = bytesToCopy;
bytesToCopy = len - bytesToCopy; // remaining bytes 剩余的未写入的字节数
bufferNumber++; //buffer数增?
if (bufferNumber == file.buffers.size())
file.buffers.addElement(new byte[BUFFER_SIZE]);
buffer = (byte[])file.buffers.elementAt(bufferNumber); //剩余字节写入下一个Buffer
System.arraycopy(src, srcOffset, buffer, 0, bytesToCopy);
}
pointer += len;
if (pointer > file.length)
file.length = pointer; //UM文g指针 在原有的基础上加上实际写入的字节L
file.lastModified = System.currentTimeMillis(); //修改文g的最后修Ҏ(gu)间ؓ当前旉
}
从指定的字节数组复制指定长度的字节到RAMFile中去。由于RAMFile中Vector的元素是byte[1024]所以可能存在做一ơ该操作
要操作两个Vector元素的情c即先将当前byte[1024]数组填满Q再新徏一个元素装载剩余的字节?br />
另外q有一个writeTo(OutputStream out)Ҏ(gu)Q将RAMFile中的数据输出到另一个输出流
UNICODE?UTF-8~码
U-00000000 - U-0000007F: 0xxxxxxx
U-00000080 - U-000007FF: 110xxxxx 10xxxxxx
U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
可见对于?0x00-0x7F范围内的UNICODE|最大有效数位:7位)Q将会编码成单字节的Q会大大节约存储I间?br />
对于?nbsp; 0x80-0x7FF范围内的UNICODEQ最大有效数位:11位)Q会~码成双字节的。先存储原字节低5位的CQ且最高位和次高位都置1Q再ơ高位置0QwriteByte((byte)(0xC0 | (code >> 6)));Q。然后存储后6位的字节Q将前两位置10QwriteByte((byte)(0x80 | (code & 0x3F)));Q?br />
对于其他的UNICODE值则
writeByte((byte)(0xE0 | (code >>> 12))); 4?br />
writeByte((byte)(0x80 | ((code >> 6) & 0x3F))); 5?br />
writeByte((byte)(0x80 | (code & 0x3F))); 3- 5?br />
final void writeString(String s) throws IOException
该函数首先用s.length()判断该Stringd有多个字符
然后首先调用writeVInt写入q个字符长度
再调用writeChars(s,s.length())写入字符
在inputStream中的readString()Ҏ(gu)则与其相反,首先用readVInt()Ҏ(gu)d字符长度len 然后dlen长度的字W?br />
protected final void flush() throws IOException
该方法调用另外一个方法flushBuffer缓冲区中的数据输出Q然后清I缓冲区Q?br />
abstract void flushBuffer(byte[] b, int len) throws IOException
可见flushBufferҎ(gu)是abstract的,即需要其子类对该Ҏ(gu)q行覆写Q以定位该输出流的输出方式?br />
final long getFilePointer() throws IOException
得到文g指针的位|,卛_到输出流已经输出的字节数?br />
public void seek(long pos) throws IOException
输出~冲区的内容Q然后将文g指针定位到l(f)ong所指示的文件位|?br />
abstract long length() throws IOException
q回文g中已有的字节数。需要子cd现?br />