数据结构与算法--实战应用

实战应用

推荐系统

比如音乐推荐,有两种方式:

  • 找口味相似的用户,推荐他们爱听的歌
  • 推荐跟喜爱歌曲特征相似的歌

基于相似用户推荐

​ 对用户的歌曲进行评分:5(单曲循环)、4(喜爱)、3(收藏)、2(搜索)、1(听完)、0(没听过)、-1(跳过),则:

​ 欧几里得距离越小,用户口味越相近,更优先推荐用户口味相近的人听过的歌曲

基于相似歌曲推荐

​ 同理对歌曲计算欧几里得距离:

数据库索引

设计考虑

  1. 数据是格式化数据还是非格式化数据,对于非结构化数据,需要预处理提取关键词,对关键词构建索引
  2. 数据是静态数据还是动态数据,对于静态数据只需考虑查询效率,对于动态数据还需考虑更新索引成本
  3. 数据量大还是小,对于少量索引存内存效率高,若索引过大则需存在磁盘上
  4. 是否支持区间查找

常用索引结构

  1. 散列表:增删改查时间复杂度O(1),适用于构建键值数据库,如Redis、Memcache,在内存中构建
  2. 红黑树:增删改查复杂度O(logn),适用于构建内存索引,如磁盘块索引
  3. B+树:更适用构建在磁盘中的索引,因为相比红黑树高度低,IO次数更少,如MySQL、Oracle
  4. 跳表:可以很好平衡索引对内存的消耗及其查询效率,如Redis中的有序集合
  5. 布隆过滤器、位图:用于加速索引查询效率

Redis背后数据结构

​ Redis常见结构包括字符串、 列表、字典、集合、有序集合

列表

​ 列表支持存储一组数据,当列表中单个数据小于 64 字节且列表数据个数少于 512 个时,采用压缩列表实现,否则采用双向循环链表

​ 压缩列表(类似于网络协议中的报文),特点是节省内存、支持多种类型数据,而且数据连续存储,读取效率高

字典

​ 用来存储一组数据对,每对包含键、值两部分 ,当键、值均小于 64 字节且字典中键值对少于 512 个时,采用压缩列表实现,否则采用散列表

​ 散列表采用MurmurHash2作为哈希函数,采用链表法避免hash冲突,支持动态扩容和缩容(当装载因子大于1扩大为原来2倍;当装载因子小于0.1就缩小为字典中数据个数的2倍)

集合

​ 用于存储一组不重复数据,当数据都为整数且个数不超过512,采用有序数组实现,否则采用散列表

有序集合

​ 所有数据都小于64字节且个数小于128个,采用压缩列表实现,否则采用跳表

搜索引擎

​ 搜索引擎大致可以分为四个部分:搜集分析索引查询,搜集就是利用爬虫爬取网页, 分析就是通过网页抽取分词来构建临时索引,索引通过临时索引来构建倒排索引, 查询负责响应用户的请求,根据倒排索引获取相关网页并返回给用户

搜集

​ 利用广度优先搜素(BFS), 先将一些网页放入队列,每次取出一个网页进行爬取,若其中包含另一个页面链接就解析出来添加到队列中(可以把页面看做一串字符,利用字符串匹配算法获取里面的网页链接)

​ 把队列持久化到文件,优点是断电后网页链接不会丢失,还支持断点续爬

​ 使用布隆过滤器避免重复爬取,避免宕机可以定期将布隆过滤器持久化到文件

​ 对每个网页分唯一ID编号,然后将网页链接和编号间对应关系单独持久化到一个文件

​ 把爬到的所有原始网页存储到文件中(按一定格式存放网页编号、网页大小、网页内容),文件大小超过1G自动创建新文件存储

分析

抽取网页文本信息:

  1. 去掉js、css格式及下拉框内容(利用AC自动机一次性查找并删除<style>、<script>、<option>三个标签及里面的内容
  2. 去除所有html标签

分词并创建临时索引:

  1. 对于英文网页:通过空格、标点符号将单词分隔开
  2. 对于中文网页:基于词库建立字典树,然后采用最长匹配规则匹配来分割词语

​ 最后将得到的单词编号和网页编号对应关系写入文件作为临时索引,单词编号和对应单词存放到散列表中(便于查找是否已有)

索引

​ 将临时索引构建成倒排索引,用于记录每个单词及包含它的网页列表

​ 由于临时索引很大无法一次性加载到内存,所以采用基于磁盘的多路归并排序,最后汇总成倒排索引

​ 最后还需持久化单词编号在倒排索引中的偏移,使得我们可以快速从倒排索引中找到单词及对应网页列表

查询

​ 我们把之前记录网页链接和网页编号间对应关系单词和单词编号间对应关系单词编号在倒排索引中偏移的三个文件加载到内存并组织成散列表(占用内存少,便于快速查找)

用户查询流程:

  1. 对用户输入内容进行分词处理,得到k个单词
  2. 根据得到的k个单词查询对应k个单词编号
  3. 根据单词编号查询对应单词编号在倒排索引中的偏移
  4. 在倒排索引中查询得到k个单词编号对应的网页列表(IO操作)
  5. 将k个网页列表按照出现次数进行合并排序(次数越多表明关联性越强)
  6. 最后拿网页列表中的网页编号去查询对应网页(IO操作)

接口鉴权

​ 在分布式中,对于RPC、Http接口,常需要鉴权来判定用户是否有接口访问权限。 比如http接口,当应用访问时系统会根据请求URL在规则中匹配,若成功就说明允许访问,否则拒绝服务

精确匹配

​ 只有当请求 URL 跟规则中某条精确匹配时,请求才会处理

​ 我们可以先把规则初始化排序,每次匹配进行二分查找

前缀匹配

​ 只要某条规则可以匹配请求 URL 的前缀,请求就会处理

​ 我们可以对规则构建字典树,子节点按顺序排列,对子节点的向下查找可以通过二分

限流

固定时间窗口限流

​ 设置一个计数器每隔1秒清零,每当来一个请求计数器++,若计数器超过阈值K,则拒绝后续请求

​ 缺点:请求集中于上个1秒的最后和下个1秒的开始,导致爆掉

滑动时间窗口限流

​ 可以实现在任意1秒请求数都不超过阈值k

​ 维护一个K大小的循环队列,设最早请求下标为p,最晚请求下标为q。若(q+1)%K!=p说明队列未满,直接将新请求加入队列,然后q = (q+1)%K;

​ 若(q+1)%K==p则代表队列已满,此时查看p坐标下的请求时间是否超过1秒,若超过则清理,然后p=(p+1)%K,q = (q+1)%K;若未超过则拒绝新请求

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值