在检索数据的时候,我们很希望可以检索出数据源的各种信息。就比如检索磁盘文件,可以检索出文件的路径,名字, 内容,修改时间等等。再比如检索图书的书号、书名、作者、出版时间.... Lucene是如何组织这些数据源的不同属性信息呢?
Lucene 数据源组织结构
org.apache.lucene.document包中有两个很重要的类:Document 和 Field。这两个类将杂乱无章的数据形式组织成可以被Lucene使用的内存数据结构。
Field类的作用主要是用来表示当前数据源的各种属性。 数据源的每种属性信息都可以组织成一个Field对象。这些对象有不同的属性名,属性值,以及属性数据的存储方式和索引方式。
举个列子,比如我们想要检索文件的路径,修改时间和内容。我们可以创建三个Field对象分别存储这三种数据:
//文件路径Field
Field pathField=new Field("path", file.getPath(), Field.Store.YES, Field.Index.NOT_ANALYZED)
//文件修改时间Field
Field modifiedField=new Field("modified", DateTools.timeToString(file.lastModified(), DateTools.Resolution.MINUTE), Field.Store.YES, Field.Index.NOT_ANALYZED)
//文件内容Field
Field contentField=new Field("contents", new FileReader(file));
下面是Field构造器(Field构造器有很多种,这里只做简单说明)
/**
* name: 名字
* value: 需要处理的字符串
* store: 是否需要将Field的原始value保存在索引文件中
* index: 是否需要对Field的原始value建立索引,如果需要,那么Field值要被分词。
*/
public Field(String name, String value, Store store, Index index)
Store和Index是Field中的枚举类型,用来表示这个Field的存储和索引方式。它们主要是为了告诉Lucene,哪些数据不需要存储,哪些数据不需要检索。
/**
* 确定该Field的原始value是否需要存储在索引中
*/
enum Store {
//该Field的原始值要被存储在索引中
//对短文本很有用。比如一个文档的标题,这个value以原始形式存储,在存储之前并不通过analyze分词
YES {
public boolean isStored() { return true; }
},
//该Field的原始值不需要存储在索引中
NO {
public boolean isStored() { return false; }
};
public abstract boolean isStored();
}
/**
* 确定该Field是否需要索引
*/
enum Index{
//该Field的值不需要索引,也就是不能提供关于这种Field值的查询
//但是如果这个Field被存储了(Stored=YES),那么我们查询别的Field的时候,可以得到这种Field信息
NO{
public boolean isIndexed() { return false; }
public boolean isAnalyzed() { return false; }
public boolean omitNorms() { return true; }
},
//该Field值需要建索引,而且需要分词
// 可以通过Field值中的词语进行查询,适合内容查询(全文检索)
ANALYZED {
public boolean isIndexed() { return true; }
public boolean isAnalyzed() { return true; }
public boolean omitNorms() { return false; }
},
//该Field值需要建索引,但不需要分词
//由于不分词,只能够通过整个值进行查询,适合像商品编号这样的ID值或者单个词语
NOT_ANALYZED {
public boolean isIndexed() { return true; }
public boolean isAnalyzed() { return false; }
public boolean omitNorms() { return false; }
},
}
Document 是Field 的集合(并不是狭隘的文件的含义) 。 在Lucene中,Document作为数据源的各种属性信息的集合,向Lucene提供原始的要索引的数据。这些数据源不仅可以是文件,也可以是一段字符串、几个数字、甚至一些链接。只要把它们加入到Document对象中,Lucene就可以为这些数据源建立索引。下面的部分Document源码表明:Document主要起到对Field信息进行记录和管理的作用。
public final class Document implements java.io.Serializable {
//Field列表
List<Fieldable> fields = new ArrayList<Fieldable>();
//在Document中加入Field
public final void add(Fieldable field) {
fields.add(field);
}
public final void removeField(String name){....}
public final Field getField(String name) {....}
.....
}
还是上面检索文件的例子,每个文档文件的不同属性信息都被组织成了三个Field对象:path Field、modified Field、content Field。我们可以创建一个Document对象,加入这三个Field,来表示一个文档文件需要被检索的三种数据。
Document doc = new Document();
doc.add(pathField);
doc.add(modifiedField);
doc.add(contentField);
总结 :下面的图很清楚的说明Lucene的数据源表示形式
举个例子,按照《Lucene体系结构概述》 中代码(IndexFiles.java )对3个txt文件建立索引。Lucene首先将这三个数据源在内存中组织成Document、Field 如下表:
Document | Field1 (path) | Field2 (modified) | Field3 (content) |
1.txt | e:\\....\\1.txt | 2010-4-1 | I'm a good stud.. |
2.txt | e:\\....\\2.txt | 2010-4-2 | It's me to a fini... |
3.txt | e:\\....\\3.txt | 2010-2-11 | Hi, Jack me too... |
Document 和 Field在Lucene中的作用是巨大的。我们都知道Lucene可以对任何形式的数据源建立索引,比如字符串、纯文本、XML、HTML等数据形式。怎么多杂乱无章的数据必须组织成统一有效的结构才能更好的处理,Document / Field 无疑做到了这一点。