当前位置: 首页 > news >正文

深圳网站的网络公司wordpress跑一亿数据

深圳网站的网络公司,wordpress跑一亿数据,通过qq群可以进行友情链接交换,网站开发的未来发展我是如何在反欺诈系统中使用 Redis 缓存客户年龄信息,提升导出性能的(实战经验总结)一、背景 我在开发一个反欺诈系统的开户流水导出功能时,需要导出约 7w 条开户流水数据,每条数据包含客户号、开户日期,并…

我是如何在反欺诈系统中使用 Redis 缓存客户年龄信息,提升导出性能的(实战经验总结)


一、背景

我在开发一个反欺诈系统的开户流水导出功能时,需要导出约 7w 条开户流水数据,每条数据包含客户号、开户日期,并且要补充客户年龄字段。

年龄字段来源于客户基本信息表,数据存储在 Elasticsearch 中,字段是客户出生日期。

开发初期,我们采用一次性查询客户号的方式,但上线后发现:

大部分年龄字段为空,数据异常!

排查发现:一次性传入 7w 个客户号查询 ES,由于 index.max_result_window 默认限制为 10000,只返回了前 1w 条数据。

于是我们做了如下优化:

  • 分批查询客户信息(每批 2000 条)
  • 使用 filter 查询,不记分
  • 只查询 custNo 和 birthDate 字段
  • 使用 Java 8 并行流加快查询速度
  • 引入 Redis 缓存客户出生日期信息,设置过期时间

二、我遇到的问题

1. 客户信息查询效率低

  • 每次导出都要重新查询 ES,性能差
  • 客户出生日期是静态数据,重复查询浪费资源

2. 一次性查询客户号数据不完整

  • 一次性传入 7w 个客户号,ES 默认最多返回 1w 条数据
  • 导致年龄字段缺失,数据异常

3. 未使用缓存,重复查询浪费资源

  • 客户出生日期基本不变,每次导出都重新查 ES,浪费资源

三、我是怎么做的?

我最终采用了如下方案进行优化:

优化项说明
分批查询每次查 2000 个客户号,规避 ES 的 max_result_window 限制
使用 filter 查询不记分,提升查询效率
只查 custNo 和 birthDate 字段减少数据传输量
使用 Java 8 并行流提升分批查询效率
引入 Redis 缓存客户出生日期减少重复查询
设置缓存过期时间(如 1 天)保证数据新鲜度

四、具体实现(Java + Elasticsearch + Redis)

✅ Redis 缓存工具类(使用 Spring Data Redis):

@Component
public class RedisCache {@Autowiredprivate RedisTemplate<String, String> redisTemplate;// 设置缓存,带过期时间public void setWithExpire(String key, String value, long timeout, TimeUnit unit) {redisTemplate.opsForValue().set(key, value, timeout, unit);}// 获取缓存public String get(String key) {return redisTemplate.opsForValue().get(key);}// 批量获取缓存public List<String> multiGet(List<String> keys) {return redisTemplate.opsForValue().multiGet(keys);}
}

✅ 分批查询客户信息 + 并行流 + Redis 缓存:

@Service
public class CustomerInfoService {@Autowiredprivate RestHighLevelClient esClient;@Autowiredprivate RedisCache redisCache;private static final int BATCH_SIZE = 2000;private static final String CACHE_KEY_PREFIX = "cust_birthdate_";public Map<String, String> getCustomerBirthDates(List<String> customerNos) throws IOException {Map<String, String> result = new HashMap<>();// 去重客户号List<String> uniqueCustNos = customerNos.stream().distinct().collect(Collectors.toList());// 先查 Redis 缓存List<String> cacheKeys = uniqueCustNos.stream().map(custNo -> CACHE_KEY_PREFIX + custNo).collect(Collectors.toList());List<String> cachedValues = redisCache.multiGet(cacheKeys);Map<String, String> cachedMap = new HashMap<>();for (int i = 0; i < uniqueCustNos.size(); i++) {String custNo = uniqueCustNos.get(i);String cachedValue = cachedValues.get(i);if (cachedValue != null) {cachedMap.put(custNo, cachedValue);}}// 筛出未缓存的客户号List<String> notCached = uniqueCustNos.stream().filter(custNo -> !cachedMap.containsKey(custNo)).collect(Collectors.toList());// 分批查询 ESList<List<String>> batches = Lists.partition(notCached, BATCH_SIZE);batches.parallelStream().forEach(batch -> {try {SearchRequest searchRequest = new SearchRequest("customer_info_index");SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();sourceBuilder.query(QueryBuilders.boolQuery().filter(QueryBuilders.termsQuery("custNo", batch)));sourceBuilder.fetchSource(new String[]{"custNo", "birthDate"}, null);sourceBuilder.size(batch.size());searchRequest.source(sourceBuilder);SearchResponse response = esClient.search(searchRequest, RequestOptions.DEFAULT);for (SearchHit hit : response.getHits()) {Map<String, Object> source = hit.getSourceAsMap();String custNo = source.get("custNo").toString();String birthDate = source.get("birthDate").toString();String cacheKey = CACHE_KEY_PREFIX + custNo;// 放入结果 & 缓存result.put(custNo, birthDate);redisCache.setWithExpire(cacheKey, birthDate, 1, TimeUnit.DAYS);}} catch (IOException e) {e.printStackTrace();}});// 合并缓存和新查的数据result.putAll(cachedMap);return result;}
}

✅ 补充年龄字段逻辑:

public List<OpenAccountRecord> enrichWithAge(List<OpenAccountRecord> records) throws IOException {List<String> customerNos = records.stream().map(OpenAccountRecord::getCustNo).distinct().collect(Collectors.toList());// 查询客户出生日期(优先 Redis 缓存,未命中则查 ES)Map<String, String> birthDateMap = getCustomerBirthDates(customerNos);// 补充年龄字段for (OpenAccountRecord record : records) {String custNo = record.getCustNo();String birthDate = birthDateMap.get(custNo);if (birthDate != null) {int age = calculateAge(birthDate);record.setAge(age);}}return records;
}private int calculateAge(String birthDateStr) {LocalDate birthDate = LocalDate.parse(birthDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd"));LocalDate now = LocalDate.now();return now.getYear() - birthDate.getYear();
}

五、优化亮点总结

优化点说明
分批查询避免一次性查询超过 ES 限制
filter 查询不记分,提升性能
只查必要字段减少数据传输
并行流处理提升查询效率
Redis 缓存客户出生日期减少重复查询,支持分布式
设置缓存过期时间(1 天)保证数据新鲜度
构建映射表便于字段补充,代码结构清晰

六、遇到的难点与思考

🔍 难点一:分页没问题,导出才暴露问题

  • 分页只查 10 条客户号,ES 限制未触发
  • 导出时一次性查 7w 条客户号,才暴露数据截断问题

🔍 难点二:ES 默认限制不报错,只截断

  • ES 不会抛异常,只是返回前 1w 条数据
  • 容易造成数据丢失而不自知

🔍 难点三:缓存过期时间如何设置?

  • 客户出生日期不变,年龄每年更新一次
  • 设置缓存过期时间为 1 天,足够使用,且数据不会太旧

七、总结

这次优化让我深刻认识到:

缓存不是万能的,但合理使用缓存可以极大提升系统性能。

通过这次优化,我们解决了:

  • 年龄字段缺失问题
  • 数据完整性保障
  • 查询性能提升
  • 减少 ES 调用次数
  • 支持多节点部署下的缓存共享
  • 代码结构更清晰

如果你也在开发反欺诈、风控、数据报表等系统,遇到类似的 ES 分页、导出、数据关联问题,希望这篇文章能给你带来一些启发和参考。

http://www.dtcms.com/a/452396.html

相关文章:

  • 广州网站建设报价搭建企业网站的步骤
  • 专业外贸网站开发邯郸移动网站建设
  • 论坛网站 备案黑龙江seo关键词优化工具
  • 网站建设 海口出入东莞最新通知今天
  • vue企业门户网站模板商务网站建设联系方式
  • 邹平建设项目网站公示青岛网站制作机构
  • 宣城网站推广卢松松博客源码 wordpress博客模板
  • 网站后台文件名福田住房和建设局网站官网
  • 卖高权重网站做跳转学设计哪个专业好
  • 网络工程师面试题四川成都网站优化
  • 天津建站商城广州高端企业网站建设
  • 胶州市城乡建设局网站网站与微信结合
  • 建设企业网站管理系统目的商品列表html模板
  • 用vs2010做免费网站模板下载地址展馆设计案例
  • 哪里建设企业网站wordpress使用cdn菜单消失
  • 闲鱼网站是哪家公司做的jsp系统网站建设带源代码
  • 电子商务毕业设计设计网站建设菏泽市住房和城乡建设路网站
  • 网站制作公司 恶意门户网站 建设商 排名
  • 网站建设合同 知乎黑糖wordpress主题破解
  • 技术支持 光速东莞网站建设网络营销的五大特点
  • 百度站长工具网站认证网站设计官网
  • 景区vi设计案例北京网站设计制作关键词优化
  • 自己买服务器做网站wordpress 分享到微信 插件
  • 石家庄做网站好的网络技术有限公司广告设计与制作专业学校
  • 有关做能源的网站桂林网站开发建设
  • 手机网站建站公司硬件开发是什么专业
  • 网站建设工作室介绍范文微信自助下单小程序怎么弄
  • 想做个网站推广手机网页游戏排行榜前十名
  • 做门户网站建设多少钱docker wordpress v
  • 上网建立网站布置wordpress网页设计步骤