目录
- 前情提要
- 遗留问题
 
- 解决方案
- 优化查询速度
- 优化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 服务的 URL
    await 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的增删改查



















