-->step1: IndexWriter
Document
-->分词、search ...
Field
------------------Document--------------------
Document
public final class Document implements java.io.Serializable
Document类具备这些功能:增加及删除域、获取域对象或域值、设置及获取boost。
注:1.在一个document对象里多个域可以同名。
2.获取的域值可以是String、byte[]。
【源码分析】
1.Document类实现了序列化java.io.Serializable接口
2.Document类里提供了一个ArrayList,用来存放Field对象。一个Document对象不会有多线程读写field。
3.向document对象里添加Fieldable型Field对象,其实是add到list中,方法如下:
public final void add(Fieldable field) {
fields.add(field);
}
其中fields是List<Fieldable> fields = new ArrayList<Fieldable>();
加进来的field是可以同名的,这样的话,同名的那些field的值在search的时候会被append起来。
removeField(String name) 用来从document对象里将某个field删除掉,本质就是通过迭代器从存放Fieldable的list里删除。
public final void removeField(String name) {
Iterator<Fieldable> it = fields.iterator();
while (it.hasNext()) {
Fieldable field = it.next();
if (field.name().equals(name)) {
it.remove();
return;
}
}
}
注意:API中对remove和add方法有这样的说明:
the removeField(s) methods like the add method only make sense prior to adding a document to an index.
如果想要改变一个已经存在的索引的内容的话,对该document对象add(Fieldable)和removeField(s)(String name)是不起作用的,如果想要达到这个目的的话,只能先将特定的document对象从index里删除,然后添加新的document对象。
Q:如果从已有index中获取document对象,然后操作add或者remove,那么索引会发生变化么?操作后通过提交更新能起作用么?
Q:boost什么作用?
------------------Field--------------------
public final class Field
extends AbstractField
implements Fieldable, Serializable
【Fieldable】
public interface Fieldable extends Serializable
【AbstractField】
public void setOmitTermFreqAndPositions(boolean omitTermFreqAndPositions) { this.omitTermFreqAndPositions=omitTermFreqAndPositions; }
omit 忽略 term freq, positions and payloads from postings for this field.
在lucene建立起倒排索引后,为了实施Vector Space Model,会保存必要的信息,比如该model需要计算文档中出现的term数(term freq)以及positions(这些信息在词组搜索时会用到),但是有时候这些域只是用在布尔搜索中,它们不为相关评分做贡献,比如该域被用作过滤(权限过滤或者日期过滤),在这些布尔查询中,是不需要前面提到的额外信息的,为了节省磁盘上存储空间及加速搜索和过滤过程,可以通过Field.setOmitTermFreqAndPositions(true) 来让lucene跳过对该项的出现频率和出现位置的索引。
【Field】
构造field对象时field的值可以是String、Reader、org.apache.lucene.analysis.TokenStream、byte[]类型。
构造:
域值是Reader——isStored=false、isIndexed=true、isTokenized=true
Q:TokenStream是什么类?
当创建好一个域时,可以指定多个域选项来控制Lucene在将文档添加进索引后针对该域的行为。
【域选项】
域索引选项(Field.Index.*)控制该域是否被索引以及怎样索引。如果需要搜索某个域,则必须首先对该域索引。
public static enum Index {
NO {
@Override
public boolean isIndexed() { return false; }
@Override
public boolean isAnalyzed() { return false; }
@Override
public boolean omitNorms() { return true; }
},
ANALYZED {
@Override
public boolean isIndexed() { return true; }
@Override
public boolean isAnalyzed() { return true; }
@Override
public boolean omitNorms() { return false; }
},
NOT_ANALYZED {
@Override
public boolean isIndexed() { return true; }
@Override
public boolean isAnalyzed() { return false; }
@Override
public boolean omitNorms() { return false; }
},
//....其他域选项值省略.....
}
** Index.NO ——对应的域不会被搜索。但是如果该域的存储选项设置为Store.stored,那么在结果中是可以看到该域的。
** Index.ANALYZED ——该选项适用于普通文本域(正文、标题、摘要等)
field values ==>by Analyzer ==>a stream of separate tokens
这些tokens是searchable的。searchable是指当用户输入keywords,这些keywords经过Analyzer后会与上述token匹配。
** Index.NOT_ANALYZED——与Index.ANALYZED相比,对域进行索引,但不会对String域值利用Analyzer进行分析,即将该域值作为单一token
并使之能够被搜索。该选项适用于那些不被分解的域值,比如URL、文件路径、日期、人名、号码、标识ID等,尤其适用于“精确匹配”搜索。
Q:isIndexed和isAnalyzed有何区别?isIndexed决定该域是否被索引,也就决定了该域是否能够被搜索。isAnalyzed决定了是否对该域值使用Analyzer,如果使用,则域值会被分解为若干个token,否则作为单一token。
** Index.ANALYZED_NO_NORMS
Index.ANALYZED的变体
** Index.NOT_ANALYZED_NO_NORMS
Index.NOT_ANALYZED的变体
关于
1.norms参见
2.倒排索引
3.Vector Space Model
域存储选项(Index.Store.*) 决定域的原始值是否被存储在索引中,如果存储则会随搜索结果展示。
public static enum Store {
YES {
@Override
public boolean isStored() { return true; }
},
NO {
@Override
public boolean isStored() { return false; }
};
public abstract boolean isStored();
}
** Store.YES 适用于那些文本比较短并且需要在搜索结果中展示的域,比如URL、标题、id。按照原始值来存储,并且存储前不会使用analyzer。
** Store.NO
域的项向量选项term vectors(Field.TermVector)
public static enum TermVector {
NO {
@Override
public boolean isStored() { return false; }
@Override
public boolean withPositions() { return false; }
@Override
public boolean withOffsets() { return false; }
},
YES {
@Override
public boolean isStored() { return true; }
@Override
public boolean withPositions() { return false; }
@Override
public boolean withOffsets() { return false; }
},
WITH_POSITIONS {
@Override
public boolean isStored() { return true; }
@Override
public boolean withPositions() { return true; }
@Override
public boolean withOffsets() { return false; }
},
WITH_OFFSETS {
@Override
public boolean isStored() { return true; }
@Override
public boolean withPositions() { return false; }
@Override
public boolean withOffsets() { return true; }
},
WITH_POSITIONS_OFFSETS {
@Override
public boolean isStored() { return true; }
@Override
public boolean withPositions() { return true; }
@Override
public boolean withOffsets() { return true; }
};
public static TermVector toTermVector(boolean stored, boolean withOffsets, boolean withPositions) {
// If it is not stored, nothing else matters.
if (!stored) {
return TermVector.NO;
}
if (withOffsets) {
if (withPositions) {
return Field.TermVector.WITH_POSITIONS_OFFSETS;
}
return Field.TermVector.WITH_OFFSETS;
}
if (withPositions) {
return Field.TermVector.WITH_POSITIONS;
}
return Field.TermVector.YES;
}
public abstract boolean isStored();
public abstract boolean withPositions();
public abstract boolean withOffsets();
}