需求3:优化应用侧分页查询收藏接口 利用上watchTime字段,xxljob只更新上一周查看过的条目,可以减少带宽。
1.改造判断逻辑 保存watchTime,首先需要获得该用户的accountId,还要获取某一条推荐对象的旧watchTime,判断是否是今天,如果是一天那就不用更新,如果是一天就需要更新。
1 2 3 4 if (!pageRes.getContent().isEmpty()){ Date oldWatchTime = pageRes.getContent().get(0).getWatchTime(); watchTimeJudgeAndUpdate(Long.parseLong(AuthInfoUtils.getContext().getAuthInfo().getAccId()),oldWatchTime); }
这个方法按道理来说要变成异步的,看后续用多线程或者@Async解决
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private void watchTimeJudgeAndUpdate (Long accountId,Date oldWatchTime) { try { if (oldWatchTime == null || !isSameDay(oldWatchTime,new Date ())){ tbGlobalCollectEntityService.updateWatchTime(accountId); } log.info("watchTimeUpdate success , accountId : {}" ,accountId); } catch (Throwable e){ log.error("watchTimeUpdate failed , accountId : {}" ,accountId,e); } } private boolean isSameDay (Date date1, Date date2) { SimpleDateFormat sdf = new SimpleDateFormat ("yyyyMMdd" ); return sdf.format(date1).equals(sdf.format(date2)); }
这里刚开始是用了jpa的抽象仓库一个一个更新,但是mentor说效率太低了,不如直接写sql,在这个方法里面支持跟mybatis那样直接执行sql。
1 2 3 4 5 6 7 8 9 @Service public class TbGlobalCollectEntityService extends AbstractEasyEntityService <TbGlobalCollectEntity> { @Autowired private TbGlobalCollectRepository repository; public void updateWatchTime (Long accountId) { repository.updateWatchTime(accountId); } }
sql是更新所有当前accountId下,没有取消掉的推荐条目,把他们的watchTime都改为现在。
这里不需要返回当前时间,就更加说明这个判断逻辑跟前端没什么关系了,所以应该用异步。
1 2 3 4 @Modifying @Transactional @Query(value = "update TbGlobalCollectEntity p set p.watchTime=NOW() where p.status != -1 and p.accountId = :accountId") int updateWatchTime(@Param("accountId") Long accountId);
2.xxljob改造 保存了watchTime,每周执行一次的定时任务需要改成查询所有watchTime为上周的条目。
DateUtil这个工具可以找到今天0点和上周0点的Date对象,然后再用jpa进行查询,把所有的数据投入kafka里。
优化的本意是减少部分挖掘facebook的流量。但是因为在这个topic里面不止有这个任务,还有部分通讯录挖掘的任务。减少了这部分流量同时也会减少通讯录挖掘的流量,但是后者更加有价值,并不应该减少。所以按照道理来说应该分为两个topic进行操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public void collectLogUpdate (int param) { Date endDate = DateUtil.trimAndIncreDate(new Date (),0 ); Date startDate = DateUtil.trimAndDecreDate(new Date (), param); List<Specification<TbGlobalCollectEntity>> specifications = Lists.newArrayList(); specifications.add(of(TbGlobalCollectEntity.class, "status" , NEQ, GlobalSubscribeStatusEnum.DELETE.getStatus())); specifications.add(of(TbGlobalCollectEntity.class, "watchTime" , GTE, startDate)); specifications.add(of(TbGlobalCollectEntity.class, "watchTime" , LTE, endDate)); List<TbGlobalCollectEntity> records = tbGlobalCollectEntityService.findAll(specifications); if (CollectionUtils.isEmpty(records)) { return ; } for (TbGlobalCollectEntity record : records) { kafkaProducer.send(KafkaConstants.COWORK_GLOBAL_COLLECT_DETAIL_CHANGE, String.valueOf(record.getId()), String.valueOf(record.getId())); } }
需求4:查验500条数据 这个的工作量不在代码上而在于excel上,学到了一些技巧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 GET cowork_global_domain_info/_search { "query": { "bool": { " must ": [ { "exists": { "field": "recommendData" } } ] } } ,"sort": { "_script": { "script": "Math.random()", "type": "number", "order": "asc" } } ,"_source": ["recommendData"] }
需要注意的点:
随机从917w中找,这里sort要用random脚本
最好不要用滚动查询,有多少条是多少条
searchHit对象是一个大的对象DomainIndexBO,recommendData只是其中的一个字段。所以getSourceAsString包装的是DomainIndexBO,刚开始类型转换没弄明白耽误很久。
excel小技巧:在这种需要保留很多字段的时候可以用¥(dollar符)分开,因为很少有业务里面会用,防止误操作。例如在这个场景里面日志可以打印成”{recommendData.domain}¥{recomendData.other}”,然后在excel按照¥分行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public void esGet () { Script script = new Script ("Math.random()" ); ScriptSortBuilder sortBuilder = new ScriptSortBuilder (script, ScriptSortBuilder.ScriptSortType.NUMBER) .order(SortOrder.ASC); BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); boolQuery.must(QueryBuilders.existsQuery("recommendData" )); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder () .query(boolQuery) .fetchSource(new String []{"recommendData" }, null ) .sort(sortBuilder) .size(500 ); SearchHit[] searchHits = domainDataIndex.query(sourceBuilder); int i = 1 ; for (SearchHit searchHit : searchHits) { DomainIndexBO domainIndexBO = JSON.parseObject(searchHit.getSourceAsString(),DomainIndexBO.class); RecommendDataBO recommendData = domainIndexBO.getRecommendData(); StringBuilder stringBuilder = new StringBuilder (); stringBuilder.append("$" ); stringBuilder.append(recommendData.getDomain()).append("$" ); stringBuilder.append(String.join("," , recommendData.getProducts())).append("$" ); if (recommendData.getAliCategories().isEmpty()){ stringBuilder.append("null" ); } else { for (RecommendDataBO.AliCategory aliCategory : recommendData.getAliCategories()) { stringBuilder.append(aliCategory.getName()).append(":" ).append(aliCategory.getScore()).append("," ); } } stringBuilder.append("$" ).append(recommendData.getIsBizP()).append("$" ); stringBuilder.append(recommendData.getIsBizVersion()).append("$" ); stringBuilder.append(recommendData.getProductsVersion()).append("$" ); if (StringUtils.isBlank(recommendData.getAliCategoryVersion())){ stringBuilder.append("null" ); } else { stringBuilder.append(recommendData.getAliCategoryVersion()); } String result = stringBuilder.toString(); log.info("第" +i+"个:" +result); i++; } }
。。。未完待续