分类:
2008-06-21 16:11:40
关于Field类和Document类。
初始化一个IndexWriter索引器之后,就可以向其中添加Document了。然而,Document逻辑文件能够与一个物理文件对应起来,在Lucene中,Document主要是维护添加到其中的多个Field。
关于Field在文章 Lucene-2.2.0 源代码阅读学习(3) 中可以了解到一点相关内容,Field类的定义比较简单,它给出了7种构造一个Field对象的构造方法:
public Field(String name, byte[] value, Store store)
public Field(String name, Reader reader)
public Field(String name, Reader reader, TermVector termVector)
public Field(String name, String value, Store store, Index index)
public Field(String name, String value, Store store, Index index, TermVector termVector)
public Field(String name, TokenStream tokenStream)
public Field(String name, TokenStream tokenStream, TermVector termVector)
Field类的内部定义了三个内部类,其中内部类Store和Index是非常重要的,它指定了一个Field被创建的时候,在索引、存储、分词方面进行选择,可以有不同的选择方式:
// Store是一个内部类,它是static的,主要为了设置Field的存储属性
public static final class Store extends Parameter implements Serializable {
private Store(String name) {
super(name);
}
// 在索引中压缩存储Field的值
public static final Store COMPRESS = new Store("COMPRESS");
// 在索引中存储Field的值
public static final Store YES = new Store("YES");
// 在索引中不存储Field的值
public static final Store NO = new Store("NO");
}
//通过Index设置索引方式
public static final class Index extends Parameter implements Serializable {
private Index(String name) {
super(name);
}
// 不对Field进行索引,所以这个Field就不能被检索到(一般来说,建立索引而使它不被检索,这是没有意义的)
// 如果对该Field还设置了Field.Store为Field.Store.YES或Field.Store.COMPRESS,则可以检索
public static final Index NO = new Index("NO");
// 对Field进行索引,同时还要对其进行分词(由Analyzer来管理如何分词)
public static final Index TOKENIZED = new Index("TOKENIZED");
// 对Field进行索引,但不对其进行分词
public static final Index UN_TOKENIZED = new Index("UN_TOKENIZED");
// 对Field进行索引,但是不使用Analyzer
public static final Index NO_NORMS = new Index("NO_NORMS");
}
第三个内部类是TermVector类,内部类的定义如下:
// 指定一个Field是否要存储一个词条向量,以怎样的方式来存储这个词条向量
public static final class TermVector extends Parameter implements Serializable {
private TermVector(String name) { // 通过指定一个字符串,来构造一个Field的TermVector,指定该Field的对词条的设置方式
super(name);
}
// 不存储
public static final TermVector NO = new TermVector("NO");
// 为每个Document都存储一个TermVector
public static final TermVector YES = new TermVector("YES");
// 存储,同时存储位置信息
public static final TermVector WITH_POSITIONS = new TermVector("WITH_POSITIONS");
// 存储,同时存储偏移量信息
public static final TermVector WITH_OFFSETS = new TermVector("WITH_OFFSETS");
// 存储,同时存储位置、偏移量信息
public static final TermVector WITH_POSITIONS_OFFSETS = new TermVector("WITH_POSITIONS_OFFSETS");
}
另外,Field类实现了Fieldabel接口类,可以通过了解Fieldable接口的定义,来了解Field类都实现了哪些方法,这些方法的功能是什么。
Fieldable接口类的定义如下所示:
package org.apache.lucene.document;
import java.io.Reader;
import java.io.Serializable;
import org.apache.lucene.analysis.TokenStream;
public interface Fieldable extends Serializable {
/* 设置命中该Field的boost因子,这个值将被乘到一个排序分值上,这个分值是这个Document中的该Field被命中的分值。
// The boost is multiplied by org.apache.lucene.document.Document#getBoost()} of the document。
Document的getBoost()方法返回一个值,这个值将与boost相乘,这里要求是包含该Field的Document。如果一个Document中有多个名字相同的Field,则这些值需要乘到一起。得到的乘积结果,再乘到 org.apache.lucene.search.Similarity#lengthNorm(String,int)}上,并且,在存储到索引中之前,rounded by org.apache.lucene.search.Similarity#encodeNorm(float)} 要保证乘积结果没有溢出。
*/
void setBoost(float boost);
// 返回boost的值
float getBoost();
/** 返回一个Field的内部字符串,例如:.
* "date"、"title"、"body"等等
*/
String name();
// Field的字符串值,或null。
public String stringValue();
// Field作为一个Reader的值,或null。
public Reader readerValue();
// Field作为Binary的值,或null。
public byte[] binaryValue();
// Field作为一个TokenStream的值,或null。
public TokenStream tokenStreamValue();
// 当且仅当Field的值被存储到索引中时,返回
boolean isStored();
// 当且仅当Field的被索引时,以便能够检索到,返回true
boolean isIndexed();
// Field的值是否被分词
boolean isTokenized();
// 是否被压缩存储
boolean isCompressed();
// 词条用于索引该Field,则以词条向量的形式存储
boolean isTermVectorStored();
/**
* True iff terms are stored as term vector together with their offsets
* (start and end positon in source text).
*/
boolean isStoreOffsetWithTermVector();
/**
* True iff terms are stored as term vector together with their token positions.
*/
boolean isStorePositionWithTermVector();
// Field的值是否以二进制存储
boolean isBinary();
// 该Field是否索引,但不分词
boolean getOmitNorms();
/** Expert:
*
* If set, omit normalization factors associated with this indexed field.
* This effectively disables indexing boosts and length normalization for this field.
*/
void setOmitNorms(boolean omitNorms);
// 是否延迟加载,检索
boolean isLazy();
}
通过Fieldable接口的定义,可以了解到实现该接口的Field类可以完成哪些功能了。
在Field构造好了以后,需要将每个Field添加到Document中,便于Document对Field进行管理。
Document类的源代码如下所示:
package org.apache.lucene.document;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.Searcher;
import java.util.*;
public final class Document implements java.io.Serializable {
List fields = new Vector(); // 用于管理多个Field的列表
private float boost = 1.0f;
// 构造一个不含有Field的Document对象
public Document() {}
// 参看Field中说明
public void setBoost(float boost) {
this.boost = boost;
}
public float getBoost() {
return boost;
}
// 向一个Document(向量列表)中添加Field
public final void add(Fieldable field) {
fields.add(field);
}
// 从Document中移除名称为name的Field,如果存在多个名称为name的Field,则移除第一个被添加到Document中的Field
public final void removeField(String name) {
Iterator it = fields.iterator();
while (it.hasNext()) {
Fieldable field = (Fieldable)it.next();
if (field.name().equals(name)) {
it.remove();
return;
}
}
}
// 从Document中移除名称为name的Field,如果存在多个名称为name的Field,则全部移除掉
public final void removeFields(String name) {
Iterator it = fields.iterator();
while (it.hasNext()) {
Fieldable field = (Fieldable)it.next();
if (field.name().equals(name)) {
it.remove();
}
}
}
// 从Document中获取名称为name的Field,如果存在多个名称为name的Field,则返回第一个被添加到Document中的Field
public final Field getField(String name) {
for (int i = 0; i < fields.size(); i++) {
Field field = (Field)fields.get(i);
if (field.name().equals(name))
return field;
}
return null;
}
// 从Document中获取名称为name的Field,如果存在多个名称为name的Field,则返回第一个被添加到Document中的Field
public Fieldable getFieldable(String name) {
for (int i = 0; i < fields.size(); i++) {
Fieldable field = (Fieldable)fields.get(i);
if (field.name().equals(name))
return field;
}
return null;
}
// 从Document中获取名称为name的Field的String串,如果存在多个名称为name的Field,则返回第一个被添加到Document中的Field的String串
public final String get(String name) {
for (int i = 0; i < fields.size(); i++) {
Fieldable field = (Fieldable)fields.get(i);
if (field.name().equals(name) && (!field.isBinary()))
return field.stringValue();
}
return null;
}
// 从Document中获取所有的Field,返回一个Enumeration类型
public final Enumeration fields() {
return ((Vector)fields).elements();
}
// 从Document中获取所有的Field,返回一个List类型
public final List getFields() {
return fields;
}
// 从Document中获取名称为name的所有Field,返回一个Field[]数组
public final Field[] getFields(String name) {
List result = new ArrayList();
for (int i = 0; i < fields.size(); i++) {
Field field = (Field)fields.get(i);
if (field.name().equals(name)) {
result.add(field);
}
}
if (result.size() == 0)
return null;
return (Field[])result.toArray(new Field[result.size()]);
}
// 从Document中获取名称为name的所有Field,返回一个Fieldable[]数组
public Fieldable[] getFieldables(String name) {
List result = new ArrayList();
for (int i = 0; i < fields.size(); i++) {
Fieldable field = (Fieldable)fields.get(i);
if (field.name().equals(name)) {
result.add(field);
}
}
if (result.size() == 0)
return null;
return (Fieldable[])result.toArray(new Fieldable[result.size()]);
}
/// 从Document中获取名称为name的所有Field的字符串值,返回一个字符串数组
public final String[] getValues(String name) {
List result = new ArrayList();
for (int i = 0; i < fields.size(); i++) {
Fieldable field = (Fieldable)fields.get(i);
if (field.name().equals(name) && (!field.isBinary()))
result.add(field.stringValue());
}
if (result.size() == 0)
return null;
return (String[])result.toArray(new String[result.size()]);
}
// 从Document中获取名称为name的所有Field的byte[] 的数组值,返回一个byte[][]数组
public final byte[][] getBinaryValues(String name) {
List result = new ArrayList();
for (int i = 0; i < fields.size(); i++) {
Fieldable field = (Fieldable)fields.get(i);
if (field.name().equals(name) && (field.isBinary()))
result.add(field.binaryValue());
}
if (result.size() == 0)
return null;
return (byte[][])result.toArray(new byte[result.size()][]);
}
// 从Document中获取名称为name的所有Field的byte字节值,返回一个byte[]数组
public final byte[] getBinaryValue(String name) {
for (int i=0; i < fields.size(); i++) {
Fieldable field = (Fieldable)fields.get(i);
if (field.name().equals(name) && (field.isBinary()))
return field.binaryValue();
}
return null;
}
// 输出Document中所有Field的名称(以字符串的形式)
public final String toString() {
StringBuffer buffer = new StringBuffer();
buffer.append("Document<");
for (int i = 0; i < fields.size(); i++) {
Fieldable field = (Fieldable)fields.get(i);
buffer.append(field.toString());
if (i != fields.size()-1)
buffer.append(" ");
}
buffer.append(">");
return buffer.toString();
}
}
Document类的最后一个方法,输出了一个Document中的所有的Field的信息,以字符串的形式输出,这个可以在检索的时候,看到具体检索关键字检索到的信息的详情,可以在文章 Lucene-2.2.0 源代码阅读学习(4) 中看到输出示例。
做个简单的例子:
直接在程序中通过字符串构造Field。
测试的主函数代码如下所示:
package org.shirdrn.lucene;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
public class DcoumentAndField {
public static void main(String[] args) {
Document doc = new Document();
Field f1 = new Field("检索","不以物喜,不以己悲。",Field.Store.YES,Field.Index.TOKENIZED);
Field f2 = new Field("雅诗","衣带渐宽终不悔,为伊消得人憔悴。",Field.Store.NO,Field.Index.UN_TOKENIZED);
Field f3 = new Field("娱乐","某某透露,最终决定,要坚持走出一条属于自己的人生路。",Field.Store.NO,Field.Index.NO_NORMS);
Field f4 = new Field("娱乐","百度的门户建设,应该是一件不容忽视的事件。",Field.Store.NO,Field.Index.NO_NORMS);
doc.add(f1);
doc.add(f2);
doc.add(f3);
doc.add(f4);
System.out.println("所有的Field信息 :"+doc.toString());
System.out.println("获取指定Field信息:"+doc.get("雅诗"));
System.out.println("获取指定Field信息:"+doc.getField("检索"));
System.out.println("指定Field信息[0]:"+doc.getValues("娱乐")[0]);
System.out.println("指定Field信息[1]:"+doc.getValues("娱乐")[1]);
}
}
运行结程序,输出结果如下所示:
所有的Field信息 :Document
获取指定Field信息:衣带渐宽终不悔,为伊消得人憔悴。
获取指定Field信息:stored/uncompressed,indexed,tokenized<检索:不以物喜,不以己悲。>
指定Field信息[0]:某某透露,最终决定,要坚持走出一条属于自己的人生路。
指定Field信息[1]:百度的门户建设,应该是一件不容忽视的事件。
到目前为止,已经对Field和Document很熟悉了。
然后,又要回到IndexWriter类了,该类特别重要,同时又是特别复杂的。IndexWriter初始化完成后,才开始了真正地建立索引的过程。建立索引是从,向一个IndexWriter实例中添加Document开始。
因此,要用到IndexWriter类的一些有用的方法了。