summer-trie 一个简单好用的前缀树工具

13 天前
 DennyFly

summer-trie

项目地址

github https://github.com/chitucao/summer-trie.git

gitee https://gitee.com/chitucao/summer-trie.git

介绍

​ 这是一个节点支持任意数据类型的前缀树,适用于大量列表数据的索引和压缩,不同于有限字符集前缀树实现(每个节点表达的状态是同一类型),主要是设计思想是将数据中多个不同类型的字段作为节点,组合成一颗前缀树,提高这些字段的检索性能;

​ 目前是用于同程旅行盲盒机票、火车票的本地资源预筛选、数据分析以及校验场景下的结果缓存;

​ 如果使用的过程中发现有 bug ,或者希望添加额外的功能,欢迎提交 PR;

适用于以下场景

关键功能和特性

几种核心的查询方式

核心概念

节点( Node )

字典( Dict )

属性( Property )

配置( Configuration )

快速开始

新建前缀树

1.作为索引,并查询原始数据

2.用作索引,只查询索引

3.用于压缩

添加数据

删除数据

查询数据

1.按层查询

List<Integer> queryDepCityList = Lists.newArrayList(144, 145, 146, 900);
List<Integer> indexList1 = dataList.stream().filter(e -> queryDepCityList.contains(e.getDepartureCityId())).map(TrainSourceDO::getArrivalCityId).distinct().sorted()
            .collect(Collectors.toList());

Criteria criteria = new Criteria();
criteria.addCriterion(Condition.IN, queryDepCityList, "depCityId");
List<Integer> indexList2 = trie.<Integer> propertySearch(criteria, "arrCityId").stream().sorted().collect(Collectors.toList());

2.原始数据查询

Criteria criteria = new Criteria();
criteria.addCriterion(Condition.IN, queryDepCityList, "depCityId");
List<TrainSourceDO> dataList2 = trie.dataSearch(criteria).stream().sorted(Comparator.comparing(TrainSourceDO::getId)).collect(Collectors.toList());

3.树结构查询

4.列表结构查询

5.字典值查询

序列化和反序列化

项目

性能分析和对比

树和位图

1.树

2.位图

前缀树和 B+树

前缀树的种类和变种

生产和个人实践

盲盒项目的背景和痛点

​ 在盲盒的开盒流程中,会对本地资源预筛后再去请求实时的搜索接口,为了提高对这份资源的检索速度,用到了位图索引;

​ 资源筛选的流程中,用户的出发地是确定的,日期,价格区间这些是随机变量,先随机日期,然后随机价格区间;

问题 1:开盒成功率低

​ 日期随机可以有两种做法,一种是从配置上指定的固定日期区间随机,另一种是拿到这个出发地下有效的出发日期然后随机。早期一直是用的第一种做法,直到目的地盲盒的出现,资源的数量太少了,对应的有效日期也变少了,所以固定日期随机会导致开盒成功率降低很多。这个时候想到了有效日期随机,先拿到这个出发地下所有有效日期,再从这些有效日期中随机,可以提高开盒成功率;

​ 如果用位图实现的话,为了得到指定出发地下的所有有效日期,需要过滤出所有原始数据,拿到日期去重后再随机,后面的随机价格区间同理,需要根据出发地和日期再过滤一次,这样查下来效率还是很低的;

​ 所以想到了使用前缀树这种结构,如果按照出发地,日期,价格区间建立节点并依次查询,可以有效减少查询范围;

问题 2:资源预校验效率低

​ 有些活动的库存数量是有限的,为了尽量提高开盒成功率,所以在用户实际开盒前会做一次资源预校验,根据用户的出发地和业务的一些策略配置,判断用户有没有有效的抵达地,如果用户没有有效抵达地资源,就提前拦截掉,避免无效的库存消耗;

​ 如果每次请求方每次都过来查显然是不行的,所以限制请求方在场次开始前只查询一次,结果包含所有的有效出发地和抵达地,然后由请求方缓存起来。这个结果是和活动场次相关的,毕竟每个活动场次里面配置的产品和策略都不一样,用这个配置去全量的资源池中过滤出有效的出发抵达地返回;

​ 随着活动场次越来越多和策略配置的精细化,即使是每个场次只查询一次,也会带来很大的查询压力以及可能的超时问题,所以想到了由服务提供方这边也建立一份缓存,定时刷新;

​ 这份缓存就很适合用前缀树实现,按照活动、场次、产品、出发城市、出发日期、抵达城市构建;

​ 有两个场景可以使用这份缓存:

​ 1.查询条件指定场次,查询结果指定出发城市+抵达城市,就是资源预校验的结果;

​ 2.场次确定了,那么从这个场次相关的预校验缓存里面去拿到的有效出发日期、有效价格区间、有效抵达地,会进一步减少数据范围,提高查询效率;

用于资源分析

实现低价日历

586 次点击
所在节点    问与答
3 条回复
pxiphx891
12 天前
感谢分享,正好之前有一个场景想用前缀树实现;另外想问几个问题:
1. 项目名称中的 summer 是什么意思?
2. 可以提供一个 maven 坐标或者打一个 jar 包吗?
3. 有和其他开源实现的功能对比和性能对比吗?
DennyFly
12 天前
问题 1:我还有一个别的项目,叫 summer-framework ,这是其中的一个工具,summer 是因为 spring....
问题 2:后续打算打一个;
问题 3:工具很多功能是近期写完的,目前只是我自己做的项目用,后续接了更多的业务场景对比一下;
DennyFly
12 天前
@pxiphx891 推到公共仓库了,还在发布中,明天应该好了~
<dependency>
<groupId>top.chitucao.summerframework</groupId>
<artifactId>summer-trie</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1075176

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX