zoukankan      html  css  js  c++  java
  • (三)基于商品属性的相似商品推荐算法——批量处理商品属性,得到属性前缀及完整属性字符串

    系列随笔:

    (总览)基于商品属性的相似商品推荐算法

    (一)基于商品属性的相似商品推荐算法——整体框架及处理流程

    (二)基于商品属性的相似商品推荐算法——Flink SQL实时计算实现商品的隐式评分

    (三)基于商品属性的相似商品推荐算法——批量处理商品属性,得到属性前缀及完整属性字符串

    (四)基于商品属性的相似商品推荐算法——推荐与评分高的商品属性相似的商品

    (五)基于商品属性的相似商品推荐算法——算法调优及其他

    2020.04.15  补充:协同过滤推荐算法.pptx

    提取码:4tds

    批量处理商品属性,得到属性前缀及完整属性字符串


    一、查询全部商品($lastCode默认0,$limit默认0)

    $sql = "SELECT goods_code FROM sj_goods WHERE goods_code>{$lastCode} ORDER BY goods_code ASC" . ($limit>0? " LIMIT $limit":"");

    注1:如果商品数量较多,建议配合 $lastCode 和 $limit 做分批处理

    注2:查询结果不要直接转数组,用游标操作效率会好一点

    二、每100个商品批量查询处理商品属性

    $list = $this->db['seller']->getAll($sql);
    $goodsCodes = [];
    $count = 0;
    while ($row = $list->fetch(PDO::FETCH_ASSOC)) {
        $count++;
        $goodsCodes[] = $row['goods_code'];
        if ($count%100 == 0) {
            // 每100个商品查询一次属性
            $properties = $this->genGoodsProperties($goodsCodes);
            // 属性入库
            $this->insertGoodsProperties($properties) or die($goodsCodes[0].' 异常!!');
            $goodsCodes = [];
        }
    }
    
    // 别忘了不够100个商品的情况
    if (!empty($goodsCodes)) {
        $properties = $this->genGoodsProperties($goodsCodes);
        $this->insertGoodsProperties($properties) or die($goodsCodes[0].' 异常!!');
    }

    三、具体的属性查询及处理(上面的 genGoodsProperties 方法)

    1)批量查询商品的属性code及属性value

    $sql = "SELECT t1.goods_code,t1.brand_code,t4.property_name,t3.property_code,t3.property_value FROM sj_goods_product t1 LEFT JOIN sj_product t2 ON t2.product_code = t1.product_code LEFT JOIN sj_style_properties t3 ON t3.style_code = t2.style_code LEFT JOIN sp_product_property t4 ON t4.property_code = t3.property_code WHERE t1.goods_code in ('". implode("','", $goodsCodes) ."')";

    注1:主要就是要把商品对应的所有属性值都查询出来,根据自己的项目数据库设计来操作就好

    注2:为了提高商品的相关性,这里我还查询了 brand_code,这个稍候再说怎么用

    2)确定要用哪些属性组合来做前缀,以及完整的属性组合

    // 属性前缀为:适用人群-佩戴场合-机芯类型-价格区间-表盘形状-表盘直径,后面的属性排列顺序可以随意
    $needs = [31=>'适用人群', 40=>'佩戴场合', 1=>'机芯类型', 39=>'价格区间', 9=>'表盘形状', 11=>'表盘直径', 13=>'表盘刻度', 17=>'表带材质', 14=>'表盘颜色', 25=>'防水', 3=>'外壳材质', 38=>'表盘宽度', 3=>'表盘厚度', 12=>'镜面材质', 16=>'表壳底盖', 19=>'表带颜色'];

    注1:数组的键为属性的code,值为属性的名称

    注2:为何这样选以及怎么优化,后面会在  (五)基于商品属性的相似商品推荐算法——算法调优及其他 里做说明。简单来说,属性前缀一样的商品,就是有40%-50%相似的

    3)循环处理商品,利用 1) 和 2) 的数据读取商品属性值,拼接属性组字符串

    private function genGoodsProperties($goodsCodes)
    {
        // 属性前缀为:适用人群-佩戴场合-机芯类型-价格区间-表盘形状-表盘直径,后面的属性排列顺序可以随意
        $needs = [31=>'适用人群', 40=>'佩戴场合', 1=>'机芯类型', 39=>'价格区间', 9=>'表盘形状', 11=>'表盘直径', 13=>'表盘刻度', 17=>'表带材质', 14=>'表盘颜色', 25=>'防水', 3=>'外壳材质', 38=>'表盘宽度', 3=>'表盘厚度', 12=>'镜面材质', 16=>'表壳底盖', 19=>'表带颜色'];
        $properties = $this->getGoodsProperty($goodsCodes);
        $return = [];
        foreach ($goodsCodes as $goodsCode) {
            $prefix = '';
            $full = '';
            foreach ($needs as $key => $value) {
                $brandCode = 0;
                // 这里的 $properties 是第1)步得到的,已转换成了map
                if (isset($properties[$goodsCode][$key]) && !empty($properties[$goodsCode][$key])) {
                    // 如果商品有此属性就拼接属性值
                    $full .= $properties[$goodsCode][$key]['property_value'].'|';
                    $brandCode = $properties[$goodsCode][$key]['brand_code'];
                } else {
                    // 如果商品没有这个属性,或属性值为空,那拼接一个 0
                    $full .= '0|';
                }
    
                // 临界点(拿到属性前缀)
                if ($value == '表盘直径') {
                    $prefix = $full;
                    // 加入品牌信息
                    $full .= $brandCode.'|';
                }
            }
    
            // 截取掉最后多余的 |
            $prefix = substr($prefix, 0, -1);
            $full = substr($full, 0, -1);
            // 拆分多选属性
            $prefix = $this->splitProperties($prefix);
            $full = $this->splitProperties($full);
            $return[$goodsCode] = [$prefix, $full];
        }
        return $return;
    }

    四、属性半成品示例

    例如:有两个商品的属性是这样的(点击放大查看)

     

    经过第三步的处理,它的属性组值是这样的:

    商品A:

    $prefix = '96|297,300|195,41|64|46|218';
    $full   = '96|297,300|195,41|64|46|218|87|220,222|51,242|58|185|198,200|41mm|12mm|276|257';

    商品B:

    $prefix = '96|298,297,299|195|64|46|218';
    $full   = '96|298,297,299|195|64|46|218|87|220,222|242|58|185|200|41mm|L619/888|276|257';

    注:逗号隔开的属性值表示多选属性,例如商品A的佩戴场合为"运动、商务休闲"(297,300),商品B的佩戴场合为"商务休闲、时尚、正装"(298,297,299)

    通过观察属性组,可以看出,其实两个商品是相似的(大部分属性位的值相同);但因为多选属性的影响,在使用属性前缀查询相似商品的时候,不太好办,就是有那么一丢丢不相同(上面示例红色字体部分)

    五、拆分多选属性

    首先,我们先要想一下自己想得到什么,然后再想办法实现。

    例如,我想像中商品A的属性前缀的拆分情况是这样的:

    观察上图可得到:

    第一步,原属性位 “297,300”,被替换成了“297”和“300”,其他属性位不变,得到两个新属性组字符串;

    第二步也一样,两个新属性组字符串的属性位“195,41”,被替换成“195”和“41”,其他属性位不变;

    很明显,这就是一个很简单的字符串替换过程,关键是怎么维护和保存原字符串

    实现代码如下:

    private function splitProperties($propertyPrefixs)
    {
        // 没有多选属性,直接返回
        if (strpos($propertyPrefixs, ',') === false) {
            return [$propertyPrefixs];
        }
    
        // 原属性组(也是结果)
        $origin = [$propertyPrefixs];
        $return = '';
        // 拆分属性位
        $arr1 = explode('|', $propertyPrefixs);
        // 循环属性位
        foreach ($arr1 as $k => $v) {
            // 多选属性位
            if (strpos($v, ',') !== false) {
                $new = [];
                // 拆分多选属性
                $arr2 = explode(',', $v);
                foreach ($arr2 as $kk => $vv) {
                    // 循环原属性组,替换原属性位
                    foreach ($origin as $kkk => $vvv) {
                        $prefixs = str_replace($v, $vv, $vvv);
                        // 替换结果
                        $new[] = $prefixs;
                    }
                }
                // 更新的原属性组
                $origin = $new;
            }
        }
        return $origin;
    }

    六、最终结果展示

    商品A:

    商品B:


    上一节:Flink SQL实时计算实现商品的隐式评分

    下一节:(四)基于商品属性的相似商品推荐算法——推荐与评分高的商品属性相似的商品

  • 相关阅读:
    Fast Member
    C++箴言:理解typename的两个含义
    网上资源工具
    WeakReference
    MonoGame教程
    The RAII Programming Idiom
    OpenGL Common Mistakes
    Finalize()、Dispose()、SafeHandle、GC
    Interop with Native Libraries
    C++计算几何库
  • 原文地址:https://www.cnblogs.com/tujia/p/12360055.html
Copyright © 2011-2022 走看看