关于推荐算法:推荐一款优秀电商开源项目

简介本文给大家举荐博主本人开源的电商我的项目newbee-mall-pro。在newbee-mall我的项目的根底上搭建而来, 应用 mybatis-plus 作为 orm 层框架,并增加了一系列高级性能以及代码优化,个性如下: 商城首页 【为你举荐】 栏目增加协同过滤算法。依照 UserCF 基于用户的协同过滤、ItemCF 基于物品的协同过滤,实现了两种不同的举荐逻辑。RedisSearch:反对中文分词搜寻,反对商品名称、简介、标签作为搜寻项,以及新品、价格排序。 RediSearch 是一个源码可用的 Redis 模块,能够对 Redis 进行查问、二级索引和全文搜寻。这些性能反对在文本查问之上进行多字段查问、聚合、准确短语匹配、数字过滤、天文过滤和矢量相似性语义搜寻。秒杀专区:反对性能齐备,生产可用的高级秒杀性能。优惠卷专区:反对优惠卷后盾配置、用户注册赠卷、下单页面优惠卷应用等性能。商城首页反对应用滑块验证码登录。领取时集成了支付宝沙箱领取,能够在开发环境体验支付宝领取成果。集成 Pace 页面,增加网页进度条,页面跳转丑化。增加 Spring 事件监听机制,异步解耦下单流程。集成spring-session-redis,反对分布式部署。集成mybatis-xmlreload,反对xml文件热加载。newbee-mall-pro 我的项目地址: 源码地址:https://github.com/wayn111/newbee-mall-pro在线地址:http://121.4.124.33/newbeemall一、开发部署# 1. 克隆我的项目git clone git@github.com:wayn111/newbee-mall-pro.git# 2. 导入我的项目依赖将newbee-mall-pro目录用idea关上,导入maven依赖# 3. 装置Mysql8.0+、Redis3.0+(RediSearch2.0+)、Jdk8+、Maven3.5+docker装置RediSearchdocker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:lates# 4. 导入sql文件在我的项目根目录下sql文件夹下,找到`newbee_mall_db_蕴含秒杀and优惠卷.sql`文件,新建mysql数据库newbee_mall_db,导入其中# 5. 解压我的项目图片将我的项目根目录下upload.zip文件加压缩到D盘upload文件夹中,eg:D:\\upload# 6. 批改Mysql、Redis连贯配置批改`application-dev.yml`文件中数据连贯配置相干信息# 7. 启动我的项目找到NewBeeMallApplication文件,右键`run AdminApplication`,启动我的项目# 8. 拜访关上浏览器输出:http://localhost:84/newbeemall二、更新日志2023年4月08日更新日志newbee-mall-pro V2.4.2公布 更新内容: 商城首页为你举荐栏目增加协同过滤算法。依照UserCF基于用户的协同过滤、ItemCF基于物品的协同过滤。 实现了两种不同的举荐逻辑。 UserCF:基于用户的协同过滤。当一个用户A须要个性化举荐的时候,咱们能够先找到和他有类似趣味的其余用户,而后把那些用户喜爱的,而用户A没有据说过的物品举荐给A。具体代码在 ltd.newbee.mall.recommend.core.UserCF 中。itemCF:基于物品的协同过滤。事后依据所以用户的历史偏好数据计算物品之间的类似度,而后把与用户喜爱的物品相相似的物品举荐给用户。具体代码在 ltd.newbee.mall.recommend.core.ItemCF 中。2023年3月27日更新日志newbee-mall-pro V2.4.1公布 更新内容: 集成mybatis-xmlreload,反对xml文件热加载代码优化,通过阿里巴巴代码标准检测降级局部依赖至最新2023年1月2日更新日志newbee-mall-pro V2.4.0公布 更新内容: Springboot版本升级至3.0.2Mybatis plus降级至3.5.3.1反对Springboot3.02022年11月17日更新日志newbee-mall-pro V2.3.0公布 更新内容: Springboot版本升级至2.7.5,jdk降级至17应用switch表达式语法扩大,优化switch语句应用instanceof类型匹配语法简化,间接给对象赋值应用文本块优化现有lua脚本显示增加@Serial注解示意序列化字段和办法代码优化,删除无用导入降级我的项目依赖bug修复: ...

April 8, 2023 · 1 min · jiezi

关于推荐算法:高效压缩位图在推荐系统中的应用

作者:vivo互联网技术-Ke Jiachen一、背景用户在浏览游戏核心/利用商店的某些模块内容时,会进行一系列滑屏操作并屡次申请游戏举荐业务来进行游戏举荐展现,这段时间咱们称之为一个用户session。 一个session内用户个别会进行十几次滑屏操作,每次滑屏操作都会申请举荐业务,所以在这个session内游戏举荐须要对举荐过的游戏进行去重,避免出现反复举荐同一款游戏影响用户体验。 精简后的业务流程如下所示:用户进行滑屏操作时会触发一次举荐申请,此时客户端会将上一页的黑名单游戏通过游戏核心服务端透传给举荐零碎,举荐零碎将一个session内每次申请的黑名单信息都累加存储到Redis中作为一个总的过滤汇合,在召回打分时就会过滤掉这些黑名单游戏。 以理论业务场景为例,用户浏览某模块的session时长个别不会超过10分钟,模块每页显示的游戏为20个左右,假如每个用户session内会进行15次的滑屏操作,那么一个session就须要存储300 个黑名单游戏的appId(整数型Id)。因而该业务场景就不适宜长久化存储,业务问题就能够归结为如何应用一个适合的数据结构来缓存一系列整数汇合以达到节俭内存开销的目标。 二、技术选型剖析接下来咱们随机选取300个游戏的appId([2945340, ....... , 2793501,3056389])作为汇合来别离试验剖析intset,bloom filter,RoaringBitMap对存储成果的影响。 2.1 intset试验结果表明用 intset保留300个游戏汇合,失去占用的空间大小为1.23KB。这是因为对于300个整数型appId游戏,每个appId用4Byte的int32就能示意。依据intset的数据结构,其开销仅为encoding + length + 400 个int所占的空间。 typedef struct intset{ unit32_t encoding; // 编码类型 unit32_t length; // 元素个数 int8_t contents[]; // 元素存储} intset;2.2 bloom filter布隆过滤器底层应用的是bitmap,bitmap自身就是一个数组能够存储整形数字,arr[N] = 1 示意数组里存储了N这个数字。 bloom filter会先用hash函数对数据进行计算,映射到bitmap相应的地位,为缩小碰撞(不同的数据可能会有雷同的hash值),会应用多个hash算子对同一份数据进行屡次映射。在业务中咱们假如线上有一万个游戏,同时业务场景不容许呈现误判,那么误差就必须管制在10^-5,通过bloom filter的计算工具https://hur.st/bloomfilter/?n...得出,须要17个hash算子,且bitmap空间要达到29KB能力满足业务需要,显然这样微小的开销并不是咱们想要的后果。 2.3 RoaringBitMapRoaringBitMap和bloom filter实质上都是应用bitmap进行存储。但bloom filter 应用的是多个hash函数对存储数据进行映射存储,如果两个游戏appId通过hash映射后得出的数据统一,则断定两者反复,这两头有肯定的误判率,所以为满足在该业务场景其空间开销会十分的大。而RoaringBitMap是间接将元数据进行存储压缩,其准确率是100%的。 试验结果表明:RoaringBitMap对300个游戏汇合的开销仅为0.5KB,比间接用intset(1.23KB)还小,是该业务场景下的首选。所以下文咱们来着重剖析下RoaringBitMap为什么为如此高效。 2.3.1 数据结构每个RoaringBitMap中都蕴含一个RoaringArray,存储了全副的数据,其构造如下: short[] keys;Container[] values;int sizer;它的思路是将32位无符号整数依照高16位分桶(container),并做为key存储到short[] keys中,最多能存储2^16 = 65536 个桶(container)。存储数据时依照数据的高16位找到container,再将低16位放入container中,也就是Container[] values。size则示意了以后keys和values中无效数据的数量。 为了不便了解,下图展现了三个container: 图片援用自:https://arxiv.org 高16位为0000H的container,存储有前1000个62的倍数。高16位为0001H的container,存储有[2^16, 2^16+100)区间内的100个数。高16位为0002H的container,存储有[2×2^16, 3×2^16)区间内的所有偶数,共215个。当然该数据结构的细节不是咱们关注的重点,有趣味的同学能够去查阅相干材料学习。当初咱们来剖析一下在举荐业务中RoaringBitMap是如何帮忙咱们节俭开销的。RoaringBitMap中的container分为ArrayContainer,BitmapContainer 和 RunContainer 但其压缩形式次要分为两种,权且就称为可变长度压缩和固定长度压缩, 这两种形式在不同的场景下有不同的利用。 ...

April 19, 2022 · 2 min · jiezi

关于推荐算法:推荐系统入门笔记九-基于内容的推荐算法

一. 简介基于内容的举荐办法是以物品的内容形容信息为根据来做出的举荐,实质上是基于对物品和用户本身的特色或属性的间接剖析和计算。 例如,假如已知电影A是一部悲剧,而凑巧咱们得悉某个用户喜爱看喜剧电影,那么咱们基于这样的已知信息,就能够将电影A举荐给该用户。 二. 基于内容举荐的实现步骤画像构建(画像就是刻画物品或用户的特色。实质上就是给用户或物品贴标签) 物品画像 : 给物品贴标签用户画像 : 给用户贴标签构建画像的办法: 依据PGC/UGC 内容构建物品画像,(PGC:物品自带的标签,UGC:用户提供的标签)依据用户记录构建用户画像依据用户画像从物品中寻找最匹配的TOP-N物品进行举荐三. 基于内容的电影举荐: 物品画像1. 构建步骤利用tags.csv中每部电影的标签作为电影的候选关键词利用Tf-IDF 或者word2vec 计算每个词的权重选取权重top-n的标签作为电影画像2. TF-IDF 算法1. 算法原理TF-IDF自然语言解决畛域中计算文档中词或短语的权值的办法,是词频(Term Frequency,TF)和逆转文档频率(Inverse Document Frequency,IDF)的乘积。TF指的是某一个给定的词语在该文件中呈现的次数。这个数字通常会被正规化,以避免它偏差长的文件(同一个词语在长文件里可能会比短文件有更高的词频,而不论该词语重要与否)。IDF是一个词语广泛重要性的度量,某一特定词语的IDF,能够由总文件数目除以蕴含该词语之文件的数目,再将失去的商取对数失去。 2. 算法举例对于计算影评的TF-IDF,以电影“加勒比海盗:黑珍珠号的咒骂”为例,假如它总共有1000篇影评,其中一篇影评的总词语数为200,其中呈现最频繁的词语为“海盗”、“船长”、“自在”,别离是20、15、10次,并且这3个词在所有影评中被提及的次数别离为1000、500、100,就这3个词语作为关键词的程序计算如下。 将影评中呈现的停用词过滤掉,计算其余词语的词频。以呈现最多的三个词为例进行计算如下: “海盗”呈现的词频为20/200=0.1“船长”呈现的词频为15/200=0.075“自在”呈现的词频为10/200=0.05;计算词语的逆文档频率如下: “海盗”的IDF为:log(1000/1000)=0“船长”的IDF为:log(1000/500)=0.3“自在”的IDF为:log(1000/100)=1由1和2计算的后果求出词语的TF-IDF后果,“海盗”为0,“船长”为0.0225,“自在”为0.05。3. 算法实现import pandas as pdimport numpy as npfrom gensim.corpora import Dictionaryfrom gensim.models import TfidfModeldef get_movie_dataset(tag_path, movie_path): # 读取电影标签文件,去第2,第3列 _tags = pd.read_csv(tag_path, usecols=[1, 2]).dropna() # 对标签数据进行汇合 tags = _tags.groupby('movieId').agg(list) # 读取电影文件,将tags标签 和电影数据组合 movies = pd.read_csv(movie_path, index_col='movieId') # 须要应用到电影的分类,所以对电影分类进行解决 movies['genres'] = movies['genres'].apply(lambda x: x.split('|')) # 将标签数据和电影数据组合,取tags 和 movies 都存在的movieId movie_index = set(movies.index) & set(tags.index) # 取标签中的值 new_tags = tags.loc[movie_index] # 组合数据 ret = movies.join(new_tags) # 将数据转换成pd movie_dataset = pd.DataFrame( map(lambda x: (x[0], x[1], x[2], x[2] + x[3]) if x[3] is not np.nan else (x[0], x[1], x[2], []), ret.itertuples()), columns=["movieId", "title", "genres", "tags"]) # 设置movie_dataset 的index为 movieId movie_dataset.set_index('movieId', inplace=True) return movie_datasetdef create_movie_profile(movie_dataset): # 1. 对数据集进行迭代 # 2. 对每个电影的现有标签进行tf-idf计算权重 # 3. 对标签进行权重排序, # 4. 取top-n 个tag 作为电影的标签 # 取出所有电影的标签 dataset = movie_dataset['tags'].values # 应用gensim计算tf-idf ,将所有词放入一个词典 dct = Dictionary(dataset) # 依据每条数据,计算对应的词索引和词频 corpus = [dct.doc2bow(line) for line in dataset] model = TfidfModel(corpus) # 给每个电影贴标签 _movie_profile = [] for i, data in enumerate(movie_dataset.itertuples()): mid = data[0] title = data[1] genres = data[2] # 依据每条数据返回标签,权重向量 vector = model[corpus[i]] # 对标签进行权重排序并去前30个作为电影标签 movie_tags = sorted(vector, key=lambda x: x[1], reverse=True)[:30] # 前30个电影-权重 topN_tags_weights = dict(map(lambda x: (dct[x[0]], x[1]), movie_tags)) # 将类别词退出tags 设置权重为1 for g in genres: topN_tags_weights[g] = 1.0 topN_tags = [i[0] for i in topN_tags_weights.items()] _movie_profile.append((mid, title, topN_tags, topN_tags_weights)) movie_profile = pd.DataFrame(_movie_profile, columns=["movieId", "title", "profile", "weights"]) movie_profile.set_index("movieId", inplace=True) return movie_profiledef create_inverted_table(movie_profile): # 对电影画像做tag-movies倒排表: # 每个关键词对应的电影,以及该词的权重 inverted_table = {} # 对所有电影的标签权重循环 for mid, weights in movie_profile['weights'].iteritems(): # 取每个电影标签 for tag, weight in weights.items(): # 获取inverted_table 中 tag的值如果不存在,返回[] _ = inverted_table.get(tag, []) # 将 电影和权重增加到标签的列表中 _.append((mid, weight)) # 增加标签对应的电影和权重 inverted_table.setdefault(tag, _) return inverted_tableif __name__ == '__main__': tag_path = 'E:/ml/recommand/ml-latest-small/all-tags.csv' movie_path = 'E:/ml/recommand/ml-latest-small/movies.csv' watch_path = 'E:/ml/recommand/ml-latest-small/ratings.csv' # 1. 获取数据,解决数据集 movie_dataset = get_movie_dataset(tag_path, movie_path) # 2. 对电影构建画像 movie_profile = create_movie_profile(movie_dataset) inverted_table = create_inverted_table(movie_profile) print(inverted_table)三. 基于内容的电影举荐: 用户画像用户画像构建步骤: ...

November 16, 2021 · 5 min · jiezi