lucene5.1 fst源码分析(fst接口方法写入和读取测试)
2017-04-22 15:41
447 查看
1 fst基本概念
1-1 节点node和弧arc
2 lucene中的fst测试代码
3 源码分析
3-1 util的get方法分析
3-2 FST的findTargetArc方法
3-2-1 类成员变量介绍
3-2-2方法原型
3-2-3源码分析
3-3 readFirstRealTargetArc方法
3-3 readNextRealArc方法
![](https://oscdn.geek-share.com/Uploads/Images/Content/201908/31/3bc429c1475c7b8e9a22c3f46ef7b6ee)
其中的labelToMatch是要查找的byte,一般是一个字符,follow是前一个弧,在执行中只提供自己的target,即follow的tonode的起始地址,目标arc肯定挂在这个tonode下。arc是要查找的弧,在传入时,和follow相同,在后续的执行中该arc的内部变量会被不断替换,最后返回的也是这个arc。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201908/31/e71a413e100973e6e2e1e367779ee156)
1-1 节点node和弧arc
2 lucene中的fst测试代码
3 源码分析
3-1 util的get方法分析
3-2 FST的findTargetArc方法
3-2-1 类成员变量介绍
3-2-2方法原型
3-2-3源码分析
3-3 readFirstRealTargetArc方法
3-3 readNextRealArc方法
.1 fst基本概念
有限状态机.1-1 节点(node)和弧(arc)
node包含了进入该node的0个或者多个arc,也包含了从该node走出的0个或者多个arc.2 lucene中的fst测试代码
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.StringReader; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.core.WhitespaceTokenizer; import org.apache.lucene.analysis.synonym.SynonymFilterFactory; import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.analysis.util.FilesystemResourceLoader; import org.apache.lucene.store.DataInput; import org.apache.lucene.store.InputStreamDataInput; import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.BytesRefBuilder; import org.apache.lucene.util.CharsRef; import org.apache.lucene.util.IntsRef; import org.apache.lucene.util.IntsRefBuilder; import org.apache.lucene.util.NumericUtils; import org.apache.lucene.util.Version; import org.apache.lucene.util.fst.Builder; import org.apache.lucene.util.fst.ByteSequenceOutputs; import org.apache.lucene.util.fst.FST; import org.apache.lucene.util.fst.FST.INPUT_TYPE; import org.apache.lucene.util.fst.PositiveIntOutputs; import org.apache.lucene.util.fst.Util; public class FSTTest2 { public static void main(String[] args) throws IOException { String inputValues[] = {"mop", "moth", "pop","star","stop","top"};//输入 long outputValues[] = {5, 7, 12, 14, 18,20};//输出。在lucene中即为term后缀在tim文件中的偏移量 // String inputValues[] = { "xstop", "xstopxx", "yxxxstop" }; // long outputValues[] = { 12, 10, 6}; PositiveIntOutputs outputs = PositiveIntOutputs.getSingleton(); Builder<Long> builder = new Builder<Long>(INPUT_TYPE.BYTE1, outputs); BytesRef scratchBytes = new BytesRef(); IntsRefBuilder ifb = new IntsRefBuilder(); IntsRefBuilder scratchInts = new IntsRefBuilder(); BytesRefBuilder bfb = new BytesRefBuilder(); //插入输入和输出到fst中 for (int i = 0; i < inputValues.length; i++) { CharSequence cs = inputValues[i]; NumericUtils.intToPrefixCodedBytes(inputValues[i].length(), 0, bfb); builder.add(Util.toUTF32(cs, ifb), outputValues[i]); } //构建字节流索引 FST<Long> fst = builder.finish(); Long value = Util.get(fst, new BytesRef("stop"));//根据输入得到输出 System.out.println(value); } }
.3 源码分析
.3-1 util的get方法分析
public static<T> T get(FST<T> fst, BytesRef input) throws IOException { assert fst.inputType == FST.INPUT_TYPE.BYTE1; final BytesReader fstReader = fst.getBytesReader(); // TODO: would be nice not to alloc this on every lookup final FST.Arc<T> arc = fst.getFirstArc(new FST.Arc<T>()); // Accumulate output as we go T output = fst.outputs.getNoOutput();//初始化输出 for(int i=0;i<input.length;i++) { if (fst.findTargetArc(input.bytes[i+input.offset] & 0xFF, arc, arc, fstReader) == null) {//寻找一个字符,即寻找一个arc return null; } output = fst.outputs.add(output, arc.output);//累加每个弧上的输出 } if (arc.isFinal()) { return fst.outputs.add(output, arc.nextFinalOutput); } else { return null; } }
.3-2 FST的findTargetArc方法
.3-2-1 类成员变量介绍
.3-2-2方法原型:
private Arc findTargetArc(int labelToMatch, Arc follow, Arc arc, BytesReader in, boolean useRootArcCache)其中的labelToMatch是要查找的byte,一般是一个字符,follow是前一个弧,在执行中只提供自己的target,即follow的tonode的起始地址,目标arc肯定挂在这个tonode下。arc是要查找的弧,在传入时,和follow相同,在后续的执行中该arc的内部变量会被不断替换,最后返回的也是这个arc。
.3-2-3源码分析
in.setPosition(getNodeAddress(follow.target)); arc.node = follow.target;//follow的tonode就是目标弧的fromnode // System.out.println("fta label=" + (char) labelToMatch); // Linear scan readFirstRealTargetArc(follow.target, arc, in);//例如找到上图中最左边那个假节点的第一个真的目标弧,例如本次会找到m while(true) { //System.out.println(" non-bs cycle"); // TODO: we should fix this code to not have to create // object for the output of every arc we scan... only // for the matching arc, if found if (arc.label == labelToMatch) { //System.out.println(" found!"); return arc;//匹配上就返回这个arc } else if (arc.label > labelToMatch) { return null; } else if (arc.isLast()) { return null; } else { readNextRealArc(arc, in);//没有匹配上label,就继续找 } }
.3-3 readFirstRealTargetArc方法
public Arc<T> readFirstRealTargetArc(long node, Arc<T> arc, final BytesReader in) throws IOException { //这里的node,是上一次匹配上的那个弧的tonode,要找下一个匹配弧,就要在这个tonode的弧里找,所以把这个地址所以本次查找的起始地址 final long address = getNodeAddress(node); in.setPosition(address); //System.out.println(" readFirstRealTargtArc address=" //+ address); //System.out.println(" flags=" + arc.flags); arc.node = node;//这个node是上一个弧的targetnode,也是本次弧的fromnode(1) if (in.readByte() == ARCS_AS_FIXED_ARRAY) { //System.out.println(" fixedArray"); // this is first arc in a fixed-array arc.numArcs = in.readVInt(); if (packed || version >= VERSION_VINT_TARGET) { arc.bytesPerArc = in.readVInt(); } else { arc.bytesPerArc = in.readInt(); } arc.arcIdx = -1; arc.nextArc = arc.posArcsStart = in.getPosition(); //System.out.println(" bytesPer=" + arc.bytesPerArc + " numArcs=" + arc.numArcs + " arcsStart=" + pos); } else { //arc.flags = b; arc.nextArc = address;//一个弧的nextArc,是这个弧的fromnode的下一个弧。但是这个弧在构造阶段,nextArc就是他自己 arc.bytesPerArc = 0; } return readNextRealArc(arc, in);//该行以上代码初始化了一个arc的fromnode((1)处),也初始化了一个arc的nextArc位置,下来就是要给arc的其他变量赋值,就在这个方法中
.3-3 readNextRealArc方法
// this is a continuing arc in a fixed array if (arc.bytesPerArc != 0) { // arcs are at fixed entries arc.arcIdx++; assert arc.arcIdx < arc.numArcs; in.setPosition(arc.posArcsStart); in.skipBytes(arc.arcIdx*arc.bytesPerArc); } else { // arcs are packed //packed的arc表示什么意思??? in.setPosition(arc.nextArc);//在初始阶段,一个arc的nextArc表示这个arc的fromnode的第一个弧的位置,所以可以作为这个arc的起始位置(这个arc的fromnode的真正的nextArc在后边会设置) } arc.flags = in.readByte();//读取flags arc.label = readLabel(in);//读取label //判断是否有输出 if (arc.flag(BIT_ARC_HAS_OUTPUT)) { arc.output = outputs.read(in); } else { arc.output = outputs.getNoOutput(); } //判断是否有final_output if (arc.flag(BIT_ARC_HAS_FINAL_OUTPUT)) { arc.nextFinalOutput = outputs.readFinalOutput(in); } else { arc.nextFinalOutput = outputs.getNoOutput(); } //是否是stopnode if (arc.flag(BIT_STOP_NODE)) { if (arc.flag(BIT_FINAL_ARC)) { arc.target = FINAL_END_NODE; } else { arc.target = NON_FINAL_END_NODE; } arc.nextArc = in.getPosition(); } else if (arc.flag(BIT_TARGET_NEXT)) {//这个弧是否有target_next优化(target_next优化见下边解释) arc.nextArc = in.getPosition(); // TODO: would be nice to make this lazy -- maybe // caller doesn't need the target and is scanning arcs... //如果有target_next优化,就需要调用者开始扫描该节点后续的所有弧,所有的弧都跳过后,就是当前弧的tonode起始地址 if (nodeAddress == null) { if (!arc.flag(BIT_LAST_ARC)) { if (arc.bytesPerArc == 0) { // must scan seekToNextNode(in); } else { in.setPosition(arc.posArcsStart); in.skipBytes(arc.bytesPerArc * arc.numArcs); } } //跳过了当前节点的所有弧后,就是当前节点的targe节点了,从这个target节点开始,就可以读当前弧的下一个弧了(不是next,是tonode的弧) arc.target = in.getPosition(); } else { arc.target = arc.node - 1; assert arc.target > 0; } } else { if (packed) { final long pos = in.getPosition(); final long code = in.readVLong(); if (arc.flag(BIT_TARGET_DELTA)) { // Address is delta-coded from current address: arc.target = pos + code; //System.out.println(" delta pos=" + pos + " delta=" + code + " target=" + arc.target); } else if (code < nodeRefToAddress.size()) { // Deref arc.target = nodeRefToAddress.get((int) code); //System.out.println(" deref code=" + code + " target=" + arc.target); } else { // Absolute arc.target = code; //System.out.println(" abs code=" + code); } } else { arc.target = readUnpackedNodeTarget(in);//如果没有target_next优化,需要再读一个字节,就可以得到这个弧的tonode的起始地址了,这是一个seek过程 } arc.nextArc = in.getPosition(); } return arc; }
相关文章推荐
- lucene5.1 fst源码分析(嵌入到lucene中的写入过程)
- lucene5.1 fst源码分析(BooleanQuery分析)
- selenium+python关于登录的脚本代码,使用了读取excel以及向excel中写入测试结果的方法
- Google Test(GTest)使用方法和源码解析——模板类测试技术分析和应用
- Spring源码分析之BeanPostProcessor接口和BeanFactoryPostProcessor接口方法不执行原因分析
- 实验报告: 人脸识别方法回顾与实验分析 【OpenCV测试方法源码】
- java再复习——多线程之初识线程,并从源码角度分析start与run方法,Thread类与Runnable接口
- Orchard源码分析(5.1):Host初始化(DefaultOrchardHost.Initialize方法)
- Elasticsearch源码分析六--调用Lucene查询接口之前缀查询(Prefix)
- Elasticsearch源码分析二--调用Lucene查询接口之常用词查询
- Orchard源码分析(5.1):Host初始化(DefaultOrchardHost.Initialize方法)
- Google Test(GTest)使用方法和源码解析——私有属性代码测试技术分析
- Elasticsearch源码分析四--调用Lucene查询接口之通配符查询
- Elasticsearch源码分析五--调用Lucene查询接口之模糊查询(Fuzzy)
- Mybatis执行dao接口方法的流程梳理及源码分析
- Elasticsearch源码分析三--调用Lucene查询接口之词条查询
- Spring源码分析之BeanPostProcessor接口和BeanFactoryPostProcessor接口方法不执行原因分析
- Google Test(GTest)使用方法和源码解析——死亡测试技术分析和应用
- jQuery.when()方法测试笔记及源码分析
- selenium+python关于登录的脚本代码,使用了读取excel以及向excel中写入测试结果的方法