三人行必有我师

Lucene里面的FST

Lucene | 作者 Charele | 发布于2024年05月12日 | 阅读数:2812

关于ES/Lucene,不可避免的要提到FST。
无疑这是Lucene比较核心的一块内容。
 
B站视频找了下没有有价值的(都是3言2语一带而过)。
网上文章还是挺多的,比如大神博客:
https://amazingkoala.com.cn/Lu ... 2589/
 这个也不错,:
https://blog.csdn.net/zx201130 ... 94342 

 (我看网上FST文章时,我是糊里糊涂的,后来看了代码后才能理解它的意思。)
 
细看这个文章: 
1111.PNG

1 不止两个,还有一个tmd文件
2 FST里面key是单词前缀(我感觉“块前缀”更准确一些),但value不是他说的这个
 
可能是版本原因,以现在版本深究的话,这个文章有很多“错误”。
如果你只是大概了解下,则不必在意这些细节
已邀请:

Charele - Cisco4321

赞同来自:

如果我有这么一个FST,它在tip文件中是如何表示的呢?
2222.PNG

PS:图中的节点A,B,C什么的,它是不存的,它只存边。
(这些A,B,C,,,只是这里用来描述节点,没有实际意义)
你肯定听说过“尾部冻结”这个说法,
冻结的过程,就是把一个节点的所有边写到内存数组的过程(最后会一起写到文件)。
冻结是以节点为单位的,而节点本身是不存的。
  这点在我刚开始的时候,很不理解,边都堆一起,岂不是分不清是哪条边了?
 
原始的存储方式很直观,为了查询(读取)效率,会产生3个变种。
要说的就是这3个变种,这是以空间换时间的做法。

Charele - Cisco4321

赞同来自:

1111.PNG

引用网上的一个图,这是常规的方式。每条边按顺序一个一个排起来,
其中的一条边最少会有两个元素(红色的),最多有5个(加上绿色的)
受大神博客的影响,我习惯上称这5个信息为“5元组“。
 
我一直有个疑问:他写是顺序写的,写完这个节点后会倒一下。然后读的时候会倒着读。
不晓得为什么要这么做,就顺着写顺着读不行吗?

Charele - Cisco4321

赞同来自:

1111.PNG

引出问题:
假如一个节点的边有很多,label为1,2,3,4,,,x,
如果你要找x这条边,你就得1,2,3,,,
一直读到最后一条边,才能找到这个边(或者说才晓得这个边存不存在), 
如果一个节点有一千条边呢?在这效率上就有点不如人意了。

Charele - Cisco4321

赞同来自:

在处理(冻结)一个节点时,会有一个判断,决定是不是用变种存储。

上面提到,一个边最少存2两元素,最多5个,所以占用的字节大小也不一样。
如果用变种,则每个边用固定的最大的那个长度来存,“WithFixedLengthArcs”。
这无疑会浪费空间,但会提高读时的效率。
1111.PNG

方法里的条件就是:(节点深度 <=3 and 节点边数 >= 5) or (边数 >= 10)
上面的例子,边数是10个,符合这个条件
 
这个判断是按每个节点来进行的,并不是全局的。
 
如果此方法返回false, 则用常规方式。

Charele - Cisco4321

赞同来自:

冻结一个节点时,依次(按边的label顺序)记录每一条边的5元组信息(有几个记几个)。
要注意的是这里:
1111.PNG

只有在常规情况下才会记录5元组中的target信息。
在变种情况下,是不用target的,
(target用来在逻辑上连结,但物理上不相领的的边,需要一个target来寻址)。
 

Charele - Cisco4321

赞同来自:

当一个节点的所有边信息都搞完后,如果是变种,
会把这堆信息,做一个处理,以便于能高效寻址。
变种会分为3种情况,(效率从高到低)
1 连续的 2 直接访问 3 二分查找
2222.PNG

其中紫色表示所有边的label字母是连续的,
上面的例子label是1,2,3,4,,,8,9,x,是不连续的,所以不能用方式1
能不能用方式2,这里有一个判断条件。
最后的选择是二分查找。
 
 然后就是把这些信息倒一下(读是倒着读的)写到内存,
现在不写文件,最后FST编译时才写
 
https://zhuanlan.zhihu.com/p/671225495
这篇文章简明偶要地说到了后两种方式的布局,
现在详细说下第一种方式的处理过程。 (3种处理方式有点类似)
 

要回复问题请先登录注册