个人编程网站

进销存(JXC)软件开发技术积累与分享

进销存系统智能推荐引擎设计与实现

引言

在进销存系统中,智能推荐功能可以帮助企业发现潜在客户需求、优化库存结构、提高销售转化率。通过分析历史交易数据、商品关联关系和客户行为模式,我们可以构建一个精准的推荐引擎。

推荐引擎架构

推荐系统的整体架构设计:

层次 组件 职责
数据采集层 埋点SDK、ETL任务 用户行为收集、数据清洗
特征工程层 特征工厂、用户画像 特征提取、向量化
算法引擎层 协同过滤、关联规则、深度学习 推荐算法实现
服务层 API网关、缓存服务 推荐结果服务

用户行为数据采集

构建完整的用户行为追踪体系:

// 用户行为采集器
class BehaviorCollector {
  constructor() {
    this.buffer = [];
    this.flushInterval = 5000;
  }

  // 记录用户行为
  async record(action, details) {
    const event = {
      userId: this.getCurrentUser(),
      sessionId: this.getSessionId(),
      action: action,
      target: details.target,
      category: details.category,
      timestamp: Date.now(),
      properties: details.properties || {},
      context: {
        url: window.location.href,
        referrer: document.referrer,
        device: this.getDeviceInfo()
      }
    };

    // 加入缓冲区
    this.buffer.push(event);

    // 达到批量阈值则发送
    if (this.buffer.length >= 100) {
      await this.flush();
    }
  }

  // 批量发送行为数据
  async flush() {
    if (this.buffer.length === 0) return;

    const events = [...this.buffer];
    this.buffer = [];

    try {
      await this.sendToServer('/api/behavior/collect', events);
    } catch (error) {
      // 失败则放回缓冲区
      this.buffer = [...events, ...this.buffer];
    }
  }

  // 常用行为追踪
  onProductView(productId) {
    this.record('product_view', {
      target: productId,
      category: 'product'
    });
  }

  onSearch(query) {
    this.record('search', {
      target: query,
      category: 'search'
    });
  }

  onAddToCart(productId, quantity) {
    this.record('add_to_cart', {
      target: productId,
      category: 'cart',
      properties: { quantity }
    });
  }

  onPlaceOrder(orderId) {
    this.record('place_order', {
      target: orderId,
      category: 'order'
    });
  }
}

// 行为事件类型
const ActionTypes = {
  // 商品相关
  PRODUCT_VIEW: 'product_view',
  PRODUCT_FAVORITE: 'product_favorite',
  PRODUCT_COMPARE: 'product_compare',

  // 购物车相关
  ADD_TO_CART: 'add_to_cart',
  REMOVE_FROM_CART: 'remove_from_cart',
  UPDATE_CART: 'update_cart',

  // 订单相关
  PLACE_ORDER: 'place_order',
  ORDER_COMPLETE: 'order_complete',
  ORDER_CANCEL: 'order_cancel',

  // 搜索相关
  SEARCH: 'search',
  SEARCH_RESULT_CLICK: 'search_result_click'
};

商品协同过滤算法

基于用户行为的协同过滤实现:

// 协同过滤推荐引擎
class CollaborativeFiltering {
  constructor(config) {
    this.k = config.neighbors || 20;  // 近邻数量
    this.minSimilarity = config.minSimilarity || 0.1;
    this.userItemMatrix = new Map();
    this.itemSimilarityMatrix = new Map();
  }

  // 构建用户-商品矩阵
  buildUserItemMatrix(behaviorData) {
    for (const event of behaviorData) {
      const { userId, target, action } = event;

      if (!this.userItemMatrix.has(userId)) {
        this.userItemMatrix.set(userId, new Map());
      }

      const userItems = this.userItemMatrix.get(userId);

      // 根据行为类型计算权重
      const weight = this.getActionWeight(action);
      const currentScore = userItems.get(target) || 0;
      userItems.set(target, currentScore + weight);
    }
  }

  // 行为权重计算
  getActionWeight(action) {
    const weights = {
      'product_view': 1,
      'product_favorite': 3,
      'add_to_cart': 5,
      'place_order': 10,
      'order_complete': 10
    };
    return weights[action] || 1;
  }

  // 计算商品相似度矩阵
  async calculateItemSimilarity() {
    const items = this.getAllItems();

    for (let i = 0; i < items.length; i++) {
      for (let j = i + 1; j < items.length; j++) {
        const similarity = this.cosineSimilarity(items[i], items[j]);

        if (Math.abs(similarity) > this.minSimilarity) {
          const key = this.getItemPairKey(items[i], items[j]);
          this.itemSimilarityMatrix.set(key, similarity);
        }
      }
    }
  }

  // 余弦相似度计算
  cosineSimilarity(itemA, itemB) {
    // 获取对商品有行为的用户
    const usersA = this.getUsersForItem(itemA);
    const usersB = this.getUsersForItem(itemB);
    const commonUsers = [...usersA].filter(u => usersB.has(u));

    if (commonUsers.length === 0) return 0;

    // 计算向量
    const vectorA = commonUsers.map(u => this.getUserRating(u, itemA));
    const vectorB = commonUsers.map(u => this.getUserRating(u, itemB));

    // 余弦相似度
    const dotProduct = vectorA.reduce((sum, v, i) => sum + v * vectorB[i], 0);
    const magnitudeA = Math.sqrt(vectorA.reduce((sum, v) => sum + v * v, 0));
    const magnitudeB = Math.sqrt(vectorB.reduce((sum, v) => sum + v * v, 0));

    if (magnitudeA === 0 || magnitudeB === 0) return 0;

    return dotProduct / (magnitudeA * magnitudeB);
  }

  // 为用户生成推荐
  recommendForUser(userId, limit = 10) {
    const userItems = this.userItemMatrix.get(userId);
    if (!userItems) return [];

    // 用户已交互的商品
    const interactedItems = [...userItems.keys()];

    // 计算候选商品得分
    const scores = [];

    for (const [itemA, similarity] of this.itemSimilarityMatrix) {
      const [item1, item2] = this.parseItemPairKey(itemA);

      // 如果用户交互过 item1,推荐 item2
      if (interactedItems.includes(item1)) {
        if (!interactedItems.includes(item2)) {
          scores.push({
            item: item2,
            score: similarity * (userItems.get(item1) || 0)
          });
        }
      }

      // 如果用户交互过 item2,推荐 item1
      if (interactedItems.includes(item2)) {
        if (!interactedItems.includes(item1)) {
          scores.push({
            item: item1,
            score: similarity * (userItems.get(item2) || 0)
          });
        }
      }
    }

    // 按得分排序并返回TopN
    scores.sort((a, b) => b.score - a.score);
    return scores.slice(0, limit);
  }

  // 基于商品的推荐
  similarProducts(productId, limit = 10) {
    const scores = [];

    for (const [pairKey, similarity] of this.itemSimilarityMatrix) {
      const [item1, item2] = this.parseItemPairKey(pairKey);

      if (item1 === productId) {
        scores.push({ item: item2, score: similarity });
      } else if (item2 === productId) {
        scores.push({ item: item1, score: similarity });
      }
    }

    scores.sort((a, b) => b.score - a.score);
    return scores.slice(0, limit);
  }
}

关联规则挖掘

使用 Apriori 算法发现商品关联关系:

// 关联规则挖掘
class AssociationMiner {
  constructor(config) {
    this.minSupport = config.minSupport || 0.01;
    this.minConfidence = config.minConfidence || 0.3;
    this.maxItemSetSize = config.maxItemSetSize || 3;
  }

  // 从订单数据中挖掘关联规则
  mineAssociationRules(orders) {
    // 1. 构建事务数据库
    const transactions = orders.map(order => order.items.map(item => item.productId));

    // 2. 频繁项集挖掘
    const frequentItemsets = this.findFrequentItemsets(transactions);

    // 3. 生成关联规则
    const rules = [];
    for (const [itemset, support] of frequentItemsets) {
      if (itemset.length < 2) continue;

      // 生成所有可能的规则
      const combinations = this.generateCombinations(itemset);
      for (const [antecedent, consequent] of combinations) {
        const antecedentSupport = this.getSupport(frequentItemsets, antecedent);
        const confidence = support / antecedentSupport;

        if (confidence >= this.minConfidence) {
          rules.push({
            antecedent: [...antecedent],
            consequent: [...consequent],
            support: support,
            confidence: confidence,
            lift: confidence / this.getSupport(frequentItemsets, consequent)
          });
        }
      }
    }

    return rules.sort((a, b) => b.lift - a.lift);
  }

  // 频繁项集挖掘 (Apriori)
  findFrequentItemsets(transactions) {
    const frequentItemsets = new Map();

    // 1-项集
    let currentItemsets = this.getCandidate1Itemsets(transactions);
    currentItemsets = this.pruneBySupport(currentItemsets, transactions);

    for (const itemset of currentItemsets) {
      frequentItemsets.set(this.itemsetKey(itemset), this.calculateSupport(itemset, transactions));
    }

    // 迭代生成k-项集
    let k = 2;
    while (k <= this.maxItemSetSize && currentItemsets.length > 0) {
      // 生成候选项集
      const candidates = this.generateCandidates(currentItemsets, k);

      // 剪枝
      const pruned = this.pruneBySupport(candidates, transactions);

      // 保存频繁项集
      for (const itemset of pruned) {
        frequentItemsets.set(this.itemsetKey(itemset), this.calculateSupport(itemset, transactions));
      }

      currentItemsets = pruned;
      k++;
    }

    return frequentItemsets;
  }

  // 生成K-项集候选项
  generateCandidates(itemsets, k) {
    const candidates = [];

    for (let i = 0; i < itemsets.length; i++) {
      for (let j = i + 1; j < itemsets.length; j++) {
        // 合并两个(k-1)-项集
        const union = [...new Set([...itemsets[i], ...itemsets[j]])];

        if (union.length === k) {
          // 检查是否需要剪枝
          const subsets = this.getSubsets(union, k - 1);
          const isValid = subsets.every(subset =>
            itemsets.some(itemset =>
              this.itemsetKey(itemset) === this.itemsetKey(subset))
          );

          if (isValid) {
            candidates.push(union);
          }
        }
      }
    }

    return candidates;
  }

  // 购买推荐生成
  generatePurchaseRecommendations(cartItems, rules, limit = 5) {
    const recommendations = [];

    for (const rule of rules) {
      // 检查购物车是否包含规则前项
      const hasAntecedent = rule.antecedent.every(item => cartItems.includes(item));

      if (hasAntecedent) {
        // 推荐后项商品
        for (const item of rule.consequent) {
          if (!cartItems.includes(item)) {
            recommendations.push({
              productId: item,
              confidence: rule.confidence,
              lift: rule.lift
            });
          }
        }
      }
    }

    // 按置信度排序
    recommendations.sort((a, b) => b.confidence - a.confidence);
    return recommendations.slice(0, limit);
  }
}

实时推荐服务

构建高效的推荐服务接口:

// 推荐服务API
class RecommendationService {
  constructor() {
    this.cf = new CollaborativeFiltering({ neighbors: 20 });
    this.association = new AssociationMiner({ minSupport: 0.01 });
    this.cache = new LRUCache({ maxSize: 1000 });
  }

  // 初始化推荐模型
  async initialize() {
    // 加载行为数据
    const behaviors = await this.loadBehaviorData();
    this.cf.buildUserItemMatrix(behaviors);
    await this.cf.calculateItemSimilarity();

    // 挖掘关联规则
    const orders = await this.loadOrders();
    this.rules = this.association.mineAssociationRules(orders);
  }

  // 获取商品推荐
  async getProductRecommendations(userId, context, limit = 10) {
    // 检查缓存
    const cacheKey = `rec_${userId}_${context.scene}`;
    const cached = this.cache.get(cacheKey);
    if (cached) return cached;

    let recommendations = [];

    switch (context.scene) {
      case 'home':
        // 首页推荐:热门商品 + 个性化
        const popular = await this.getPopularProducts(limit);
        const personalized = this.cf.recommendForUser(userId, limit);
        recommendations = this.mergeRecommendations(popular, personalized, 0.3);
        break;

      case 'product_detail':
        // 商品详情页:相似商品 + 关联商品
        const similar = this.cf.similarProducts(context.productId, limit);
        const related = this.association.generatePurchaseRecommendations(
          [context.productId],
          this.rules,
          limit
        );
        recommendations = [...similar, ...related];
        break;

      case 'cart':
        // 购物车:关联推荐
        recommendations = this.association.generatePurchaseRecommendations(
          context.cartItems,
          this.rules,
          limit
        );
        break;

      case 'order_complete':
        // 订单完成页:交叉销售
        const orderProducts = context.orderItems;
        recommendations = this.association.generatePurchaseRecommendations(
          orderProducts,
          this.rules,
          limit
        );
        break;
    }

    // 去重并填充
    recommendations = this.deduplicate(recommendations, limit);

    // 缓存结果
    this.cache.set(cacheKey, recommendations, 300);  // 5分钟缓存

    return recommendations;
  }

  // 合并推荐结果
  mergeRecommendations(listA, listB, weightA = 0.5) {
    const scoreMap = new Map();

    // 评分A列表
    for (const item of listA) {
      scoreMap.set(item.productId || item.item, {
        productId: item.productId || item.item,
        score: (item.score || item.confidence || 0) * weightA,
        source: 'A'
      });
    }

    // 评分B列表
    for (const item of listB) {
      const existing = scoreMap.get(item.productId || item.item);
      if (existing) {
        existing.score += (item.score || item.confidence || 0) * (1 - weightA);
      } else {
        scoreMap.set(item.productId || item.item, {
          productId: item.productId || item.item,
          score: (item.score || item.confidence || 0) * (1 - weightA),
          source: 'B'
        });
      }
    }

    // 转换为数组并排序
    return [...scoreMap.values()]
      .sort((a, b) => b.score - a.score)
      .slice(0, 10);
  }
}

最佳实践建议

总结

智能推荐引擎是进销存系统的重要增值功能:

通过智能推荐,企业可以提升客户体验、增加销售机会、优化库存周转。

← 下一篇:进销存系统智能客服与语音交互