在检索数据的时候,我们很希望可以检索出数据源的各种信息。就比如检索磁盘文件,可以检索出文件的路径,名字, 内容,修改时间等等。再比如检索图书的书号、书名、作者、出版时间.... 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 无疑做到了这一点。