作者回复: 你注意到了这个问题,非常棒!多问为什么,你就会想得更明白。 你可以想一下,lru把一个元素提到链表头是怎么操作的。步骤如下: 1.查询哈希表 2.通过哈希表直接访问到链表中的节点k(注意:节点k不是遍历链表得到的!是哈希表直接定位的!因此,我们此时并不知道k的前序节点是哪个)。 3.将节点k提到链表头。到这一步的时候,你就会发现,如果链表是单链表的话,那么如何把k节点从链表中摘取出来,然后链表还不能被打断,这就成了一个问题了。因此,我们用双向链表,就可以快速地找到k节点的前序节点,这样就能完成节点k的摘取操作。
作者回复: 1.调整次序涉及到预估代价的问题,因此如果对于系统的数据分布情况不清楚的话,的确效果不见得好。可以在有把握的情况下才调整。 2.3.你会发现,检索核心技术是通用的,大数据时代的各个框架都会用相似的技术来进行加速处理。万变不离其宗。 4.非常好!任何方案都有自己的适用场景。因此我们才需要学习它们的实现原理。缓存法适用于有查询热点存在的场景。否则如果没有热点,缓存的命中率不高,它反而会造成无谓的缓存管理代价。
作者回复: 其实每种方法都有要注意的问题,都需要进行一定的优化才能更好地发挥效果。 1.调整批次法要预判是否调整以后有效,否则如果调整前和调整后性能差不多,那么无谓的调整反而会增大开销。 2.快速多路归并法适用在要归并的key较多且posting list较长的情况下。否则频繁的排序调整也是一个额外开销。 而预先组合和缓存法,就像你说的,需要有合理的实时更新方案。而且缓存法适用于有热点的情况下,并且需要设置缓存的生命周期,在一些场景下,还要解决数据一致性,缓存击穿等问题。 因此,我们无论是使用什么方法,一定要深入了解这种方法的优点和缺点,并针对具体场景采用合适的解决方案。
作者回复: 起名字的确是个难题。基础篇会比较偏算法,但是进阶篇开始会有一些系统设计和更全面的知识。所以最后还是定了这么一个“朴实无华且枯燥”的题目。希望到后面全部看下来都能保持轻松愉快😄
作者回复: 总结得很好。es中也用了快速多路归并法,因此你现在了解了这个算法以后,再去看es的相关代码,相信就容易理解了。 至于3和4,你的举例和总结都很好。其实在你们的广告系统中,如果想提高性能,也可以试试这两种方案。
作者回复: 你的理解是对的。accessOrder = true,表示“使用最近最少访问次序”,那么按照“最近最少使用”来排序的话,就是1,3,2了。 当然,由于是双链表,因此不管是升序还是降序都可以操作,只要弄清楚链表头和链表尾元素的意义就好。
作者回复: 临时建立数据结构往往开销都挺大,因此一般来说,我们都是提前建立好索引。 如果数据集本身是静态的不可变的,没有实时插入删除的问题,那么其实完全可以使用数组代替跳表,这样空间也紧凑,还能利用内存局部性原理进行加速。