如何基于ProductId与重量范围动态匹配第三方API产品目录?
我们网站对接了第三方运费API,网站的productId对应对方目录里的externalProductId,但对方会按productId和重量对商品分类,所以我们单个商品(比如Bag)在对方目录里会有多个条目。网站面向国际用户,支持lbs和kgs两种重量单位。
我们需要把我方productId和对方externalProductId匹配,再从对方目录中筛选出符合商品重量范围的条目,用来调用定价API获取运费预估,而且每个用户选择的商品都要执行这个匹配操作。
目前对方所有商品最小重量都是0,如果硬编码重量区间(比如50lbs<重量<70lbs)来查找,后续对方调整定价或重量范围时就会失效,所以需要实现基于productId、externalProductId和重量范围的动态匹配,求这个多条件目录搜索的最优高效方案。
我方网站商品示例
{ "productId" : "BAG", "weight": 60, "unit":"lbs" }
对方匹配条目示例
对方目录中externalProductId为'BAG'的商品有两个,符合重量范围的条目如下:
{ "productId": "BG2", "externalProductId": "BAG", "productName": "Bag", "weight": { "minimum": [ { "minWeight": 0, "unit": "lbs" }, { "minWeight": 0, "unit": "kgs" } ], "maximum": [ { "maxWeight": 70, "unit": "lbs" }, { "maxWeight": 32, "unit": "kgs" } ] } }
第三方完整产品目录
[ { "productId": "BG1", "externalProductId": "BAG", "productName": "Bag", "weight": { "minimum": [ { "minWeight": 0, "unit": "lbs" }, { "minWeight": 0, "unit": "kgs" } ], "maximum": [ { "maxWeight": 50, "unit": "lbs" }, { "maxWeight": 23, "unit": "kgs" } ] } }, { "productId": "BG2", "externalProductId": "BAG", "productName": "Bag", "weight": { "minimum": [ { "minWeight": 0, "unit": "lbs" }, { "minWeight": 0, "unit": "kgs" } ], "maximum": [ { "maxWeight": 70, "unit": "lbs" }, { "maxWeight": 32, "unit": "kgs" } ] } }, { "productId": "GF1", "externalProductId": "GLF", "productName": "Golf Bag", "weight": { "minimum": [ { "minWeight": 0, "unit": "lbs" }, { "minWeight": 0, "unit": "kgs" } ], "maximum": [ { "maxWeight": 50, "unit": "lbs" }, { "maxWeight": 23, "unit": "kgs" } ] } }, { "productId": "GF2", "externalProductId": "GLF", "productName": "Golf Bag", "weight": { "minimum": [ { "minWeight": 0, "unit": "lbs" }, { "minWeight": 0, "unit": "kgs" } ], "maximum": [ { "maxWeight": 70, "unit": "lbs" }, { "maxWeight": 32, "unit": "kgs" } ] } }, { "productId": "MI1", "externalProductId": "MUS", "productName": "Music Instrument", "weight": { "minimum": [ { "minWeight": 0, "unit": "lbs" }, { "minWeight": 0, "unit": "kgs" } ], "maximum": [ { "maxWeight": 50, "unit": "lbs" }, { "maxWeight": 23, "unit": "kgs" } ] } }, { "productId": "MI2", "externalProductId": "MUS", "productName": "Music Instrument", "weight": { "minimum": [ { "minWeight": 0, "unit": "lbs" }, { "minWeight": 0, "unit": "kgs" } ], "maximum": [ { "maxWeight": 70, "unit": "lbs" }, { "maxWeight": 32, "unit": "kgs" } ] } } ]
1. 预构建索引提升查询效率
先把第三方目录转换成以externalProductId为键的分组结构,每个键对应同类型的所有商品条目,这样可以快速过滤出和我方productId匹配的候选条目,避免每次查询都遍历整个目录。
示例代码(JavaScript):
// 预构建索引 const externalProductIndex = {}; thirdPartyCatalog.forEach(item => { const key = item.externalProductId; if (!externalProductIndex[key]) { externalProductIndex[key] = []; } externalProductIndex[key].push(item); });
2. 统一重量单位处理逻辑
优先用我方商品的单位去匹配对方对应单位的重量范围,如果对方没有该单位的记录,再做单位转换(转换系数:1lbs≈0.453592kgs)。因为对方所有商品最小重量都是0,只需判断我方重量是否小于等于对应条目最大重量即可。
示例代码(JavaScript):
function findMatchingThirdPartyItem(ourProduct, externalProductIndex) { const candidates = externalProductIndex[ourProduct.productId] || []; if (candidates.length === 0) return null; const ourWeight = ourProduct.weight; const ourUnit = ourProduct.unit; // 优先匹配同单位的条目 const match = candidates.find(item => { const maxWeightEntry = item.weight.maximum.find(w => w.unit === ourUnit); return maxWeightEntry && ourWeight <= maxWeightEntry.maxWeight; }); if (match) return match; // 同单位无匹配时做单位转换 let convertedWeight; if (ourUnit === 'lbs') { convertedWeight = ourWeight * 0.453592; return candidates.find(item => { const kgMax = item.weight.maximum.find(w => w.unit === 'kgs'); return kgMax && convertedWeight <= kgMax.maxWeight; }); } else if (ourUnit === 'kgs') { convertedWeight = ourWeight / 0.453592; return candidates.find(item => { const lbsMax = item.weight.maximum.find(w => w.unit === 'lbs'); return lbsMax && convertedWeight <= lbsMax.maxWeight; }); } return null; }
3. 动态适配对方重量范围变化
每次获取到最新的第三方目录后,重新生成索引即可自动适配对方的重量范围或定价调整,完全不需要修改硬编码的区间值。
4. 性能优化建议
- 仅在第三方目录更新时重新构建索引,无需每次查询都重建
- 若目录数据量极大,可将索引缓存到内存或Redis中,进一步提升查询速度
- 把单位转换逻辑封装成独立工具函数,方便后续维护和扩展其他单位(比如oz)
内容的提问来源于stack exchange,提问作者Shokwave

