技术心得:功能点分析:商品类目表

简介: 技术心得:功能点分析:商品类目表

前言


    作为电商网站,必然要有商品类目表,以便商品分类检索。而设计商品类目表,又是一件特别繁杂的事情。一件商品可能有多个类目来检索出来,比如苹果手机,可以从品牌检索也可以从手机检索。一个类目对应多个商品,比如手机下对应了多款属于手机类的商品。而类目是一个多叉树结构,类似于文件夹的结构。通常大电商都是把类目整理好了放在cache上,就不用频繁访问数据库和整理排序了。


个人类目标的结构设计


    参考了一下网上无限级分类的表设计,简化模型为一个表内存在父子级从属关系。


    表中的isRoot可以去掉,只要parent为0就认为是根节点就好了。而为什么不存子节点而是存父节点,因为子节点的映射类,生成整理的时候比存父节点要复杂一些,当然程序写的不复杂而是这个问题需要花费的时间就会多一些。


    表设计好了之后,就需要查询数据并且整理出他们的从属关系。为了减少数据库的查询次数,我采用了全部查询,在内存中生成多叉树的形式。节点类的定义想法非常直接,它存在唯一识别:id,真实信息:name,以及它的子树:List or Map。


/


树型存储


/


class CategoryTree{


private long id;


private String name;


private List children;


public CategoryTree(){


children = new ArrayList();


}


public long getId() {


return id;


}


public void setId(long id) {


this.id = id;


}


public String getName() {


return name;


}


public void setName(String name) {


this.name = name;


}


public List getChildren() {


return children;


}


public void setChildren(List children) {


this.children = children;


}


}


/


哈希表存储


/


class CategoryMap{


private long id;


private String name;


private Map children;


public CategoryMap(){


children = new HashMap();


}


public long getId() {


return id;


}


public void setId(long id) {


this.id = id;


}


public String getName() {


return name;


}


public void setName(String name) {


this.name = name;


}


public Map getChildren() {


return children;


}


public void setChildren(Map children) {


this.children = //代码效果参考:http://hnjlyzjd.com/hw/wz_24902.html

children;

}


}


    在对乱序数组生成三级n叉树这个过程中,最快的方式是用map。在生成过程中,只能一级级生成,因为没有父节点不可能有子节点跟随这个逻辑的存在。


//集合存储


public void test1(){


tool.connection2MYSQL();


Connection conn = tool.getCon();


String sql = "select from category";


Statement stm = null;


List clist = new ArrayList();


try {


stm = conn.createStatement();


ResultSet rs = stm.executeQuery(sql);


while(rs.next()){


category c = new category();


c.setId(rs.getLong("id"));


c.setName(rs.getString("name"));


c.setParentId(rs.getLong("parent_id"));


c.setIsRoot(rs.getInt("is_root"));


clist.add(c);


}


tool.closeConn(conn);


} catch //代码效果参考:http://hnjlyzjd.com/xl/wz_24900.html

(SQLException e1) {

// TODO Auto-generated catch block


e1.printStackTrace();


}


/


检查集合


/


// for(category ca:clist){


// System.out.println("id: "+ca.getId()+" name: "+ca.getName()+" parentId: "+ca.getParentId()+" isRoot: "+ca.getIsRoot());


// }


/


逻辑尝试=====


/


List roots = new ArrayList();


List second = new ArrayList();


List third = new ArrayList();


//一次遍历 添加根节点


int i = 0;


while(i != clist.size()-1){


if(clist.get(i).getParentId() == 0){


CategoryTree ct = new CategoryTree();


ct.setId(clist.get(i).getId());


ct.setName(clist.get(i).getName());


roots.add(ct);


clist.remove(i);


}else


i++;


}


//二次遍历 添加二级节点


for(int j=0;j

i = 0;


while(i [span style="color: rgba(0, 0, 0, 1)"> clist.size()){


if(clist.get(i).getParentId() == roots.get(j).getId()){


CategoryTree ct = new CategoryTree();


ct.setId(clist.get(i).getId());


ct.setName(clist.get(i).getName());


roots.get(j).getChildren().add(ct);


second.add(ct);//用空间换


clist.remove(i);


}else


i++;


}


}


//三次遍历 添加三级节点


for(int j=0;j

i = 0;


while(i [span style="color: rgba(0, 0, 0, 1)"> clist.size()){


if(clist.get(i).getParentId() == second.get(j).getId()){


CategoryTree ct = new CategoryTree();


ct.setId(clist.get(i).getId());


ct.setName(clist.get(i).getName());


second.get(j).getChildren().add(ct);


third.add(ct);//用空间换


clist.remove(i);


}else


i++;


}


}


for(category ca:clist){


System.out.println("id: "+ca.getId()+" name: "+ca.getName()+" parentId: "+ca.getParentId()+" isRoot: "+ca.getIsRoot());


}


for(CategoryTree ct:roots){


System.out.println("id: "+ct.getId()+" name: "+ct.getName());


{


for(CategoryTree ct1:ct.getChildren())


{


System.out.println("二级 id: "+ct1.getId()+" name: "+ct1.getName());


for(CategoryTree ct2:ct1.getChildren())


System.out.println("三级 id: "+ct2.getId()+" name: "+ct2.getName());


}


}


}/


逻辑尝试=====


/


}


    我对每一级的节点做了一个额外的存储,在第三级生成的时候简化一个循环,也就是n平方的复杂度。


    使用map生成的话,仅在生成这个过程,就可以把问题化简成n的复杂度。因为Map“知道”自己存储的对象的id,而List要通过遍历才知道它的自己存的元素的id。


public void test2(){


tool.connection2MYSQL();


Connection conn = tool.getCon();


String sql = "select from category";


Statement stm = null;


List clist = new ArrayList();


try {


stm = conn.createStatement();


ResultSet rs = stm.executeQuery(sql);


while(rs.next()){


category c = new category();


c.setId(rs.getLong("id"));


c.setName(rs.getString("name"));


c.setParentId(rs.getLong("parent_id"));


c.setIsRoot(rs.getInt("is_root"));


clist.add(c);


}


tool.closeConn(conn);


} catch (SQLException e1) {


// TODO Auto-generated catch block


e1.printStackTrace();


}


/**


逻辑尝试=====


/


Map rootMap = new HashMap();


Map secondMap = new HashMap();


//遍历一级


int i = 0;


while(i [span style="color: rgba(0, 0, 0, 1)"> clist.size()){


if(clist.get(i).getParentId() == 0){


CategoryMap cm = new CategoryMap();


cm.setId(clist.get(i).getId());


cm.setName(clist.get(i).getName());


rootMap.put(cm.getId(),cm);


clist.remove(i);


}else


i++;


}


//遍历二级


i = 0;


while (i [span style="color: rgba(0, 0, 0, 1)"> clist.size()) {


if (rootMap.get(clist.get(i).getParentId()) != null) {


CategoryMap cm = new CategoryMap();


cm.setId(clist.get(i).getId());


cm.setName(clist.get(i).getName());


rootMap.get(clist.get(i).getParentId()).getChildren().put(cm.getId(), cm);


secondMap.put(cm.getId(), cm);


clist.remove(i);


} else


i++;


}


//遍历三级


i = 0;


while (i [span style="color: rgba(0, 0, 0, 1)"> clist.size()) {


if (secondMap.get(clist.get(i).getParentId()) != null) {


CategoryMap cm = new CategoryMap();


cm.setId(clist.get(i).getId());


cm.setName(clist.get(i).getName());


secondMap.get(clist.get(i).getParentId()).getChildren().put(cm.getId(), cm);


clist.remove(i);


} else


i++;


}


// for (Map.Entry entry : rootMap.entrySet()) {


// System.out.println("Key = " + entry.getKey() + ", id : " + entry.getValue().getId()+" name : "+entry.getValue().getName());


// for (Map.Entry entry1 : entry.getValue().getChildren().entrySet()){


// System.out.println("二级 Key = " + entry1.getKey() + ", id : " + entry1.getValue().getId()+" name : "+entry1.getValue().getName());


// for (Map.Entry entry2 : entry1.getValue().getChildren().entrySet()){


// System.out.println("三级 Key = " + entry2.getKey() + ", id : " + entry2.getValue().getId()+" name : "+entry2.getValue().getName());


// }


// }


//


// }


JSONArray json = new JSONArray();


for (CategoryMap entry : rootMap.values()) {


JSONObject job1 = new JSONObject();


job1.put("id", entry.getId());


job1.put("name", entry.getName());


JSONArray joa1 = new JSONArray();


// System.out.println("id : " + entry.getId()+" name : "+entry.getName());


for (CategoryMap entry1 : entry.getChildren().values()){


JSONObject job2 = new JSONObject();


job2.put("id", entry1.getId());


job2.put("name", entry1.getName());


JSONArray joa2 = new JSONArray();


// System.out.println("二级 id : " + entry1.getId()+" name : "+entry1.getName());


for (CategoryMap entry2 : entry1.getChildren().values()){


JSONObject job3 = new JSONObject();


job3.put("id", entry2.getId());


job3.put("name", entry2.getName());


joa2.add(job3);


// System.out.println("三级 id : " + entry2.getId() + " name : "+entry2.getName());


}


job2.put("chird", joa2);


joa1.add(job2);


}


job1.put("chird", joa1);


json.add(job1);


}


for(int k=0;k

JSONObject jo = json.getJSONObject(k);


System.out.println(jo.toString());


}


/**


逻辑尝试=====


*/


}


    最后的生成json的时候,仍然需要三次方的复杂度,我在考虑如何能在整理过程中顺带生成json,现在还没做出来,不过优化成n应该还是有机会的。


    另外,遍历源数据的时候,把抽掉的节点remove掉也是一种减少重复遍历的方式。


    最后生成的结果如同预期。


连接成功


{"chird":【{"chird":【{"name":"衬衣","id":16}】,"name":"七匹狼","id":6},{"chird":【{"name":"运动服","id":17}】,"name":"阿迪达斯","id":7}】,"name":"男装","id":1}


{"chird":【{"chird":【{"name":"毛衣","id":18}】,"name":"zara","id":8},{"chird":【{"name":"包包","id":19}】,"name":"普拉达","id":9}】,"name":"女装","id":2}


{"chird":【{"chird":【{"name":"笔记本电脑","id":20}】,"name":"dell","id":10},{"chird":【{"name":"台式电脑","id":21}】,"name":"lenovo","id":11}】,"name":"电脑","id":3}


{"chird":【{"chird":【{"name":"note","id":22}】,"name":"三星","id":12},{"chird":【{"name":"iPhone","id":23}】,"name":"苹果","id":13}】,"name":"手机","id":4}


{"chird":【{"chird":【{"name":"第一版","id":24}】,"name":"Java程序设计","id":14},{"chird":【{"name":"第三版","id":25}】,"name":"C++程序设计","id":15}】,"name":"图书","id":5}


总结


    对于表设计和这个问题的解决不知道有没有更加规范一点的方式,还需要继续探讨。对于我们项目来说,这个方法已经可以适应了,商品分类我打算用个分类表来做映射,类目表叶子节点的id和商品的id存入,检索的时候根据叶子节点id检索所有商品。本次问题,在于对乱序数组转化为多叉树的模型建立,解决了这个问题,对转化思维又有了进一步的提高。(在这里其实问题的阶并不重要,因为这是有穷集合,类目表的条目基本不会超过几百,考虑的最多的就是访问量的问题,因为小电商不会做cache,每一次访问都生成三级树,所以本次问题重在如何用更好的运算模型去解决同一个问题)


追加


    关于三级关系树的运用,我做了一个小的地域管理页面,与类目树是一样的结构。


<%@ page language="java" contentType="text/html; charset=UTF-8"


pageEncoding="UTF-8"%>


<%@include file="/common.jsp" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" ""

[/span>html

[/span>head

[/span>script type="text/javascript" src="js/jquery.js"

<span style="color: rgb

相关文章
|
7月前
|
机器学习/深度学习 搜索推荐 API
商品信息全景图:API接口在聚合商品数据中的应用
在电子商务的世界中,API接口是连接不同服务和数据的桥梁。特别是在商品信息的聚合上,API接口扮演了至关重要的角色,它允许开发者从多个来源收集、整合并展示商品信息,从而为消费者提供全面且一致的购物体验。本文将深入探讨API接口在聚合商品数据中的应用,并通过具体的代码示例来揭示其工作原理。
|
2月前
|
供应链 监控 数据挖掘
淘宝商品详情数据接口:解锁电商数据分析新密码
在数字化时代,电商竞争激烈,精准的数据分析成为制胜关键。淘宝商品详情数据接口如同一把神奇的钥匙,为商家提供商品名称、价格、销量、评价等详细信息,助力洞察市场趋势、优化商品策略、提升运营效率。通过实时更新的数据,商家可以及时调整定价、促销和库存管理,增强竞争力。未来,该接口将带来更多智能化的数据分析工具和精准的市场预测模型,助力电商从业者在竞争中脱颖而出。
|
5月前
|
分布式计算 大数据 MaxCompute
MaxCompute产品使用合集之如何实现根据商品维度统计每件商品的断货时长的功能
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
6月前
电商项目商品表关系广告类别表
电商项目商品表关系广告类别表
|
6月前
|
存储 JSON API
批量采集抖音商品详情数据:推荐你使用API(通过商品id取商品详情商品主图sku属性)
批量采集抖音商品详情,建议使用API接口。步骤包括:注册抖音开放平台获取App Key和Secret,调用商品详情API接口传入商品ID及相关参数,解析返回的JSON获取商品信息(如名称、价格、主图和SKU)。此外,接口列表提供商品搜索、销售量查询、历史价格、订单管理等多种功能。已封装的API接口地址:c0b.cc/R4rbK2,可测试并联系获取SDK文件。
|
6月前
|
数据库
电商购物系统商品数据结构设置 -- 商品类别表
电商购物系统商品数据结构设置 -- 商品类别表
|
7月前
|
存储 数据采集 搜索推荐
商品比价系统实现
商品比价系统实现
412 4
|
7月前
|
搜索推荐 算法
基于用户的协同过滤算法实现商品推荐
基于用户的协同过滤算法实现商品推荐
89 2
|
7月前
|
存储 数据采集 JSON
电商API分享:如何批量获取商品详情页数据(属性图价格sku视频评论)
电商API(应用程序接口)通常提供了丰富的数据获取功能,使开发者能够方便地获取商品详情页的各种数据,包括商品属性、图片、价格、SKU(库存量单位)、视频以及评论等。以下是一个基本的步骤指南,用于通过电商API批量获取商品详情页数据:
电商API接口开发系列-商品采集接口、关键字搜索接口,获取商品ID、商品主图接口
目前各大电商平台都有自己的开放平台,通过API接口开放本电商平台的相关数据和功能,以自由开放的姿态来占领更多的市场份额。也让更多的人能来电商市场分得一杯羹。 通过电商API接口可以实现获取电商平台商品数据、订单数据、上下架商品、批量处理订单、批量发货、批量购买、买家信息、卖家信息等等功能。
电商API接口开发系列-商品采集接口、关键字搜索接口,获取商品ID、商品主图接口