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

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

前言


    作为电商网站,必然要有商品类目表,以便商品分类检索。而设计商品类目表,又是一件特别繁杂的事情。一件商品可能有多个类目来检索出来,比如苹果手机,可以从品牌检索也可以从手机检索。一个类目对应多个商品,比如手机下对应了多款属于手机类的商品。而类目是一个多叉树结构,类似于文件夹的结构。通常大电商都是把类目整理好了放在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

相关文章
|
2月前
|
机器学习/深度学习 搜索推荐 API
商品信息全景图:API接口在聚合商品数据中的应用
在电子商务的世界中,API接口是连接不同服务和数据的桥梁。特别是在商品信息的聚合上,API接口扮演了至关重要的角色,它允许开发者从多个来源收集、整合并展示商品信息,从而为消费者提供全面且一致的购物体验。本文将深入探讨API接口在聚合商品数据中的应用,并通过具体的代码示例来揭示其工作原理。
|
26天前
电商项目商品表关系广告类别表
电商项目商品表关系广告类别表
|
26天前
|
数据库
电商购物系统商品数据结构设置 -- 商品类别表
电商购物系统商品数据结构设置 -- 商品类别表
|
2月前
|
存储 数据采集 搜索推荐
商品比价系统实现
商品比价系统实现
140 4
|
2月前
|
搜索推荐 算法
基于用户的协同过滤算法实现商品推荐
基于用户的协同过滤算法实现商品推荐
49 2
|
9月前
|
前端开发 JavaScript
23分布式电商项目 - 商品分类管理(列表实现)
23分布式电商项目 - 商品分类管理(列表实现)
61 0
|
12月前
|
XML JSON 缓存
Java实现商品ID获取淘宝商品类目数据方法
Java实现商品ID获取淘宝商品类目数据方法
114 0
|
API 开发工具
itemprops.get( 获取标准商品类目属性 )
通过设置必要的参数,来获取商品后台标准类目属性,以及这些属性里面详细的属性值prop_values。
|
测试技术 数据库
实战SSM_O2O商铺_38【商品类别】解除商品与商品类别的关联
实战SSM_O2O商铺_38【商品类别】解除商品与商品类别的关联
70 0
|
JSON 前端开发 Java
谷粒商城--商品新增业务流程分析
谷粒商城--商品新增业务流程分析
146 0