1 倒排索引
倒排索引是满足实际应用而设计的一种数据结构。倒排索引的每一个元素是一个索引项,每一个索引项是由关键字属性值和关键字关联结果,或者记录的存放地址组成。倒排索引是利用索引关键字直接确定文档列表,最后确定希望找到的文档列表。与传统的顺序查找和记录组织方式相反,因此称为倒排索引。通常把采用倒排索引方式组织的文件或者倒排索引和文档主文件一起称为倒排文件。
2 Lucence索引器
2.1 模式
2.1.1 独立索引模式:每个Document独立索引成一个文件
2.1.2 符合索引模式:等待索引的全部Document索引成一个文件
2.2 结构
索引项->索引域->索引文档->索引段->索引
2.2.1 索引域的属性
1、域的名称(String类型)
2、域存储的值
3、Store
Store.YES:保持索引和原始信息
Store.NO:信息只索引,但不保存
4、Index
Index.ANALYZED:分词并建立索引
Index.ANALYZED_NO_NORMS:分词并建立索引,同时index-time,document boosting和field length normalization这几个域不使用。
Index.NO:不建立索引
Index.NOT_ANALYZED:不分词,但建立索引
Index.NOT_ANALYZED_NO_NORMS:不分词,建立索引,同时index-time,document boosting和field length normalization这几个域不使用。
5、Field.TermVector:表示域内信息是否需要分词。
2.2.2 索引项
索引项是索引管理的最小单元。在程序中没有显示的调用,它是利用分词器,在后台自动把一个域的值进行分隔。得到的每个独立元素称为一个索引项,用来建立索引。
2.3 格式
复合索引模式(默认):可以减少索引文件的数量,便于管理和使用,适用于静态索引。多文件索引格式适用于动态索引。
2.3.1 多文件索引格式
使用一系列索引文件分别存储索引,分散管理数据的索引存储格式。多文件索引在打开时需要读取大量文件,会大大占用系统的文件句柄等资源,造成系统响应速度慢,甚至系统崩溃。
主要的索引文件及功能:
1、segment_*:描述一组索引的参数,使用文件头固定格式描述后面的内容,包括每个独立新建索引的大小,属性等。
2、fnm:索引域描述文件,一个独立的索引(PerIndex)叫做一个segment(索引段),一个fnm文件描述了本索引的File数,各个Field的属性编号。
3、fdx:文档域值索引文件,采用定长方式存储,根据docid排序,可直接定位。用来记录每个文档的Stored fields值的存储位置。
4、fdt:文档域值存储文件,存储Stored fields值的文件。通过fdx中记录的便宜访问。
5、tis:存储每个term在文档中的分布信息,如文档频率,每个含term文档出现次数记录的偏移和位置记录的偏移排列顺序。先按Field名字字典排序,在每个Field按term字典排序。
6、tii:该文件是tis文件的索引和精简,排列格式一样,但不含有每个term属性的信息。这个文件可以完全读入到内存中。
7、frq:该文件是tis文件的扩展。记录每个term在每个包含文件中具体出现频率。
8、prx:该文件是tis文件的延伸,记录每个term在每个文档偏移信息。这个文档省略类docid,必须配合frq文件使用。
9、tvx,tvd,tvf:用来索引和保持每一个文档的向量化字段的信息。
2.3.2 复合索引结构
1、segment_*:描述一组索引的参数,使用文件头固定格式描述后面的内容,包括每个独立新建索引的大小,属性等。
2、segment.gen:存储索引创建参数。
3、cfs:存储实际的索引数据,不同子索引的内容按照一定的格式存储,仍然可以区分,直到索引优化压缩操作发生时。
3 与索引操作相关的类
3.1 IndexWriter
构造方法:
IndexWriter(Directory d, Analyzer a, boolean create, IndexDeletionPolicy deletionPolicy, IndexWriter.MaxFieldLength mfl) IndexWriter(Directory d, Analyzer a, boolean create, IndexWriter.MaxFieldLength mfl) IndexWriter(Directory d, Analyzer a, IndexDeletionPolicy deletionPolicy, IndexWriter.MaxFieldLength mfl) IndexWriter(Directory d, Analyzer a, IndexDeletionPolicy deletionPolicy, IndexWriter.MaxFieldLength mfl, IndexCommit commit) IndexWriter(Directory d, Analyzer a, IndexWriter.MaxFieldLength mfl)
各个构造方法的参数意义相同。其中,Directory d 表示索引的存储路径;Analyzer a 是分词器;boolean create表示是否新建索引,IndexDeletionPolicy deletionPolicy表示索引的删除策略;IndexWriter.MaxFieldLength mfl索引项个数;IndexCommit commit,用于获得和commit point相关联的segment文件。
3.2 IndexReader
IndexReader管理已经建立的Lucence索引,负责磁盘目录上存放的索引的加载和删除维护工作。通过它内部的方法,可以统计当前索引中的文档数目等信息。
3.3 Analyzer
分词器,用于分词。
4 索引设置的一些建议
4.1 索引域类型选择
1) 尽量减少不必要的存储
2) 不需要检索的内容不要建立索引
3) 非文本格式需要提前转化
4)需要整体存放的内容不要分词
4.2 索引参数优化
1) 设置合并参数setMergeFactor(),用于控制最大内存中存放的索引文档Document个数。
2)设置最大文档个数setMaxBufferedDocs(),合并段的大小,也就是一个索引段达到多少个以后,可以合并成一个更大的新段。
3) 限制域索引个数setMaxFieldLength()
4) 设置最大内存删除项数setMaxBufferedDeleteTerms
4.3 磁盘索引和内存索引
磁盘索引使用FSDirectory,内存索引使用RAMDirectory。
4.4 同步与锁机制
write.lock用于避免一个线程同时修改一个索引文档而设置
commit.lock主要在segment建立,合并或读取时使用,只在索引的合并函数和段合并函数中使用。
实例:
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Date; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.store.Directory; import org.apache.lucene.store.FSDirectory; import org.apache.lucene.util.Version; public class LuceneIndexManager { private static String Index_Path = "D:/index"; private static String Text_Path = "D:/text/wine.txt"; public static void main(String[] args) { try { Date start = new Date(); File file1 = new File(Text_Path); File file2 = new File(Index_Path); Directory dir = FSDirectory.open(file2); Analyzer TextAnalyzer = new StandardAnalyzer(Version.LUCENE_CURRENT); IndexWriter TextIndex = new IndexWriter(dir,TextAnalyzer, true,IndexWriter.MaxFieldLength.LIMITED); Document document = new Document(); Field field_name = new Field("name", file1.getName(),Field.Store.YES,Field.Index.NOT_ANALYZED); document.add(field_name); FileInputStream inputfile = new FileInputStream(file1); int len = inputfile.available(); byte[] buffer = new byte[len]; inputfile.read(buffer); inputfile.close(); String contenttext = new String(buffer); Field field_content = new Field("content", contenttext,Field.Store.YES, Field.Index.ANALYZED); document.add(field_content); TextIndex.addDocument(document); TextIndex.optimize(); TextIndex.close(); Date end = new Date(); long tm_index = end.getTime() - start.getTime(); System.out.print("Total Time(ms): "); System.out.println(tm_index); } catch (IOException e) { e.printStackTrace(); } System.out.println("Index Success"); } }