一、案例逻辑
1.1 solr搜索实现三步走实现
1,需要把商品的数据导入到Solr 里面
2,根据条件编写各种代码实现搜索
3,使用定时任务定时同步数据库和solr的数据【当然应该提供手动同步】
1.2 solr搜索说明
1.2.1 关键字搜索 copyField[数组]去完成
1.2.2 分页
1.2.3 过滤条件
1.2.4 排序
1.2.5 高亮
1.2.6 价格区间
二、准备数据库
jd-shop
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for goods -- ---------------------------- DROP TABLE IF EXISTS `goods`; CREATE TABLE `goods` ( `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '商品ID', `name` varchar(300) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '商品名称', `shopid` bigint(20) NULL DEFAULT NULL COMMENT '店铺id', `oriprice` decimal(15, 2) NULL DEFAULT 0.00 COMMENT '原价', `price` decimal(15, 2) NULL DEFAULT NULL COMMENT '现价', `remark` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '简要描述,卖点等', `content` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '详细描述', `picture` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '商品主图', `imgs` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '商品图片,以,分割', `status` int(1) NULL DEFAULT 0 COMMENT '默认是1,表示正常状态, -1表示删除, 0下架', `categoryid` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '商品分类', `salenum` int(11) NULL DEFAULT NULL COMMENT '销量', `totalstocks` int(11) NULL DEFAULT 0 COMMENT '总库存', `deliverymode` json NULL COMMENT '配送方式json', `deliverytemplateid` bigint(20) NULL DEFAULT NULL COMMENT '运费模板id', `createtime` datetime(0) NULL DEFAULT NULL COMMENT '录入时间', `updatetime` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改时间', `filters` json NULL COMMENT '{\"is_jd_express\":true,\"is_second-hand\":true,\"is_new\":true,\"is_to_pay\":true} 是否京东快递,是否二手,是否新品,是否支持货到付款', PRIMARY KEY (`id`) USING BTREE, INDEX `shop_id`(`shopid`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 95 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '商品' ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of goods -- ---------------------------- INSERT INTO `goods` VALUES (1, 'Apple iPhone XS Max 移动联通电信4G手机 111111', 1, 0.00, 1.01, '6.5英寸大屏,支持双卡。', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 1, 93, 0, 95, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 78, '2019-03-29 14:40:00', '2020-04-04 15:07:24', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (2, '兰蔻粉水清滢柔肤水400ml 爽肤水女保湿舒缓滋润嫩肤', 1, 0.00, 420.00, '好看耐穿', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 1, 87, 0, 0, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 48, '2019-04-21 19:15:34', '2020-04-04 15:07:34', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (3, '【Dole都乐】菲律宾都乐非转基因木瓜1只 单只约410g', 1, 0.00, 26.00, '包邮 肉厚籽少 独具风味', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 1, 95, 0, 0, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 47, '2019-04-21 21:56:38', '2020-04-04 15:07:34', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (4, '阿迪达斯官方 adidas 三叶草 NITE JOGGER 男子经典鞋BD7956', 1, 10.00, 1199.00, ' 运动鞋/休闲鞋', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 0, 88, 0, 0, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 47, '2019-04-21 22:10:04', '2020-04-04 15:07:35', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (5, '【Dole都乐】比利时Truval啤梨12只 进口水果新鲜梨 单果120g左右', 1, 0.00, 38.00, '好吃', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 1, 95, 100, 15, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 47, '2019-04-22 16:43:33', '2020-04-04 15:07:36', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (6, '旗舰店官网 自拍神器 梵高定制', 1, 10.00, 6998.00, '梵高定制礼盒 全球限量发售 分期免息', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 1, 85, 0, 99, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 47, '2019-04-23 15:43:26', '2020-04-04 15:07:36', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (7, '餐厅装饰画现代简约饭厅挂画墙面壁画好好吃饭', 1, 169.00, 169.00, '创意餐厅装饰画 好好吃饭', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 1, 91, 0, 0, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 47, '2019-04-25 10:22:21', '2020-04-04 15:07:37', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (8, '阴阳师寮办秘制 月见和菓子 184克', 1, 0.00, 22.00, '三层夹心,Q弹有料', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 1, 95, 0, 77, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 47, '2019-04-27 11:37:13', '2020-04-04 15:07:37', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (9, '旺仔牛奶', 2, 0.00, 100.00, '测试', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 1, 95, 0, 0, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 48, '2019-05-22 10:39:49', '2020-04-04 15:07:38', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (10, '测试商品A', 1, 30.00, 30.00, '牛逼', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 1, 95, 0, 30, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 47, '2019-05-23 17:23:11', '2020-04-04 15:07:38', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (11, '测试商品B', 1, 40.00, 40.00, 'BBBB', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 1, 95, 0, 40, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 47, '2019-05-23 17:24:06', '2020-04-04 15:07:39', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (12, '测试商品C', 1, 60.00, 50.00, 'CCC', '<p>测试商品</p>', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 'https://img12.360buyimg.com/n7/jfs/t7297/154/3413903491/65679/45ae4902/59e42830N9da56c41.jpg', 1, 95, 0, 50, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 47, '2019-05-23 17:24:48', '2020-04-04 15:07:39', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (13, '华为鲸鱼手机', 1, 0.00, 0.00, '5G快速四摄高清', '<p>测试商品</p>', 'http://47.101.176.118/g1/M00/00/00/rBPi511H47aAEkS9AAD0Hf0JFCw449.jpg', 'http://47.101.176.118/g1/M00/00/00/rBPi511H47aAEkS9AAD0Hf0JFCw449.jpg', 1, 93, 0, 0, '{\"hasUserPickUp\": true, \"hasShopDelivery\": false}', 59, '2019-08-05 17:13:41', '2020-04-04 15:07:40', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (14, '鲸鱼', 1, 0.00, 0.00, '鲸鱼好吃的鲸鱼', '<p>测试商品</p>', 'http://47.101.176.118/g1/M00/00/00/rBPi511H8_KAWI_tAAAH1Pr_MrM101.jpg', 'http://47.101.176.118/g1/M00/00/00/rBPi511H8_KAWI_tAAAH1Pr_MrM101.jpg', 1, 96, 0, 0, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 59, '2019-08-05 17:17:31', '2020-04-04 15:07:40', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (15, '华为Mate 20 PRO', 1, 0.00, 1.00, '5G四摄索引麒麟980', '<p>测试商品</p>', 'http://47.101.176.118/g1/M00/00/00/rBPi511H9P6AW6-sAAD0Hf0JFCw913.jpg', 'http://47.101.176.118/g1/M00/00/00/rBPi511H9P6AW6-sAAD0Hf0JFCw913.jpg', 1, 93, 0, 4, '{\"hasUserPickUp\": false, \"hasShopDelivery\": true}', 59, '2019-08-05 17:24:15', '2020-04-04 15:07:41', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (16, '算法导论第四版', 1, 0.00, 11.00, '你学不会', '<p>测试商品</p>', 'http://47.101.176.118/g1/M00/00/00/rBPi511Tdt2Aa6pQAABcteVfoYk808.jpg', 'http://47.101.176.118/g1/M00/00/00/rBPi511Tdt2Aa6pQAABcteVfoYk808.jpg', 1, 94, 0, 11, '{\"hasUserPickUp\": true, \"hasShopDelivery\": false}', 47, '2019-08-14 10:58:09', '2020-04-04 15:07:41', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (17, '算法导论第四版', 1, 0.00, 11.00, '你学不会', '<p>测试商品</p>', 'http://47.101.176.118/g1/M00/00/00/rBPi511Tdt2Aa6pQAABcteVfoYk808.jpg', 'http://47.101.176.118/g1/M00/00/00/rBPi511Tdt2Aa6pQAABcteVfoYk808.jpg', 1, 94, 0, 11, '{\"hasUserPickUp\": true, \"hasShopDelivery\": false}', 47, '2019-08-14 10:58:10', '2020-04-04 15:07:42', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (18, '算法导论第N版', 1, 0.00, 1.00, '学不会', '<p>测试商品</p>', 'http://47.101.176.118/g1/M00/00/01/rBPi511TeU6AUZ1hAABcteVfoYk222.jpg', 'http://47.101.176.118/g1/M00/00/01/rBPi511TeU6AUZ1hAABcteVfoYk222.jpg', 1, 94, 0, 1, '{\"hasUserPickUp\": true, \"hasShopDelivery\": false}', 47, '2019-08-14 11:01:19', '2020-04-04 15:07:42', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (19, '锤子(smartisan) 坚果Pro3 8GB+128GB 黑色 骁龙855PLUS 4800万四摄 全网通双卡双待 全面屏游戏手机', 1, 2289.00, 2289.00, '稀缺货源,限量抢购】2K+90Hz流体屏,骁龙855旗舰,4800万超广角三摄,影音娱乐不在话下', '<p>测试商品</p>', 'http://47.101.176.118/g1/M00/00/01/rBPi511Ted6AV01_AABcteVfoYk963.jpg', 'http://47.101.176.118/g1/M00/00/01/rBPi511Ted6AV01_AABcteVfoYk963.jpg', 1, 93, 0, 0, '{\"hasUserPickUp\": true, \"hasShopDelivery\": false}', 47, '2019-08-14 11:03:23', '2020-04-04 15:07:43', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (20, '荣耀9X 麒麟810 4000mAh续航 4800万超清夜拍 6.59英寸升降全面屏 全网通6GB+64GB 魅海蓝', 1, 1289.00, 1289.00, '稀缺货源,限量抢购】2K+90Hz流体屏,骁龙855旗舰,4800万超广角三摄,影音娱乐不在话下', '<p>测试商品</p>', 'http://47.101.176.118/g1/M00/00/01/rBPi511Ted6AV01_AABcteVfoYk963.jpg', 'http://47.101.176.118/g1/M00/00/01/rBPi511Ted6AV01_AABcteVfoYk963.jpg', 1, 93, 0, 0, '{\"hasUserPickUp\": true, \"hasShopDelivery\": false}', 47, '2019-08-14 11:03:23', '2020-04-04 15:07:43', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (21, 'Apple iPhone 11 (A2223) 128GB 黑色 移动联通电信4G手机 双卡双待', 1, 5999.00, 5999.00, '稀缺货源,限量抢购】2K+90Hz流体屏,骁龙855旗舰,4800万超广角三摄,影音娱乐不在话下', '<p>测试商品</p>', 'http://47.101.176.118/g1/M00/00/01/rBPi511Ted6AV01_AABcteVfoYk963.jpg', 'http://47.101.176.118/g1/M00/00/01/rBPi511Ted6AV01_AABcteVfoYk963.jpg', 1, 93, 0, 0, '{\"hasUserPickUp\": true, \"hasShopDelivery\": false}', 47, '2019-08-14 11:03:25', '2020-04-04 15:07:43', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (22, '一加 OnePlus 7T 90Hz流体屏 骁龙855Plus旗舰 4800万超广角三摄 8GB+256GB 冰川银 全面屏拍照游戏手机', 1, 3199.00, 3199.00, '稀缺货源,限量抢购】2K+90Hz流体屏,骁龙855旗舰,4800万超广角三摄,影音娱乐不在话下', '<p>测试商品</p>', 'http://47.101.176.118/g1/M00/00/01/rBPi511Ted6AV01_AABcteVfoYk963.jpg', 'http://47.101.176.118/g1/M00/00/01/rBPi511Ted6AV01_AABcteVfoYk963.jpg', 1, 93, 0, 0, '{\"hasUserPickUp\": true, \"hasShopDelivery\": false}', 47, '2019-08-14 11:05:43', '2020-04-04 15:07:45', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); INSERT INTO `goods` VALUES (23, '努比亚 nubia X 双面屏 深空灰 8GB+128GB 全网通 移动联通电信4G手机 双卡双待', 1, 2399.00, 2399.00, '【火爆销售中】双屏黑科技,骁龙845,AOD熄屏,双摄AI美颜自拍', '<p>测试商品</p>', 'http://47.101.176.118/g1/M00/00/01/rBPi511TeqGAdjQfAABcteVfoYk439.jpg', 'http://47.101.176.118/g1/M00/00/01/rBPi511TeqGAdjQfAABcteVfoYk439.jpg', 1, 85, 0, 1, '{\"hasUserPickUp\": true, \"hasShopDelivery\": false}', 47, '2019-08-14 11:07:04', '2020-04-04 15:07:44', '{\"is_new\": true, \"is_to_pay\": true, \"is_jd_express\": true, \"is_second_hand\": true}'); SET FOREIGN_KEY_CHECKS = 1;
updatetime 是最后做增加更新时使用
三、创建项目
3.1 springboot项目
3.2修改pom.xml添加Druid和mybatisplus的依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.1.tmp</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.21</version> </dependency>
3.3 配置yml
#端口 server: port: 8080 spring: #数据源的配置 datasource: url: jdbc:mysql://127.0.0.1:3306/jd-shop?serverTimezone=UTC username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver application: name: jd-search data: solr: host: http://47.95.34.202:8983/solr/jd-shop #配置mybatisplus mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl mapper-locations: classpath:mapper/*.xml global-config: db-config: id-type: auto
3.4 使用插件生成Goods和GoodsMapper
3.4.1 准备工作
3.4.2 安装插件
https://zhile.io/2019/04/23/mybatis-code-helper-pro-crack.html
OK之后重启IDEA
3.4.3 生成Goods,GoodsMapper,XML
Goods
@Data @AllArgsConstructor @NoArgsConstructor @TableName(value = "goods") public class Goods { /** * 商品ID */ @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 商品名称 */ @TableField(value = "name") private String name; /** * 店铺id */ @TableField(value = "shopid") private Long shopid; /** * 原价 */ @TableField(value = "oriprice") private BigDecimal oriprice; /** * 现价 */ @TableField(value = "price") private BigDecimal price; /** * 简要描述,卖点等 */ @TableField(value = "remark") private String remark; /** * 详细描述 */ @TableField(value = "content") private String content; /** * 商品主图 */ @TableField(value = "picture") private String picture; /** * 商品图片,以,分割 */ @TableField(value = "imgs") private String imgs; /** * 默认是1,表示正常状态, -1表示删除, 0下架 */ @TableField(value = "status") private Integer status; /** * 商品分类 */ @TableField(value = "categoryid") private Long categoryid; /** * 销量 */ @TableField(value = "salenum") private Integer salenum; /** * 总库存 */ @TableField(value = "totalstocks") private Integer totalstocks; /** * 配送方式json */ @TableField(value = "deliverymode") private Object deliverymode; /** * 运费模板id */ @TableField(value = "deliverytemplateid") private Long deliverytemplateid; /** * 录入时间 */ @TableField(value = "createtime") private Date createtime; /** * 修改时间 */ @TableField(value = "updatetime") private Date updatetime; /** * {"is_jd_express":true,"is_second-hand":true,"is_new":true,"is_to_pay":true} 是否京东快递,是否二手,是否新品,是否支持货到付款 */ @TableField(value = "filters") private Object filters; public static final String COL_ID = "id"; public static final String COL_NAME = "name"; public static final String COL_SHOPID = "shopid"; public static final String COL_ORIPRICE = "oriprice"; public static final String COL_PRICE = "price"; public static final String COL_REMARK = "remark"; public static final String COL_CONTENT = "content"; public static final String COL_PICTURE = "picture"; public static final String COL_IMGS = "imgs"; public static final String COL_STATUS = "status"; public static final String COL_CATEGORYID = "categoryid"; public static final String COL_SALENUM = "salenum"; public static final String COL_TOTALSTOCKS = "totalstocks"; public static final String COL_DELIVERYMODE = "deliverymode"; public static final String COL_DELIVERYTEMPLATEID = "deliverytemplateid"; public static final String COL_CREATETIME = "createtime"; public static final String COL_UPDATETIME = "updatetime"; public static final String COL_FILTERS = "filters"; }
GoodsMapper
public interface GoodsMapper extends BaseMapper<Goods> { }
GoodsMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.solr.mapper.GoodsMapper"> <resultMap id="BaseResultMap" type="com.example.solr.domain.Goods"> <!--@mbg.generated--> <!--@Table goods--> <id column="id" jdbcType="BIGINT" property="id" /> <result column="name" jdbcType="VARCHAR" property="name" /> <result column="shopid" jdbcType="BIGINT" property="shopid" /> <result column="oriprice" jdbcType="DECIMAL" property="oriprice" /> <result column="price" jdbcType="DECIMAL" property="price" /> <result column="remark" jdbcType="VARCHAR" property="remark" /> <result column="content" jdbcType="LONGVARCHAR" property="content" /> <result column="picture" jdbcType="VARCHAR" property="picture" /> <result column="imgs" jdbcType="VARCHAR" property="imgs" /> <result column="status" jdbcType="INTEGER" property="status" /> <result column="categoryid" jdbcType="BIGINT" property="categoryid" /> <result column="salenum" jdbcType="INTEGER" property="salenum" /> <result column="totalstocks" jdbcType="INTEGER" property="totalstocks" /> <result column="deliverymode" jdbcType="OTHER" property="deliverymode" /> <result column="deliverytemplateid" jdbcType="BIGINT" property="deliverytemplateid" /> <result column="createtime" jdbcType="TIMESTAMP" property="createtime" /> <result column="updatetime" jdbcType="TIMESTAMP" property="updatetime" /> <result column="filters" jdbcType="OTHER" property="filters" /> </resultMap> <sql id="Base_Column_List"> <!--@mbg.generated--> id, `name`, shopid, oriprice, price, remark, content, picture, imgs, `status`, categoryid, salenum, totalstocks, deliverymode, deliverytemplateid, createtime, updatetime, filters </sql> </mapper>
3.4.4 修改主启动类
@SpringBootApplication @MapperScan(basePackages = {"com.example.solr.mapper"}) public class SolrSpringbootJdApplication { public static void main(String[] args) { SpringApplication.run(SolrSpringbootJdApplication.class, args); } }
3.4.5 测试mybatisplus和solr是否可用
四、在solr里面创建jd-shop的core并配置好属性
4.1 创建jd-shop
4.2 配置分词和属性[schema文件]
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" /> <field name="name" type="text_cn" indexed="true" stored="true" required="true" multiValued="false" /> <field name="shopid" type="plong" indexed="true" stored="true" multiValued="false" /> <field name="oriprice" type="pdouble" indexed="true" stored="true" multiValued="false" /> <field name="price" type="pdouble" indexed="true" stored="true" multiValued="false" /> <field name="remark" type="text_cn" indexed="true" stored="true" multiValued="false" /> <field name="content" type="text_cn" indexed="true" stored="true" multiValued="false" /> <field name="picture" type="string" indexed="false" stored="true" multiValued="false" /> <field name="categoryid" type="plong" indexed="true" stored="true" multiValued="false" /> <field name="salenum" type="pint" indexed="true" stored="true" multiValued="false" /> <field name="totalstocks" type="pint" indexed="true" stored="true" multiValued="false" /> <field name="is_jd_express" type="pint" indexed="true" stored="true" multiValued="false" /> <field name="is_second-hand" type="pint" indexed="true" stored="true" multiValued="false" /> <field name="is_new" type="pint" indexed="true" stored="true" multiValued="false" /> <field name="is_to_pay" type="pint" indexed="true" stored="true" multiValued="false" /> <field name="keywords" type="text_cn" indexed="true" stored="true" multiValued="true" /> <copyField source="name" dest="keywords" /> <copyField source="remark" dest="keywords" /> <!--添加一个中文分词器IK--> <fieldType name="text_cn" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <tokenizer class="org.apache.lucene.analysis.ik.IKTokenizerFactory" useSmart="true"/> </analyzer> <analyzer type="query"> <tokenizer class="org.apache.lucene.analysis.ik.IKTokenizerFactory" useSmart="false"/> </analyzer> </fieldType>
覆盖到solr并重启
五、代码实现全量和增量导入
5.1 添加依赖并全量导入
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency>
ImportService接口
public interface ImportService { /*** * @Description: * @Param: 全量导入 */ public void importAll(); /*** * @Description: * @Param: 增量导入 */ public void importUpdate(); }
ImportServiceImpl
@Service @Transactional public class ImportServiceImpl implements ImportService { @Autowired private GoodsMapper goodsMapper; @Autowired private SolrClient solrClient; @Override @PostConstruct //只要IOC容器加载就运行 public void importAll() { //查询出所有上架的商品 QueryWrapper<Goods> qw=new QueryWrapper<>(); qw.eq("status",1); List<Goods> goodsList = goodsMapper.selectList(qw); List<SolrInputDocument> docs=this.createDoc(goodsList); try { solrClient.add(docs); solrClient.commit();//提交 System.out.println("数据全量同步成功:"+new Date()); }catch (Exception e){ System.out.println(e); } } /*** * @Description: 构造文档集合 * @Param: [goodsList] */ private List<SolrInputDocument> createDoc(List<Goods> goodsList) { List<SolrInputDocument> docs=new ArrayList<>(goodsList.size()); for (Goods g : goodsList) { SolrInputDocument doc=new SolrInputDocument(); doc.addField("id",g.getId().toString()); doc.addField("name",g.getName()); doc.addField("shopid",g.getShopid().longValue()); doc.addField("oriprice",g.getOriprice().doubleValue()); doc.addField("price",g.getPrice().doubleValue()); doc.addField("remark",g.getRemark()); doc.addField("content",g.getContent()); doc.addField("picture",g.getPicture()); doc.addField("categoryid",g.getCategoryid().longValue()); doc.addField("salenum",g.getSalenum().intValue()); doc.addField("totalstocks",g.getTotalstocks().intValue()); JSONObject jsonObject = JSON.parseObject(g.getFilters().toString()); doc.addField("is_jd_express",jsonObject.get("is_jd_express").equals(true)?1:0); doc.addField("is_second_hand",jsonObject.get("is_second_hand").equals(true)?1:0); doc.addField("is_new",jsonObject.get("is_new").equals(true)?1:0); doc.addField("is_to_pay",jsonObject.get("is_to_pay").equals(true)?1:0); docs.add(doc); } return docs; } @Override public void importUpdate() { } }
去控制台查看数据即可。
5.2 增量导入
修改ImportServiceImpl
@Service @Log4j2 @Transactional public class ImportServiceImpl implements ImportService { @Autowired private GoodsMapper goodsMapper; @Autowired private SolrClient solrClient; @Override @PostConstruct //只要IOC容器加载就运行 public void importAll() { //查询出所有上架的商品 QueryWrapper<Goods> qw=new QueryWrapper<>(); qw.eq("status",1); List<Goods> goodsList = goodsMapper.selectList(qw); List<SolrInputDocument> docs=this.createDoc(goodsList); try { solrClient.add(docs); solrClient.commit();//提交 log.info("数据全量同步成功:"+new Date()); }catch (Exception e){ System.out.println(e); log.warn("数据全量同步失败,{}",e); } this.lastSycnDate=new Date(); } /*** * @Description: 构造文档集合 * @Param: [goodsList] */ private List<SolrInputDocument> createDoc(List<Goods> goodsList) { List<SolrInputDocument> docs=new ArrayList<>(goodsList.size()); for (Goods g : goodsList) { SolrInputDocument doc=new SolrInputDocument(); doc.addField("id",g.getId().toString()); doc.addField("name",g.getName()); doc.addField("shopid",g.getShopid().longValue()); doc.addField("oriprice",g.getOriprice().doubleValue()); doc.addField("price",g.getPrice().doubleValue()); doc.addField("remark",g.getRemark()); doc.addField("content",g.getContent()); doc.addField("picture",g.getPicture()); doc.addField("categoryid",g.getCategoryid().longValue()); doc.addField("salenum",g.getSalenum().intValue()); doc.addField("totalstocks",g.getTotalstocks().intValue()); JSONObject jsonObject = JSON.parseObject(g.getFilters().toString()); doc.addField("is_jd_express",jsonObject.get("is_jd_express").equals(true)?1:0); doc.addField("is_second-hand",jsonObject.get("is_second-hand").equals(true)?1:0); doc.addField("is_new",jsonObject.get("is_new").equals(true)?1:0); doc.addField("is_to_pay",jsonObject.get("is_to_pay").equals(true)?1:0); docs.add(doc); } return docs; } //声明一个最后一次的导入时间 private Date lastSycnDate=new Date(); @Override @Scheduled(initialDelay = 5*1000,fixedRate = 5*1000) //延时5秒执行 5秒循环一次 public void importUpdate() { //查询出所有上架的商品 QueryWrapper<Goods> qw=new QueryWrapper<>(); qw.eq("status",1); qw.ge("updatetime",lastSycnDate); List<Goods> goodsList = goodsMapper.selectList(qw); List<SolrInputDocument> docs=this.createDoc(goodsList); try { solrClient.add(docs); solrClient.commit();//提交 lastSycnDate=new Date(); log.info("数据增量导入成功:"+lastSycnDate.toLocaleString()); }catch (Exception e){ System.out.println(e); log.warn("数据增量导入失败{}",e); } } }
修改主启动类开启定时任务
@SpringBootApplication @MapperScan(basePackages = {"com.example.solr.mapper"}) @EnableScheduling public class SolrSpringbootJdApplication { public static void main(String[] args) { SpringApplication.run(SolrSpringbootJdApplication.class, args); } }
六、编写代码实现搜索
6.1 创建DataGridView
@Data @AllArgsConstructor @NoArgsConstructor public class DataGridView { private Integer code=0; private String msg=""; private Long count; private Object data; }
6.2 创建SearchService
public interface SearchService { /*** * @Description: * @Param: [keywords, 关键字 * page, 页码 * limit, 每页显示条数 * sort, 排序字段 1 价格 2 销量 * priceScope, 价格区间 200-300 * filters] "is_jd_express":1, * "is_second-hand":1, * "is_new":1, * "is_to_pay":1, * @return: DataGridView */ DataGridView searchGoods(String keywords, Integer page, Integer limit, Integer sort, String priceScope, Map<String,Object> filters); }
6.3 创建SearchServiceImpl
@Service @Log4j2 public class SearchServiceImpl implements SearchService { @Autowired private SolrClient solrClient; /*** * @Description: * @Param: [keywords, 关键字 * page, 页码 * limit, 每页显示条数 * sort, 排序字段 1 价格升 2 价格降 3 销量升 4 销量降 * priceScope, 价格区间 200-300 * filters] "is_jd_express":1, * "is_second_hand":1, * "is_new":1, * "is_to_pay":1, * @return: DataGridView * @Author: 雷哥 * @Date: 2020/4/4 */ @Override public DataGridView searchGoods(String keywords, Integer page, Integer limit, Integer sort, String priceScope, Map<String, Object> filters) { //关键字 SolrQuery solrQuery=null; if(StringUtils.isEmpty(keywords)){ solrQuery=new SolrQuery("*:*"); }else{ solrQuery=new SolrQuery("keywords:"+keywords); } //分页处理 solrQuery.setStart((page-1)*limit); solrQuery.setRows(limit); //处理排序 switch (sort){ case 1://按价格升 solrQuery.addSort("price",SolrQuery.ORDER.asc); break; case 2://按价格降 solrQuery.addSort("price",SolrQuery.ORDER.desc); break; case 3://按销量升 solrQuery.addSort("salenum",SolrQuery.ORDER.asc); break; case 4://按销量降 solrQuery.addSort("salenum",SolrQuery.ORDER.desc); break; } //处理价格过滤 List<String> filterList=new ArrayList<>(); if(!StringUtils.isEmpty(priceScope)){ String[] split = priceScope.split("-"); if(split.length!=2){ throw new RuntimeException("传入的价格范围参数不合法"); } filterList.add("price:["+split[0]+" TO "+split[1]+"]"); } //处理其它过滤"is_jd_express":1, // * "is_second_hand":1, // * "is_new":1, // * "is_to_pay":1, if(!filters.isEmpty()){ for (Map.Entry<String, Object> entry : filters.entrySet()) { filterList.add(entry.getKey()+":"+entry.getValue()); } } //添加过滤条件 if(!filterList.isEmpty()){ solrQuery.addFilterQuery(filterList.toArray(new String[]{})); } //只要关键字不为空才设置高亮 if(!StringUtils.isEmpty(keywords)){ solrQuery.setHighlight(true); solrQuery.addHighlightField("name"); solrQuery.addHighlightField("remark"); solrQuery.setHighlightSimplePre("<font color=red>"); solrQuery.setHighlightSimplePost("</font>"); } DataGridView dataGridView=new DataGridView(); List<Goods> goods=new ArrayList<>(); try { QueryResponse query = solrClient.query(solrQuery); SolrDocumentList results = query.getResults(); dataGridView.setCount(results.getNumFound());//设置总条数 Map<String, Map<String, List<String>>> highlighting =null; if(solrQuery.getHighlight()){//如果开户高亮,就高亮查询 highlighting=query.getHighlighting(); } for (SolrDocument result : results) { Goods g=new Goods(); g.setId(Long.valueOf(result.getFieldValue("id").toString())); g.setName(result.getFieldValue("name").toString()); g.setShopid(Long.valueOf(result.getFieldValue("shopid").toString())); g.setOriprice(new BigDecimal(Double.valueOf(result.getFieldValue("oriprice").toString()))); g.setPrice(new BigDecimal(Double.valueOf(result.getFieldValue("price").toString()))); g.setRemark(result.getFieldValue("remark").toString()); g.setContent(result.getFieldValue("content").toString()); g.setPicture(result.getFieldValue("picture").toString()); g.setCategoryid(Long.valueOf(result.getFieldValue("categoryid").toString())); g.setSalenum(Integer.valueOf(result.getFieldValue("salenum").toString())); g.setTotalstocks(Integer.valueOf(result.getFieldValue("totalstocks").toString())); //处理高亮 if(solrQuery.getHighlight()){ if(null!=highlighting&&!highlighting.isEmpty()){ for (Map.Entry<String, Map<String, List<String>>> entry : highlighting.entrySet()) { String key = entry.getKey(); Map<String, List<String>> value = entry.getValue(); if(value.containsKey("name")){ String hlName=value.get("name").get(0); g.setName(hlName); } if(value.containsKey("remark")){ String hlRemark=value.get("remark").get(0); g.setRemark(hlRemark); } } } } goods.add(g); } }catch (Exception e){ log.warn("查询失败{}",e); } dataGridView.setData(goods); return dataGridView; } }
6.4 测试
@SpringBootTest class SolrSpringbootJdApplicationTests { @Autowired private SearchService searchService; @Test void contextLoads() { Map<String, Object> filters=new HashMap<>(); filters.put("is_jd_express",1);//要求京东快递 DataGridView searchGoods = searchService.searchGoods("", 1, 5, 1, "70-500", filters); List<Goods> data = (List<Goods>) searchGoods.getData(); for (Goods datum : data) { System.out.println(datum); } } }
七、Solr控制台全量和增量导入配置
7.1 清空solr里面的数据
7.2 导包
在solr安装目录下dist目录下有两个solr-dataimport**。.jar
引入mysql的驱动包
7.3 修改server/solr/jd-shop/conf/solrconfig.xml
<!--配置控制台的数据导入--> <requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler"> <lst name="defaults"> <str name="config">data-config.xml</str> </lst> </requestHandler>
7.4 创建server/solr/jd-shop/conf/data-conf.xml的文件
<?xml version="1.0" encoding="UTF-8" ?> <dataConfig> <!--配置数据源--> <dataSource type="JdbcDataSource" driver="com.mysql.jdbc.Driver" url="jdbc:mysql://127.0.0.1:3306/jd-shop?serverTimezone=UTC" user="root" password="123456"/> <document> <entity name="goods" query="select id,name,shopid,oriprice,price,remark,content,picture,categoryid,salenum,totalstocks, case JSON_EXTRACT(filters, '$.is_jd_express') WHEN true THEN 1 ELSE 0 END AS is_jd_express, case JSON_EXTRACT(filters, '$.is_second_hand') WHEN true THEN 1 ELSE 0 END AS is_second_hand, case JSON_EXTRACT(filters, '$.is_new') WHEN true THEN 1 ELSE 0 END AS is_new, case JSON_EXTRACT(filters, '$.is_to_pay') WHEN true THEN 1 ELSE 0 END AS is_to_pay FROM goods where status= 1;" > <!--查询的数据和数据库索引意义对应column 是查询的字段name 是solr索引对应的字段 <field column="fid" name="fid"/> 因为已经使用As映射好了 不用加了--> </entity> </document> </dataConfig>
7.5 在阿里云上使用docker运行一个mysql
docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
nvcat连接再把本地的数据库jd-shop上传到阿里云
7.6 把刚才修改和创建的两配置文件覆盖到solr配置
重启solr 并查看控制台
执行之后再查看数据