分词存储设置范围最佳实践:
分词索引:Field.Index.* |
存储:Field.Store.YES/NO |
适用范围 |
NOT_ANALYZED_NOT_NORMS |
YES |
标识符(主键、文件名),电话号码,身份证号,姓名,日期 |
ANALYZED |
YES |
文档标题和摘要 |
ANALYZED |
NO |
文档正文 |
NO |
YES |
文档类型,数据库主键(不进行索引) |
NOT_ANALYZED |
NO |
隐藏关键字 |
import java.io.File;
import java.io.IOException;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
public class IndexUtil
{
private String[] ids = { "1", "2", "3", "4", "5", "6" };
private String[] emails = { "b1", "b2", "b3", "b4", "b5", "b6" };
private String[] content = { "b1 aaaa this is hello ",
"b2 i kill to you ma", "b3 cc wo are you from hold",
"b4 Index Reader", "b5 r RUNTIME DATA AREA",
"b6 java lang ClassLoader" };
private int[] attachs = { 2, 3, 1, 4, 5, 5 };
private String[] names = { "wc1", "wc2", "wc3", "wc4", "wc5", "wc6" };
private Directory directory = null;
public IndexUtil()
{
try
{
// 设置索引目录
directory = FSDirectory.open(new File("D:\\workspace\\helloLucene\\IndexUtil\\"));
}
catch (IOException e)
{
// TODO Auto-generated catch
// block
e.printStackTrace();
}
}
public void index()
{
IndexWriter writer = null;
try
{
writer = new IndexWriter(directory,
new IndexWriterConfig(Version.LUCENE_35,
new StandardAnalyzer(Version.LUCENE_35)));
Document doc = null;
for (int i = 0; i < ids.length; i++)
{
doc = new Document();
// id需要存储不分词不加权
doc.add(new Field("id",
ids[i],
Field.Store.YES,
Field.Index.NOT_ANALYZED_NO_NORMS));
// email需要存储不分词,希望区分公司邮件为重点-加权重
doc.add(new Field("email",
emails[i],
Field.Store.YES,
Field.Index.NOT_ANALYZED));
// content不存储分词
doc.add(new Field("content",
content[i],
Field.Store.NO,
Field.Index.ANALYZED));
// name需要存储不分词不加权
doc.add(new Field("name",
names[i],
Field.Store.YES,
Field.Index.NOT_ANALYZED_NO_NORMS));
writer.addDocument(doc);
}
}
catch (Exception e)
{
// TODO Auto-generated catch
// block
e.printStackTrace();
}
finally
{
try
{
if (writer != null)
{
writer.close();
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
public void query() {
try {
IndexReader reader = IndexReader.open(directory);
//通过reader可以有效的获取到文档的数量
System.out.println("返回索引中的Document的数 numDocs:"+reader.numDocs());
System.out.println("下一个Document对象的编号 maxDocs:"+reader.maxDoc());
System.out.println("deleteDocs:"+reader.numDeletedDocs());
reader.close();
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args)
{
IndexUtil iu = new IndexUtil();
iu.index();
iu.query();
System.out.println("end...");
}
}
Lucene使用文件扩展名标识不同的索引文件。如.fnm文件存储域Fields名称及其属性,.fdt存储文档各项域数据,.fdx存储文档在fdt中的偏移位置即其索引文件,.frq存储文档中term位置数 据,.tii文件存储term字典,.tis文件存储term频率数据,.prx存储term接近度数据,.nrm存储调节因子数据,另外 segments_X文件存储当前最新索引片段的信息,其中X为其最新修改版本,segments.gen存储当前版本即X值。
它们的关系图则如下所示:
FNM 保存Field域信息,代码中定义一致。
第0x05字节表示存储了4个域
FDX 保存Field域索引,保存了每个document的词域数据在.fdt的起始位置(每个位置数据用Uint64,8个字节)
如图:第0x03字节表示??,第0个document的词域数据信息起始于.fdt的第0x04字节,第1个document的词域数据信息起始于.fdt的第0x14字节。
FDT 保存Field域数据,按document依次存储词域数据。每个词域数据信息包括该词域序号(FieldNum)、词域位信息(Bits)和词域数据。词域数据又分字符串和二进制2种类型。字符串数据包含字符个数(非字节数)和字符串内容,字符串内容是经过utf-8编码的。
如图:0x04字节表示该document有3个词域,第0x05-0x09字节表示第0个词域数据信息,其中第0x05、0x09字节表示词域序号,即FieldNum;第0x05字节表示词域位信息,即Bits;第0x07、0x0b表示词域数据字符长度,即1、2个;第0x08字节就是词域数据,即“1”,第0x0C、0x0D字节就是词域数据,即“b1”。。
FRQ 评分和排序,词语所在文档的文档列表(docID)和该词语出现在文档中的频率信息。
TII 词典,索引文件。保存了tis中每隔IndexInterval个词的位置信息,这是为了加快对词典文件tii中词的查找速度
TIS 词典数据文件。存放索引表中Dictionary的所有Term的信息