工作纪实51-手撸AB实验分流策略

前几天写了一篇关于哈希算法的文章,起源就是在构思AB实验平台的时候,用到了哈希,所以对其做了深入的了解
AB实验平台是一般互联网做策略、样式实验会用到的一个系统,一般开启某个实验之后,需要对线上流量进行分流:客户端->实验平台->策略平台->应用服务,大概是这个链路

场景

线上流量策略分流,需要对不同人群做策略实验,最终效果好的一组需要推全到100%,在未推全之前,100%的流量会被分到原有流量+几个实验组;
比如我有一个实验:样式迭代,产品希望60%的流量走线上逻辑,剩下的40%,均分到4个实验组,这样可以细致的比对样式的效果,当然,如果一个用户命中了实验组A,那么他后续的行为,在实验组不调整的情况下,需要一直保持(有的人说希望调整了也保持,但是真的了解AB分流逻辑之后,真挺难的);
其实我们有自己的AB平台,但是我在想如果让我去实现,我会怎么做,便有了这一篇文章;

考虑的问题

1.如何保证一个用户对实验命中唯一性

在实验组不调整的情况下,PM希望用户分流的结果始终保持一致;
【策略】:hash算法,通过对imei进行哈希运算得到int的哈希值即可,可以加一个时间戳(实验修改时间),来控制用户的imei命中变化

2.如何按比例分流

【策略】取模运算,构建一个长度为100的bucket,然后通过对imei的哈希值运算结果对100取模,即可得到0-100的数,从而去命中数据区间,挑选实验组即可;由于哈希算法的特性,只要imei不变,时间戳(因子)不变,计算得到的哈希值是永远不会变的,所以取模结果,命中实验的结果也是不变的;

比如我的case是线上流量60%,其他实验组10%,10%,10%,10%,则可以构建一个数据区间:【0,60,70,80,90,100】
在这里插入图片描述

实战

代码

@Data
public class TrafficDistributor {private String id;// 实验idprivate String name;private double isolation;// 线上流量private List<Experiment> experiments;// 实验组private Table<String, String, Set<String>> whiteTable = HashBasedTable.create();private static Date updateTime = new Date(1719844946L);//2024/7/1 22:42:26public TrafficDistributor(String id, String name, double isolation, List<Experiment> experiments, Table<String, String, Set<String>> whiteTable) {this.id = id;this.name = name;this.isolation = isolation;this.experiments = experiments;this.whiteTable = whiteTable;}public static void main(String[] args) {// 实验idString id = "new_style";// 1.初始化白名单==》正式环境从db中拿出来初始化Table<String, String, Set<String>> white = HashBasedTable.create();white.put(id, "00", Sets.newHashSetWithExpectedSize(0));white.put(id, "01", Set.of("whitelist_imei_1", "whitelist_imei_2"));white.put(id, "02", Set.of("whitelist_imei_3", "whitelist_imei_4"));white.put(id, "11", Set.of("whitelist_imei_5", "whitelist_imei_6"));white.put(id, "12", Set.of("whitelist_imei_7", "whitelist_imei_8"));// 2.初始化实验组Experiment experiment1 = new Experiment("01", "对照组01", 10);Experiment experiment2 = new Experiment("02", "对照组02", 10);Experiment experiment3 = new Experiment("11", "实验组01", 10);Experiment experiment4 = new Experiment("12", "实验组02", 10);List<Experiment> experiments = List.of(experiment1, experiment2, experiment3, experiment4);// 3.初始化分流器TrafficDistributor distributor = new TrafficDistributor(id, "新样式实验", 60, experiments, white);// 4.模拟分流for (int times = 0; times < 100; times++) {int index = 1, size = 100;Map<String, Integer> result = Maps.newHashMap();List<Long> cost = Lists.newArrayListWithCapacity(size);while (index <= size) {String imei = RandomStringUtils.randomAlphanumeric(64);long start = System.currentTimeMillis();// 核心分流Experiment experiment = distributor.allocate(id, imei);if (experiment != null) {// 实验组result.compute(experiment.getId(), (eid, count) -> (count == null) ? 1 : count + 1);} else {// 线上int value = result.getOrDefault("00", 0);result.put("00", value + 1);}cost.add(System.currentTimeMillis() - start);index++;}System.out.println("耗时:" + cost.stream().mapToLong(Long::longValue).sum() + ";结果:" + JSON.toJSONString(result));}}/*** 流量分配: 白名单 - 实验组 - 线上流量*/public Experiment allocate(String id, String imei) {Experiment whiteListShot = whiteListShot(id, imei);if (whiteListShot != null) {return whiteListShot;}List<Double> weights = experiments.stream().map(Experiment::getWeight).collect(Collectors.toList());int groupId = distributeTraffic(weights, imei);if (groupId < 0) {// 线上流量return null;}// 实验组流量return experiments.get(groupId);}/*** 根据每个实验组的权重配比,判断最终流量应该分配到哪个实验组。** @param weights 每个实验组的权重值数组。* @param imei    imei* @return 分配流量的实验组索引*/public int distributeTraffic(List<Double> weights, String imei) {if (CollectionUtils.isEmpty(weights)) {return -1;}double totalWeight = 100;// 总权重100%double testWeight = weights.stream().mapToDouble(Double::doubleValue).sum();// 实验组总权重if (totalWeight != (isolation + testWeight)) {throw new IllegalArgumentException("实验组和对照组流量分配存在问题");}// imei+时间戳(因子)生成hashint hash = HashUtils.hashcode(imei + updateTime.getTime());return bucketShot(weights, hash % totalWeight);}/*** 哈希值进行取模定位后,命中的实验*/public int bucketShot(List<Double> weights, double bucketIndex) {List<Double> range = Lists.newArrayListWithCapacity(weights.size() + 1);range.add(isolation);double pre = range.get(0);for (double weight : weights) {range.add(pre + weight);pre = pre + weight;}for (int i = 0; i < range.size(); i++) {if (bucketIndex <= range.get(i)) {return i - 1;}}throw new IllegalArgumentException("实验组和对照组流量分配存在问题");}/*** 白名单命中** @param id   实验id* @param imei imei* @return 实验组*/public Experiment whiteListShot(String id, String imei) {assert whiteTable != null && !whiteTable.isEmpty();if (!whiteTable.containsRow(id)) {throw new IllegalArgumentException("实验id=" + id + "不存在");}Map<String, Set<String>> experimentData = whiteTable.row(id);for (Map.Entry<String, Set<String>> entry : experimentData.entrySet()) {Set<String> values = entry.getValue();if (!CollectionUtils.isEmpty(values) && values.contains(imei)) {String key = entry.getKey();return experiments.stream().filter(test -> test.getId().equals(key)).findFirst().orElse(null);}}return null;}// 其他方法保持不变@Data@AllArgsConstructorstatic class Experiment {private String id;private String name;private double weight;}
public class HashUtils {/*** hashCode方法*/public static int hashcode(Object obj) {final int p = 16777619;int hash = (int) 2166136261L;String str = obj.toString();for (int i = 0; i < str.length(); i++)hash = (hash ^ str.charAt(i)) * p;hash += hash << 13;hash ^= hash >> 7;hash += hash << 3;hash ^= hash >> 17;hash += hash << 5;if (hash < 0)hash = Math.abs(hash);return hash;}
}

分析

耗时:34;结果:{"11":11,"00":61,"01":7,"12":9,"02":12}
耗时:4;结果:{"11":8,"00":61,"12":4,"01":9,"02":18}
耗时:2;结果:{"11":9,"00":60,"01":10,"12":7,"02":14}
耗时:2;结果:{"11":11,"00":54,"01":10,"12":14,"02":11}
耗时:1;结果:{"11":9,"00":65,"12":12,"01":8,"02":6}
耗时:3;结果:{"11":9,"00":61,"01":6,"12":12,"02":12}
耗时:2;结果:{"11":9,"00":56,"12":8,"01":17,"02":10}
耗时:2;结果:{"11":7,"00":61,"12":7,"01":10,"02":15}
耗时:1;结果:{"11":8,"00":58,"01":13,"12":4,"02":17}
耗时:0;结果:{"11":5,"00":72,"01":9,"12":5,"02":9}
耗时:0;结果:{"11":2,"00":70,"12":14,"01":8,"02":6}
耗时:2;结果:{"11":7,"00":63,"12":10,"01":10,"02":10}
耗时:0;结果:{"11":8,"00":60,"12":11,"01":10,"02":11}
耗时:1;结果:{"11":9,"00":60,"12":11,"01":13,"02":7}
耗时:0;结果:{"11":12,"00":71,"12":5,"01":9,"02":3}
耗时:1;结果:{"11":12,"00":57,"01":11,"12":11,"02":9}
耗时:0;结果:{"11":8,"00":62,"01":14,"12":7,"02":9}
耗时:1;结果:{"11":10,"00":64,"12":6,"01":9,"02":11}
耗时:2;结果:{"11":5,"00":73,"12":7,"01":9,"02":6}
耗时:0;结果:{"11":9,"00":68,"01":6,"12":9,"02":8}
耗时:1;结果:{"11":12,"00":63,"01":10,"12":4,"02":11}
耗时:1;结果:{"11":15,"00":59,"01":8,"12":9,"02":9}
耗时:0;结果:{"11":10,"00":66,"01":8,"12":6,"02":10}
耗时:1;结果:{"11":8,"00":64,"01":10,"12":6,"02":12}
耗时:2;结果:{"11":11,"00":63,"01":8,"12":8,"02":10}
耗时:1;结果:{"11":5,"00":66,"12":9,"01":12,"02":8}
耗时:3;结果:{"11":8,"00":67,"12":10,"01":9,"02":6}
耗时:1;结果:{"11":9,"00":54,"12":16,"01":7,"02":14}
耗时:0;结果:{"11":11,"00":63,"12":5,"01":11,"02":10}
耗时:1;结果:{"11":10,"00":59,"01":12,"12":8,"02":11}
耗时:1;结果:{"11":12,"00":62,"12":11,"01":8,"02":7}
耗时:0;结果:{"11":8,"00":59,"12":8,"01":13,"02":12}
耗时:1;结果:{"11":12,"00":51,"12":11,"01":15,"02":11}
耗时:1;结果:{"11":1,"00":72,"01":10,"12":8,"02":9}
耗时:1;结果:{"11":8,"00":55,"01":18,"12":9,"02":10}
耗时:0;结果:{"11":6,"00":54,"01":22,"12":5,"02":13}
耗时:1;结果:{"11":9,"00":58,"12":11,"01":11,"02":11}
耗时:1;结果:{"11":15,"00":57,"12":12,"01":3,"02":13}
耗时:1;结果:{"11":6,"00":66,"12":10,"01":11,"02":7}
耗时:0;结果:{"11":13,"00":61,"12":12,"01":8,"02":6}
耗时:0;结果:{"11":8,"00":61,"12":11,"01":10,"02":10}
耗时:0;结果:{"11":10,"00":57,"01":10,"12":12,"02":11}
耗时:1;结果:{"11":6,"00":62,"12":12,"01":11,"02":9}
耗时:5;结果:{"11":9,"00":64,"12":8,"01":10,"02":9}
耗时:0;结果:{"11":15,"00":54,"12":8,"01":9,"02":14}
耗时:0;结果:{"11":12,"00":62,"01":8,"12":10,"02":8}
耗时:0;结果:{"11":9,"00":63,"12":6,"01":12,"02":10}
耗时:0;结果:{"11":9,"00":59,"01":10,"12":9,"02":13}
耗时:1;结果:{"11":10,"00":58,"01":7,"12":14,"02":11}
耗时:1;结果:{"11":9,"00":73,"01":8,"12":2,"02":8}
耗时:0;结果:{"11":14,"00":62,"12":7,"01":10,"02":7}
耗时:1;结果:{"11":12,"00":55,"12":10,"01":12,"02":11}
耗时:0;结果:{"11":5,"00":59,"01":7,"12":17,"02":12}
耗时:0;结果:{"11":10,"00":59,"12":7,"01":10,"02":14}
耗时:1;结果:{"11":11,"00":54,"01":17,"12":8,"02":10}
耗时:0;结果:{"11":8,"00":65,"12":8,"01":9,"02":10}
耗时:1;结果:{"11":13,"00":61,"12":8,"01":9,"02":9}
耗时:1;结果:{"11":6,"00":67,"01":10,"12":11,"02":6}
耗时:1;结果:{"11":7,"00":61,"12":8,"01":10,"02":14}
耗时:0;结果:{"11":6,"00":63,"12":8,"01":10,"02":13}
耗时:0;结果:{"11":9,"00":62,"12":9,"01":9,"02":11}
耗时:1;结果:{"11":5,"00":65,"01":8,"12":11,"02":11}
耗时:0;结果:{"11":11,"00":52,"12":9,"01":15,"02":13}
耗时:0;结果:{"11":14,"00":66,"01":4,"12":7,"02":9}
耗时:0;结果:{"11":12,"00":54,"12":8,"01":8,"02":18}
耗时:1;结果:{"11":9,"00":64,"12":8,"01":10,"02":9}
耗时:1;结果:{"11":9,"00":65,"01":3,"12":11,"02":12}
耗时:0;结果:{"11":5,"00":67,"01":7,"12":12,"02":9}
耗时:0;结果:{"11":13,"00":50,"01":12,"12":11,"02":14}
耗时:1;结果:{"11":18,"00":55,"12":7,"01":10,"02":10}
耗时:0;结果:{"11":5,"00":64,"01":12,"12":5,"02":14}
耗时:0;结果:{"11":10,"00":68,"12":6,"01":7,"02":9}
耗时:1;结果:{"11":9,"00":71,"12":4,"01":6,"02":10}
耗时:0;结果:{"11":8,"00":62,"12":9,"01":9,"02":12}
耗时:0;结果:{"11":10,"00":64,"12":8,"01":9,"02":9}
耗时:0;结果:{"11":9,"00":57,"12":10,"01":9,"02":15}
耗时:0;结果:{"11":10,"00":60,"12":13,"01":9,"02":8}
耗时:0;结果:{"11":12,"00":66,"01":5,"12":9,"02":8}
耗时:0;结果:{"11":6,"00":58,"01":11,"12":13,"02":12}
耗时:1;结果:{"11":10,"00":62,"01":12,"12":9,"02":7}
耗时:1;结果:{"11":7,"00":66,"12":11,"01":7,"02":9}
耗时:0;结果:{"11":10,"00":63,"12":9,"01":11,"02":7}
耗时:1;结果:{"11":8,"00":61,"12":10,"01":12,"02":9}
耗时:0;结果:{"11":8,"00":62,"12":6,"01":10,"02":14}
耗时:0;结果:{"11":7,"00":68,"12":8,"01":11,"02":6}
耗时:0;结果:{"11":11,"00":54,"01":11,"12":16,"02":8}
耗时:0;结果:{"11":7,"00":68,"01":10,"12":6,"02":9}
耗时:0;结果:{"11":7,"00":65,"12":7,"01":8,"02":13}
耗时:0;结果:{"11":8,"00":69,"01":8,"12":5,"02":10}
耗时:0;结果:{"11":15,"00":60,"01":6,"12":11,"02":8}
耗时:0;结果:{"11":9,"00":70,"01":6,"12":7,"02":8}
耗时:0;结果:{"11":14,"00":62,"12":7,"01":10,"02":7}
耗时:0;结果:{"11":11,"00":64,"12":7,"01":7,"02":11}
耗时:1;结果:{"11":6,"00":56,"12":14,"01":10,"02":14}
耗时:0;结果:{"11":7,"00":64,"12":8,"01":11,"02":10}
耗时:1;结果:{"11":14,"00":65,"12":4,"01":10,"02":7}
耗时:0;结果:{"11":13,"00":59,"12":7,"01":13,"02":8}
耗时:1;结果:{"11":5,"00":65,"12":8,"01":14,"02":8}
耗时:1;结果:{"11":12,"00":54,"01":11,"12":10,"02":13}
耗时:1;结果:{"11":10,"00":56,"12":11,"01":11,"02":12}
Process finished with exit code 0
  • 我手写的hashCode方法,包括随机字符串生成的imei仍然存在实验组分类偏向的情况,中间尝试过使用一致性哈希解决偏移,但是又解决不了加权按比例分配的问题,不知道各位同仁有没有什么好的建议;我怀疑是随机字符串的偏向性问题,后面看看有没有办法解决
  • 取模算法是个宝藏,既可以精准定位,也可以利用随机性,来做区间命中
  • updateTime它是个变化因子,如果实验有新增实验组或者流量调整,可以利用它来控制imei实验组变化

参考资料

  • https://zhuanlan.zhihu.com/p/404232432
  • https://blog.csdn.net/SmartCodeTech/article/details/113698568?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ECtr-2-113698568-blog-131205090.235%5Ev43%5Epc_blog_bottom_relevance_base8&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ECtr-2-113698568-blog-131205090.235%5Ev43%5Epc_blog_bottom_relevance_base8&utm_relevant_index=5

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/862550.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

lvs+上一章的内容

书接上回这次加了个keepalived 一、集群与分布式 1.1 集群介绍 **集群&#xff08;Cluster&#xff09;**是将多台计算机组合成一个系统&#xff0c;以解决特定问题的计算机集合。集群系统可以分为以下三种类型&#xff1a; **LB&#xff08;Load Balancing&#xff0c;负载…

创业思维和商业模式的区别,从0到1:构建到突破,专业新零售全案策划

在如今快速变化的市场环境中&#xff0c;创业思维和商业模式的重要性日益凸显。创业思维侧重于创新、冒险和解决问题的能力&#xff0c;而商业模式则关注企业如何创造并获取价值。将这两者有效地融合&#xff0c;不仅可以增强企业的竞争力&#xff0c;还可以帮助企业在市场中取…

希尔排序的实现

引言 排序在我们生活中十分常见&#xff0c;无论是购物软件中的商品推荐还是名次、排名都与排序算法息息相关。希尔排序是排序中较快的一种&#xff0c;而希尔排序实现的基础是插入排序。 排序的实现 插入排序&#xff08;以升序为例&#xff09; 插入排序的原理是从第二个数…

Springboot多模块项目从0构建打包运行

今天复习了一下Springboot的多模块的构建&#xff0c;其实一直以来都对单体项目使用多模块感到不太理解&#xff0c;不知道到底有什么样的优势&#xff0c;目前切身体会到的优势就是确实可以让依赖的划分更加清晰&#xff08;每个模块下的pom文件只引入该模块需要的依赖&#x…

Docker容器 || MySQL容器时间与宿主机同步

网上说的有好几种方式。 本人认为最实用的就是这个&#xff1a; docker exec -it idste_mysql ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime诸如其它的还有&#xff1a; 1、启动的时候直接挂载&#xff0c;这个有效 docker run --name your_container_name -v …

力扣第215题“数组中的第K个最大元素”

在本篇文章中&#xff0c;我们将详细解读力扣第215题“数组中的第K个最大元素”。通过学习本篇文章&#xff0c;读者将掌握如何使用快速选择算法和堆排序来解决这一问题&#xff0c;并了解相关的复杂度分析和模拟面试问答。每种方法都将配以详细的解释&#xff0c;以便于理解。…

wsl ubuntu 安装Anaconda3步骤

如何在Ubuntu上安装Anaconda3呢?本章记录整个安装过程。 1、下载脚本 https://mirrors.bfsu.edu.cn/anaconda/archive/Anaconda3-2023.09-0-Linux-x86_64.sh 下载之后,将脚本上传到Ubuntu里。 2、安装脚本 bash Anaconda3-2021.11-Linux-x86_64.sh根据提示进行安装,提示输…

maven 打包执行配置(对maven引用的包或者丢进去的包都包含在里面)打成jar包

一 、springboot jar包 maven的pom文件 1 在resources下放了一些文件想打进去jar包 2 在lib下放了其他稀奇古怪jar包文件想打进去jar包 编写如下引入jar <build><!-- 打包名称 --><finalName>${project.artifactId}</finalName><resources><…

visual studio 2022配置和使用jsoncpp

下载 jsoncpp下载位置&#xff1a; GitHub - open-source-parsers/jsoncpp: A C library for interacting with JSON. 编译库 1、下载完成之后解压 2、在解压文件的makefiles文件下有个vs71&#xff0c;在vs71中有visual studio项目&#xff0c;不过这里的项目是visual stud…

凸优化相关文章汇总

深度学习/机器学习入门基础数学知识整理&#xff08;三&#xff09;&#xff1a;凸优化&#xff0c;Hessian&#xff0c;牛顿法_深度学习和凸优化-CSDN博客 深度学习/机器学习入门基础数学知识整理&#xff08;四&#xff09;&#xff1a;拟牛顿法、BFGS、L-BFGS、DFP、共轭梯…

NSI66x1B:单通道增强隔离智能栅极驱动器

Single-Channel Isolated Smart Gate Driver 单通道隔离智能门驱动器 参考 Novosense-NSi66x1A_Datasheet_Rev1.x_EN.pdf Product Overview NSI66x1B是一款单通道增强隔离智能栅极驱动器,可在许多应用中驱动igbt和SiC mosfet。它可以输出和吸收10A的峰值电流。系统鲁棒性由…

Leetcode 501:二叉搜索树中的众数

给你一个含重复值的二叉搜索树&#xff08;BST&#xff09;的根节点 root &#xff0c;找出并返回 BST 中的所有 众数&#xff08;即&#xff0c;出现频率最高的元素&#xff09;。 如果树中有不止一个众数&#xff0c;可以按 任意顺序 返回。 假定 BST 满足如下定义&#xf…

如何在服务器中安装anaconda

文章目录 Step1: 下载 Anaconda方法1&#xff1a;下载好sh文件上传到服务器安装方法2&#xff1a;在线下载 Step2: 安装AnacondaStep3: 配置环境变量Step 4: 激活AnacondaStep4: 检验安装是否成功 Step1: 下载 Anaconda 方法1&#xff1a;下载好sh文件上传到服务器安装 在浏览…

Typescript 【实用教程】(2024最新版)含类型声明,类型断言,函数,接口,泛型等

简介 TypeScript 是 JavaScript 的超集&#xff0c;是 JavaScript&#xff08;弱类型语言&#xff09; 的强类型版本。 拥有类型机制文件后缀 .tsTypescript type ES6TypeScript 和 JavaScript 的关系类似 less 和 css 的关系TypeScript对 JavaScript 添加了一些扩展&#x…

入门网络安全工程师要学习哪些内容

大家都知道网络安全行业很火&#xff0c;这个行业因为国家政策趋势正在大力发展&#xff0c;大有可为!但很多人对网络安全工程师还是不了解&#xff0c;不知道网络安全工程师需要学什么?知了堂小编总结出以下要点。 网络安全工程师是一个概称&#xff0c;学习的东西很多&…

数据仓库面试题(三)

1. 简述什么是ER模型 &#xff1f; ER模型&#xff08;Entity-Relationship Model&#xff09;&#xff0c;即实体-关系模型&#xff0c;是一种用于表示实体之间关系的图形化数据库设计方法。它由Peter Chen在1976年提出&#xff0c;广泛应用于数据库设计、系统分析和软件工程…

Spring Boot应用知识梳理

一.简介 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的工具。它简化了基于 Spring 的应用程序的配置和部署过程&#xff0c;提供了一种快速、便捷的方式来构建独立的、生产级别的 Spring 应用程序。 Spring Boot 的一些主要优点包括&#xff1a; 1. 简化配置…

js实现数据去重合并

应用场景&#xff0c;一个list&#xff0c;包含已经选择的数据和未选择的数据&#xff0c;新增数据到已选择的数据中。 要考虑到二次选择的数据和已经选择的数据有重复的可能&#xff0c;所以&#xff0c;第一步先从二次选择的数据中进行去重&#xff0c;然后再将两个list进行数…

《互联网政务应用安全管理规定》自2024年7月1日起,关于日志存储至少保存一年说明

学习目标&#xff1a;《互联网政务应用安全管理规定》第二十条 机关事业单位应当留存互联网政务应用相关的防火墙、主机等设备的运行日志&#xff0c;以及应用系统的访问日志、数据库的操作日志&#xff0c;留存时间不少于1年&#xff0c;并定期对日志进行备份&#xff0c;确保…

DBeaver通过jdbc方式连接ES(免证书)

前言 之前其实已经分享过DBeaver连接ES,为什么重新分享一篇,用过的肯定知道,之前那种方式需要ES服务的服务器上装证书,免费证书只能用一个月。这次分享的就是解决这个时间限制问题,但是需要用一个自己开发的jar,而且暂未上到maven的中心库。 一、先看效果 证书方式 自研…