果蔬识别系统性能优化之路(三)
目录
- 前情提要
- 遗留问题
- 解决方案
- 优化查询速度
- 优化ivf初始化的速度
- 下一步
前情提要
果蔬识别系统性能优化之路(二)
遗留问题
- 优化同步速度,目前大约30秒,不是一个生产速度
这次来解决遗留问题
通过console,发现两个地方特别耗时,一个是查询数据,另一个是初始化ivf
/*** 同步redis* @param storeCode*/async syncRedis(storeCode: string) {let s = Date.now();const featureDatabase = await this.findAll(storeCode);let e = Date.now();console.log(`查询耗时1:${e - s}ms`);const ids = featureDatabase.map(({ id }) => id);await this.redisService.set(`${storeCode}-featureDatabase`, JSON.stringify(ids));s = Date.now();const url = 'http://localhost:5000/sync'; // Python 服务的 URLawait firstValueFrom(this.httpService.post(url, { data: featureDatabase, storeCode }));e = Date.now();console.log(`查询耗时3:${e - s}ms`);}
解决方案
优化查询速度
之前使用的是FIND_IN_SET方法对类似1,2,3这样的数据进行包含条件的查询,速度太慢了,优化后:
/*** 查询所有* @param storeCode*/async findAll(storeCode: string) {return await this.featureRepository.createQueryBuilder('feature').select(['feature.id', 'feature.features']).where('feature.storeCode REGEXP :storeCode', { storeCode: `(^|,)${storeCode}(,|$)` }).getMany();}
效果提升了一倍:
优化ivf初始化的速度
当前的初始化方法
def __init__(self, features, nlist=100, m=16, n_bits=8):d = features.shape[1]# 创建量化器quantizer = faiss.IndexFlatL2(d) # 使用L2距离进行量化self.index = faiss.IndexIVFPQ(quantizer, d, nlist, m, n_bits)# 训练索引self.index.train(features)self.index.add(features) # 将特征向量添加到索引中
优化方法:
- 增加并行化处理
# 设置线程数,例如使用所有可用的CPU核心
faiss.omp_set_num_threads(num_threads) # num_threads 是你希望使用的线程数量
- 减少索引的复杂度
减少nlist和m的值,但这样会损失精度,先不采用 - 使用增量添加数据
分批处理可以分散压力,同时利用数据流式处理的优势。
batch_size = 1000 # 每次处理1000个特征
for i in range(0, len(features), batch_size):self.index.add(features[i:i+batch_size])
- 更换其他索引类型
self.index = faiss.IndexIVFFlat(quantizer, d, nlist)
下一步
- 新建store_feature表,关联storeCode和featureId表,对数据库进行规范化,创建一个新的表来映射storeCode与feature的关系,从而可以使用简单的WHERE条件来充分利用索引
- 实现对特征向量ivf的增删改查