B2B2B2C 电商系统过滤solr搜索结果

商品池怎么定义的?

自有商品SKU库的表: shop_goods

alter table shop_goods modify column `goods_pools` varchar(255) DEFAULT '';

这个很重要,保证 goods_pools 字段不为null

自有商品分类就是表: shop_goods_class_custom

自定义的商品库的表: bus_goods_pool

商品池定义: bus_goods_pool

DROP TABLE IF EXISTS bus_goods_pool;
CREATE TABLE bus_goods_pool (
  pool_id varchar(50) NOT NULL,
  pool_name varchar(50) DEFAULT NULL,
  effective_time TIMESTAMP null default now() COMMENT '有效期起始时间',
  failure_time TIMESTAMP null default now() COMMENT '有效期结束时间',
  create_time TIMESTAMP null default now() COMMENT '创建时间',
  update_time TIMESTAMP null default now() on update now() COMMENT '更新时间',
  operator_id varchar(50) DEFAULT NULL COMMENT '操作人id',
  operator varchar(50) DEFAULT NULL COMMENT '操作人',
  pool_type int(10) DEFAULT 1 NULL COMMENT '商品池类型',
  pool_status int(10) DEFAULT 0 NULL comment '状态:0 未启用 1 启用 2 失效',
  PRIMARY KEY (pool_id),
  key pool_name (pool_name) using btree,
  key effective_failure_time (effective_time, failure_time) using btree

) ENGINE=InnoDB DEFAULT CHARSET=utf8 comment '商品池定义';


insert into bus_goods_pool (pool_id, pool_name, effective_time, failure_time, update_time, pool_type, pool_status) values 
((select replace(uuid(), '-', '')), '狗东商品池1', NOW(), DATE_ADD(NOW(),INTERVAL 100 day), NOW(), 1, 1),
((select replace(uuid(), '-', '')), '狗东商品池2', NOW(), DATE_ADD(NOW(),INTERVAL 101 day), NOW(), 1, 1),
((select replace(uuid(), '-', '')), '二手东商品池1', NOW(), DATE_ADD(NOW(),INTERVAL 102 day), NOW(), 1, 1),
((select replace(uuid(), '-', '')), '二手东商品池2', NOW(), DATE_ADD(NOW(),INTERVAL 103 day), NOW(), 1, 1),
((select replace(uuid(), '-', '')), '网易严选商品池1', NOW(), DATE_ADD(NOW(),INTERVAL 104 day), NOW(), 1, 1),
((select replace(uuid(), '-', '')), '网易严选商品池2', NOW(), DATE_ADD(NOW(),INTERVAL 104 day), NOW(), 1, 1);

生成的数据

select * from bus_goods_pool;
f536fc9151a011e8b1b5005056bf65f0    狗东商品池1  2018-05-07 10:47:18 2018-08-15 10:47:18 2018-05-07 10:47:18         1   1   2018-05-07 20:38:15
f536ff8a51a011e8b1b5005056bf65f0    狗东商品池2  2018-05-07 10:47:18 2018-08-16 10:47:18 2018-05-07 10:47:18         1   1   2018-05-07 20:38:15
f537014951a011e8b1b5005056bf65f0    二手东商品池1 2018-05-07 10:47:18 2018-08-17 10:47:18 2018-05-07 10:47:18         1   1   2018-05-07 20:38:15
f537029551a011e8b1b5005056bf65f0    二手东商品池2 2018-05-07 10:47:18 2018-08-18 10:47:18 2018-05-07 10:47:18         1   1   2018-05-07 20:38:15
f53703d451a011e8b1b5005056bf65f0    网易严选商品池1    2018-05-07 10:47:18 2018-08-19 10:47:18 2018-05-07 10:47:18         1   1   2018-05-07 20:38:15
f537054751a011e8b1b5005056bf65f0    网易严选商品池2    2018-05-07 10:47:18 2018-08-19 10:47:18 2018-05-07 10:47:18         1   1   2018-05-07 20:38:15

企业和自定义商品库的映射关系: bus_enterprise_goodspool

DROP TABLE IF EXISTS bus_enterprise_goodspool;
CREATE TABLE bus_enterprise_goodspool (
  id varchar(50) not null,
  enterprise_id varchar(50) NOT NULL comment '企业id',
  enterprise_no varchar(50) NOT NULL comment '企业ep_no',
  pool_id varchar(50) NOT NULL comment '商品池id',
  -- effective_time datetime null default now() COMMENT '有效期起始时间',
  -- failure_time datetime null default now() comment '有效期结束时间',
  priority int(10) DEFAULT 1 null comment '优先级',
  discount double(10, 2) default 1.0 comment '折扣',
  create_time TIMESTAMP null default now() COMMENT '创建时间'
  primary key (id),
  key enterprise_id(enterprise_id) using btree,
  key pool_id(pool_id) using btree
  -- key effective_failure_time(effective_time, failure_time) using btree

) ENGINE=InnoDB DEFAULT CHARSET=utf8 comment='企业商品池关联表';


insert into bus_enterprise_goodspool (id, enterprise_id, enterprise_no, pool_id, priority, discount) values 
((select replace(uuid(), '-', '')), '93fcf2a17a9b4e82af36891726a8e448', '11', 'f536fc9151a011e8b1b5005056bf65f0', 1, 1.0),
((select replace(uuid(), '-', '')), '93fcf2a17a9b4e82af36891726a8e448', '11', 'f536ff8a51a011e8b1b5005056bf65f0', 2, 1.0),
((select replace(uuid(), '-', '')), '93fcf2a17a9b4e82af36891726a8e448', '11', 'f537014951a011e8b1b5005056bf65f0', 3, 1.0),

((select replace(uuid(), '-', '')), '33a6aeed50f011e8b1b5005056bf65f0', 'NO002', 'f537029551a011e8b1b5005056bf65f0', 1, 1.0),
((select replace(uuid(), '-', '')), '33a6aeed50f011e8b1b5005056bf65f0', 'NO002', 'f53703d451a011e8b1b5005056bf65f0', 2, 1.0),
((select replace(uuid(), '-', '')), '33a6aeed50f011e8b1b5005056bf65f0', 'NO002', 'f537054751a011e8b1b5005056bf65f0', 3, 1.0);

生成的数据

select * from bus_enterprise_goodspool;

ab13591851a411e8b1b5005056bf65f0    93fcf2a17a9b4e82af36891726a8e448    11  f536fc9151a011e8b1b5005056bf65f0    1   1   2018-05-07 20:38:33
ab135c0251a411e8b1b5005056bf65f0    93fcf2a17a9b4e82af36891726a8e448    11  f536ff8a51a011e8b1b5005056bf65f0    2   1   2018-05-07 20:38:33
ab135d7851a411e8b1b5005056bf65f0    93fcf2a17a9b4e82af36891726a8e448    11  f537014951a011e8b1b5005056bf65f0    3   1   2018-05-07 20:38:33
ab135e8651a411e8b1b5005056bf65f0    33a6aeed50f011e8b1b5005056bf65f0    NO002   f537029551a011e8b1b5005056bf65f0    1   1   2018-05-07 20:38:33
ab135faf51a411e8b1b5005056bf65f0    33a6aeed50f011e8b1b5005056bf65f0    NO002   f53703d451a011e8b1b5005056bf65f0    2   1   2018-05-07 20:38:33
ab1360e751a411e8b1b5005056bf65f0    33a6aeed50f011e8b1b5005056bf65f0    NO002   f537054751a011e8b1b5005056bf65f0    3   1   2018-05-07 20:38:33

商品池、商品映射关系表: bus_rel_goods_pool

DROP TABLE IF EXISTS bus_rel_goods_pool;
CREATE TABLE bus_rel_goods_pool (
  id varchar(50) NOT NULL ,
  pool_id varchar(50) DEFAULT NULL comment '商品池id',
  goods_id varchar(50) DEFAULT NULL comment '商品id',
  goods_price decimal(10,2) DEFAULT NULL comment '商品池对应的价格',
  partner_id varchar(50) DEFAULT NULL,
  status int(10) DEFAULT NULL comment '状态',
  store_flag int(10) DEFAULT NULL,
  PRIMARY KEY (id),
  key pool_id(pool_id) using BTREE,
  key goods_id (goods_id) using BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC comment='商品池商品关联表';

-- 生成商品池、商品关联数据
SELECT  
concat('((select replace(uuid(), ''-'', ''''))', ', ''f537054751a011e8b1b5005056bf65f0'', ''', g.goods_id, ''', ', goods_store_price, '),')
FROM shop_goods g
ORDER BY RAND()
LIMIT 500;

商品池怎么生成?

通过企业id,去 bus_enterprise_goodspool 表查询其对应的商品池,然后通过商品池的id,去 goods_pool_goods 查询对应商品的总和,根据优先级排序、去重。获得所有的商品。然后再根据商品的 goods_idshop_goods 表里查询 商品的状态,并根据 折扣 * 价格,生成价格。

select
goodspool.priority, pg.goods_price as pool_price, distinct(g.goods_id), g.* 
from bus_enterprise en 
left join bus_enterprise_goodspool goodspool on en.id = goodspool.enterprise_id 
left join bus_goods_pool pool on goodspool.pool_id = pool.pool_id and pool.pool_status = 1
left join bus_rel_goods_pool pg on goodspool.pool_id = pg.pool_id
left join shop_goods g on pg.goods_id = g.goods_id
where en.id = '93fcf2a17a9b4e82af36891726a8e448'
and pool.pool_status = 1
and pool.effective_time < now() and pool.failure_time < DATE_ADD(NOW(),INTERVAL 100 day)

这个sql返回的是所有商品池里的商品的总和。需要按优先级去重

或者可以直接在sql里去重,执行时间差不多

select x.*, gp.goods_price as pool_price , g.*
from 
(select
max(goodspool.priority) as priority, g.goods_id
from bus_enterprise en 
left join bus_enterprise_goodspool goodspool on en.id = goodspool.enterprise_id 
left join bus_goods_pool pool on goodspool.pool_id = pool.pool_id and pool.pool_status = 1
left join bus_rel_goods_pool pg on goodspool.pool_id = pg.pool_id
left join shop_goods g on pg.goods_id = g.goods_id
where en.id = '93fcf2a17a9b4e82af36891726a8e448'
and pool.pool_status = 1
and pool.effective_time < now() and pool.failure_time < DATE_ADD(NOW(),INTERVAL 104 day)
group by g.goods_id
-- order by g.goods_id
) x, bus_rel_goods_pool gp, bus_enterprise_goodspool ep
, shop_goods g
where x.goods_id = gp.goods_id 
and gp.pool_id = ep.pool_id 
and x.priority = ep.priority 
and ep.enterprise_id = '93fcf2a17a9b4e82af36891726a8e448'
and x.goods_id = g.goods_id
order by g.recommend

搜索结果

  1. 在登陆的时候,通过获得 企业id,通过企业id,去 bus_enterprise_goodspool 表查询 该企业有哪些商品池,把这个 数据存到redis里面。

应该存入redis,而不是session。session 是每个用户存一份,redis 是所有用户共享的。

  1. LucenePager 这个类加一个 goodsPool 字段

  2. 调用 search/goodsSearch?searchType=gcIdSearch&keyword=831 这样的接口的时候,从 redis 读该企业都有哪些 商品池的编号,把这个编号数据 赋给 LucenePager 的 goodsPool 字段

  3. 修改 \solr\serviceImpl\SolrServiceImpl.javasearchGoodsIndex 方法,把goodsPool 这个查询条件,加到solr的 queryString 里。

  4. 搜索出结果之后,价格的处理,要依赖于商品池。遍历LucenePager,去商品池查对应的价格。 需要要一个独立的任务维护商品池的数据更新。

搜索的展示层是:

\zzwelfare\welfare-front\src\main\webapp\WEB-INF\views_v4.0\search\goods-search.ftl

是遍历 lucencePager 这个结果集。

假如,想不改展示层的话,那么,从用商品池里取出的结果,替换从solr搜索出来的结果。

\welfare-solr\src\main\java\com\xxyouxx\extend\module\solr\serviceImpl\SolrServiceImpl.java 增加了yige过滤条件,商品池id:

            if(StringUtils.isNotEmpty(lucenePager.getPoolIds())){
                query.addFilterQuery("goodsPools:" + lucenePager.getPoolIds());
                query.set("q", "*:*");
            }

\welfare-service\src\main\java\com\xxyouxx\service\module\search\service\impl\GoodsSearchServiceImpl.java 增加了获取当前企业的商品池id列表


            String enterpriseId = null;
            // 根据当前企业的商品池,修改搜索结果的价格

            String poolIds = null;
            Subject subject = SecurityUtils.getSubject();
            Session session = subject.getSession();

            // 获取企业的id,通过企业的id,获取企业的商品池
            BusEnterprise busEnterprise = (BusEnterprise)session.getAttribute(SysConstants.SESSION_LOGIN_USER_ENTERPRISE);
            if(null != busEnterprise) {
                enterpriseId = busEnterprise.getId();
                if(null != enterpriseId && !"".equals(enterpriseId)) {

                    if(JedisConfig.JEDIS_STATUS) {
                        //需要安装redis
                        Object obj = JedisUtils.getObject(JedisConfig.GOODS_POOL + enterpriseId);
                        if(obj == null){
                            // 先获取商品池id
                            poolIds = busEnterpriseGoodsPoolService.getAllPoolIds(enterpriseId);

                            //1小时,甚至可以更长,因为这基本是配置好了,就不会再变动的数据了。
                            JedisUtils.setObject(JedisConfig.GOODS_POOL + enterpriseId, poolIds, 60 * 60);

                        } else {
                            poolIds = (String)obj;
                        }
                    } else {
                        poolIds = busEnterpriseGoodsPoolService.getAllPoolIds(enterpriseId);
                    }
                }
            }

            // 根据当前企业的商品池,修改搜索结果的价格
            if(org.apache.commons.lang3.StringUtils.isNotBlank(poolIds)) {
                lucenePager.setPoolIds(poolIds);
            }

和 根据 商品池里的价格,更新solr搜索结果价格的代码

            // 用商品池里的价格,来更新商品的价格
            // 根据当前企业的商品池,修改搜索结果的价格
            if(org.apache.commons.lang3.StringUtils.isNotBlank(poolIds)) {

                // 商品池里的全部商品
                List<PoolGoods> poolGoodsList = null;
                PoolGoodsVo vo = new PoolGoodsVo();
                vo.setEnterpriseId(enterpriseId);

                // 确保搜索出结果,再去处理价格
                if(lucenePager.getResult().size() > 0 ) {
                    if(JedisConfig.JEDIS_STATUS) {
                        //需要安装redis
                        Object obj = JedisUtils.getObject(JedisConfig.ENTERPRISE_POOL_GOODS + enterpriseId);
                        if(null == obj || ((List<PoolGoods>)obj).size() == 0) {
                            poolGoodsList = poolGoodsService.findPoolGoods(vo);

                            //然后把这个商品池放到缓存里,而不是修改价格之后的
                            //1小时,甚至可以更长,因为这基本是配置好了,就不会再变动的数据了。
                            JedisUtils.setObject(JedisConfig.ENTERPRISE_POOL_GOODS + enterpriseId, poolGoodsList, 60 * 60);
                        } else {
                            poolGoodsList = (List<PoolGoods>)obj;
                        }

                    } else {
                        poolGoodsList = poolGoodsService.findPoolGoods(vo);
                    }

                    if(null != poolGoodsList && poolGoodsList.size() > 0) {

                        // 用小结果集,驱动大结果集
                        for(Object object : lucenePager.getResult()) {
                            Goods goods = (Goods)object;
                            for(PoolGoods poolGoods: poolGoodsList) {
                                // Mappper 里的sql 确保返回的第一个Goods就是优先级最高的

                                if(goods.getGoodsId().equals(poolGoods.getGoodsId())) {
                                    // 两个对象的goodsId 相同,则认为就是同一个商品,就可以用商品池里的价格更新商品的价格
                                    goods.setGoodsPrice(poolGoods.getGoodsPrice());
                                    break;
                                }
                            }
                        }

                        // 修改价格之后的,也可以考虑放到缓存里。
                        // 这个让生成的HTML去缓存是不是更好?

                    } else {
                        // 配置的数据不对
                        // 处理异常配置
                    }
                }
            }

测试

重新生成 solr 索引

为了避免分页问题,需要solr的搜索结果是一定要给定 满足商品池id 这个条件,这个怎么实现?

solr 的配置文件
http://10.9.19.61:37040/solr/admin.html#/shop_goods/files?file=schema.xml

对于goods_pools 字段的配置:

<field name="goodsPools" type="text_general" indexed="true" stored="true" required="true" multiValued="false" /> 
`

> 注意:shop_goods 表里的 `goods_pools` 字段不能为空,否则使用admin生成索引的时候会报错:

org.apache.solr.client.solrj.impl.HttpSolrClient$RemoteSolrException: Error from server at http://10.9.19.61:37040/solr/shop_goods: [doc=a100004458] missing required field: goodsPools


所以,需要针对表结构做修改
```sql
alter table shop_goods modify column `goods_pools` varchar(255) DEFAULT '';
update shop_goods set goods_pools = '' where goods_pools is null;

同时,针对java 的 entity 类做修改,给 goodsPools 字段赋默认值
\welfare-core\src\main\java\com\xxyouxx\core\entity\base\Goods.java

    @Field
    private String goodsPools = "";

更新 shop_goods 表里的 goods_pools 字段

select (select GROUP_CONCAT(pool_id SEPARATOR ',') from bus_rel_goods_pool pg where pg.goods_id = g.goods_id), g.* from shop_goods g;

update shop_goods g set goods_pools = (select GROUP_CONCAT(pool_id SEPARATOR ' ') from bus_rel_goods_pool pg where pg.goods_id = g.goods_id);
update shop_goods set goods_pools = "" where goods_pools is null;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • CREATE TABLE IF NOT EXISTS ecs_order_info (order_id mediu...
    cookie口阅读 15,664评论 0 16
  • 基础知识: 1.数据库的连接mysql -u -p -h-u 用户名-p 密码-h host主机 2:库级知识2....
    网络安全自修室阅读 1,452评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • If a loan is 4 years, what can we do? :::: We need a defa...
    MC1229阅读 311评论 0 0
  • 一,课堂上的收获 看到需要,比满足需要更重要。看到需要我们的策论就多了。 二,无法释怀的事 好像想了很久没有无法释...
    幸福石头阅读 147评论 0 1