说到常规场景下的倒排索引,那么大家第一时间想到的肯定是基于es实现
这个也是我在之前某个推荐引擎中首个使用的中间件
简单说一下场景,就是每天会有100-200万条记录,大概有十个字段需要用来查询,其中还有一个字段,需要拿来排序,超过需要的数目时排序后进行截断。
大概如下面的表所示:
如果使用es,那么直接针对这几列建立索引,然后直接查询即可
但是,我们的服务对tp99 有要求,其实所有的互联网服务都对tp99、tp999有要求,如果是直接面向用户的,那么这个时间可能在500ms左右,但是这个500ms往下分配的时候,给我们分配就往往没有这么多时间了,很多情况下,给单纯的推荐流程只会有100-200ms的时间。这个时间除了用来召回,还有各种各样的粗排序,特征查询,精排等过程,那么其中的召回和粗排序,基本只能排下来50ms的时间了,那么,可见我们常见的es就不能满足这个需求。
放弃了es,后续我尝试了下redis,就是将几个key的组合结果离线计算然后存储到redis,结构如下
key结构:c1_c4_c6
value:1,2,3,4,5,6,7,8...10000
这样导致的结果是存储的结果不是很多,当需要往对应的结果存储1000个item的时候,带来的大key问题不容忽视。
到这里,基本只能想办法自己啃这个硬骨头,既然要降低时间复杂度,那么就只能从空间复杂度上手:
用hashmap套hashmap这种形式,数据中存储排序后的数据,那么基本解决了这个问题:tp999:2ms,随之相应的,吞吐量也有了很大的提升,但是也带了其他问题:占用了很大的内存,如果直接dump这个对象基本是4G左右的文件,后面想试试用cuckoo hash的方式,降低内存的消耗,那就是另外一个问题了。