前情提要
剩下问题
同步数据库数据并初始化ivf依然要8,9秒
问题排查
通过断点加时间打印,发生其实初始化ivf的时间很快,慢的是数据在网络间的传输,并在python端的数据解析,无语
本地调本地,都要十秒,这不合理,改!
解决方案
因为这里必须要查一次全量数据,然后存入redis并将特征值传给python端进行初始化,所以最快的方案就是舍弃数据传输,直接在python端进行查询并初始化,即在python端查全量数据+设置redis+初始化ivf,虽然不想承认,但确实把python端做重在架构和设计层面可能都是最优解,改吧
- python端增加mysql查询
import mysql.connector
from mysql.connector import pooling
# 配置数据库连接
db_config = {
'host': 'localhost', # 替换为你的 MySQL 主机地址
'user': 'root', # 替换为你的 MySQL 用户名
'password': 'cmkkl407', # 替换为你的 MySQL 密码
'database': 'cnn' # 替换为你的数据库名称
}
pool = pooling.MySQLConnectionPool(pool_name="mypool", pool_size=5, **db_config)
def get_feature_by_store_code(store_code):
query = "SELECT id, features FROM feature WHERE storeCode REGEXP %s"
results = query_data(query, params=(f"(^|,){store_code}(,|$)",))
return results
def query_data(query, params):
connection = pool.get_connection()
cursor = connection.cursor(dictionary=True)
cursor.execute(query, params)
results = cursor.fetchall()
cursor.close()
connection.close() # 连接会被返回到池中
return results
- 修改sync方法
def sync(self, store_code):
if store_code + '-featureDatabase' in self.ivfObj:
del self.ivfObj[store_code + '-featureDatabase']
data = get_feature_by_store_code(store_code)
def parse_features(item):
return orjson.loads(item['features'])
with ThreadPoolExecutor() as executor:
features_list = list(executor.map(parse_features, data))
# 提取所有特征并转换为 NumPy 数组
features = np.array(features_list, dtype=np.float32)
self.ivfObj[store_code + '-featureDatabase'] = IVFPQ(features)
ids = [item['id'] for item in data]
return ids
由于python端查出来的json默认会给字符串格式,所以还需要转成json
一个优化小点:
并行处理:使用多线程或多进程并行处理数据。可以使用 concurrent.futures 库中的 ThreadPoolExecutor 或 ProcessPoolExecutor 来加快解析速度。
def parse_features(item):
return orjson.loads(item['features'])
with ThreadPoolExecutor() as executor:
features_list = list(executor.map(parse_features, data))
同时利用查出了所有id将ids进行返回给nestjs端直接进行redis存储
4. nestjs端修改
/**
* 同步redis
* @param storeCode
*/
async syncRedis(storeCode: string) {
const url = 'http://localhost:5000/sync'; // Python 服务的 URL
const s = Date.now();
const response = await firstValueFrom(this.httpService.post(url, { storeCode }));
const { ids } = response.data;
await this.redisService.set(`${storeCode}-featureDatabase`, JSON.stringify(ids));
const e = Date.now();
console.log(`同步redis耗时:${e - s}ms`);
}
- 优化后速度减少了一倍
下一步
- 新建store_feature表,关联storeCode和featureId表,对数据库进行规范化,创建一个新的表来映射storeCode与feature的关系,从而可以使用简单的WHERE条件来充分利用索引
- 实现对特征向量ivf的增删改查