跳转到内容

小天管理

管理员
  • 注册日期

  • 最后上线

小天管理 发表的所有内容

  1. 升级到 iOS18 后,Google Authenticator 不能启动,国区 App Store 也不支持 ga 更新,使用 ga 的,升级前注意备份数据哈
  2. 现在的业务在用代理。 一直用的快代理,现在感觉有点贵。 现在我的配置是 [隧道代理,每次请求换 ip ,每秒 12 次上限,带宽峰值是 8.0Mb/s ] 这个配置每小时的价格是 17 元,一天的费用大概 400 元。 感觉有点贵了。 于是搜了一下,发现有的网站,同样配置差不多 250 元一周。折合不到 40 一天。 竟然差了 10 倍! 我这种配置,一般啥价格啊,低价的会不会有坑? 快代理是不是贵了点?
  3. 安卓 13 ,已 root ,照理说 MT 管理器获取读写权限,往 system cacerts 里面复制文件就可以了。 但是很奇怪现在文件复制不进去,用 magisk 插件就算复制进去了,文件系统里面能看到,系统还是看不到。。。 感觉非常诡异。 有没有好的办法?
  4. 128g 盘,安装 pve ,估计剩余空间 24g ,然后按照群晖。请问群晖镜像最少能占据多大的空间? 如果空间真不够不行就另买 ssd 盘了。
  5. 如题。 品牌的动辄上万,太贵了。淘宝眼花缭乱,不知道怎么选。 请问有推荐吗?
  6. 我们是做安全产品的厂商,最近一个客户端程序,有 Androd 和 Windows 两个平台。 架构师原先是做 Java 的,负责 Android 端的开发,我负责 Windows 端开发。 因为需要和其他程序通信,所以他选定的是 socket ,用于本地进程的进程间通信,这里没有任何跨操作系统和跨设备的通讯需求。 我在 Windows 端用的是命名管道,现在强压我要改成 Socket 。 改 Socket 是没什么难度,但是被强制往自己的代码里糊屎非常难受。 Socket 他还没做任何权限认证,也就是本地的任何线程,不管是其他合法进程还是木马病毒,都可以给它的 Socket 端口发消息,只要格式正确它都会执行。 请问下,IPC 用 Socket 的多吗?是纯属他太菜,还是我水平不足??
  7. docker info: Debug Mode: true Registry Mirrors: https://mirror.iscas.ac.cn/ https://docker.nju.edu.cn/ 上面两个地址都可以 ping 通 docker pull mysql: Using default tag: latest Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) 我到底错哪儿了!我把 GPT 都活剐了。。。
  8. 我家里有一台 M2 Mac Mini 和一台 Windows PC ,共用同一套显示器、键盘、鼠标,连接方式如图: 连接图 目前 Mac Mini 使用完全无异常,但是切换到 Windows PC 的状态下,待机或者打游戏的时候,偶尔会黑屏一下子,如果 Windows PC 直连显示器则没有这个问题。你知道 V 友有没有遇到这类问题,你们多台设备是怎么共用同一套显示器和键鼠的呢,有遇到过黑屏的问题吗?
  9. Java 后端 5 年,想准备 1 年左右跳到杭州。 对工作的期待:可适当加班,但不要太卷,不要无效加班,技术氛围好一些。不介意转语言。 有哪些好公司或好项目组推荐呢?
  10. 2025 年微软中国校园招聘正式开启! 欢迎各位应届毕业生投递,校园招聘系统会根据你的简历匹配合适的岗位,收到面试之后请留意面试要求。 想内推加入微软的同学欢迎发送简历到:wulo#microsoft.com (记得替换 # 成 @;标题请注明:校招,并附上你希望应聘岗位的 ID ,如:校招 - 1743227 ) 毕业时间 2024 年 9 月 - 2025 年 8 月的海内外应届毕业生(本硕博)开放岗位 微软亚洲研究院 MSRA Microsoft Research Asia (MSR Asia, or MSRA) Researcher |北京/上海| 1743227 微软 MCAPS Microsoft Customer and Partner Solutions Account Executive - MBA |北京/上海 |(此职位面向全日制 MBA 同学)| 1770891 Solution Area Specialist - MBA |上海/深圳 |(此职位面向全日制 MBA 同学)| 1770893 Cloud Solution Architect |北京/上海/深圳 | 1771417 Technical Specialist |北京/上海/深圳| 1770896 Solution Area Specialist |北京/上海| 1770892 Account Executive |北京/上海| 1770936 Cloud Solution Architect |香港| 1770887 Technical Specialist |香港| 1770889 Account Tech Strategist |台北| 1770879 Technical Specialist |台北| 1770880
  11. 个人从 iPhone 15 PM 换到 iPhone 16 Pro ,目前非常满意,尤其是对 16 Pro 的续航非常赞,家里两台 iPhone 16 Pro 都明显感到续航大幅度提升,有种 3 年前使用 13 PM 的感觉,看了下实际电池使用时间,每天重度使用 11 小时才勉强用掉 100% 电池容量: 个人总结了三个原因: 1. iOS 17 太垃圾,导致 15 PM 续航严重不够用,充电时间明显多于之前的 13 PM 2. 上一台 iPhone 15 PM 用的是常熟新普电池,才冲了 300 次就衰减到了 89%,妥妥的劣质产品,新的 16 Pro 换回了惠州德赛。 3. iOS 18 新的调度策略也大幅优化了 CPU 电池消耗,整机用下来非常凉爽,很少出现 15 PM 上使用 5G 看视频 20 分钟就开始烫手的问题。 一方面靠软件,一方面靠硬件,这代很有可能成为 13 香之后又一个钉子户产品,至少在 AI 出来之前。
  12. 作为一名程序员,长久以来对于穿搭非常苦恼,平时身边的同事经常也有这样的困惑。 所以和一个很有穿衣品味的朋友一起做了一个穿搭的产品,但目前还没有上线,先试试效果。 所以如果你也在这方面有困惑,可以留下你的年龄、身高、体重、肤色(黑白、冷暖)、目标季节等;另外如果你有偏好的话还可以留下你想要的风格;如果有其他特征的话也可以留下,比如大肚腩、翘屁股。 我会根据产品给你建议🌺 注意:只会给你穿搭建议,不会给你衣服的品牌、购买链接等具体指向
  13. 截止到本貼發出時,已無法使用 hostname 方式在我本地訪問到以下 DOH 服務,並且通過 17ce 驗證同樣的 hostname 在其他地方也是一樣無法訪問,這似乎是開始大規模屏蔽 DOH 的象徵。 目前已測得無法訪問的有: dns.quad9.net dns11.quad9.net dns.cloudflare-dns.com dns.opendns.com one.one.one.one dns.google 附圖: 這是 17ce 的結果: 這是我本地的結果: 提醒大家若有在使用 DOH 服務解析域名的人,請儘快切換到以 IP 位址方式方式來訪問服務,或將相應請求通過代理傳送,以避免正常使用受到影響。
  14. 图片请点击:https://smms.app/image/Ybc5FU9fTJGsBEo uBlock Origin 拦截不到搜索结果的广告。(尝试了 Adblock plue 也拦截不到)。
  15. summer-trie 项目地址 github https://github.com/chitucao/summer-trie.git gitee https://gitee.com/chitucao/summer-trie.git 介绍 ​ 这是一个节点支持任意数据类型的前缀树,适用于大量列表数据的索引和压缩,不同于有限字符集前缀树实现(每个节点表达的状态是同一类型),主要是设计思想是将数据中多个不同类型的字段作为节点,组合成一颗前缀树,提高这些字段的检索性能; ​ 目前是用于同程旅行盲盒机票、火车票的本地资源预筛选、数据分析以及校验场景下的结果缓存; ​ 如果使用的过程中发现有 bug ,或者希望添加额外的功能,欢迎提交 PR; 适用于以下场景 索引,大量列表数据场景下建立前缀树索引,提高检索性能; 数据压缩,支持将列表数据转换成树结构,配合字段值字典,既压缩了数据,也提高了查询性能; 关键功能和特性 比较通用和易用,只需要编写少量的代码,就可以将某个数据的多个字段组合成前缀树; 支持多种方式的增删改查; 查询条件支持 EQUAL 、BETWEEN 、GTE 、LTE 、IN 、NOT_IN (可以扩展),得益于树结构,等值查询复杂度可以支持到 O(1),范围查询可以支持到 O(logn),不仅仅是前缀匹配,也可以支持后续条件匹配; 支持简单的聚合查询(可以扩展),例如 MIN ,MAX ,时间复杂度可以达到 O(logn); 树节点不存储实际字段值,而是由一个全局的字典维护字段值,树节点存储的是字段对应的字典索引,可以压缩数据,提高查询性能; 支持序列化和反序列化,适用于通信和数据 dump 分析; 几种核心的查询方式 按层查询,可以查询某一层的数据,典型的应用场景是从首层到底层依次查询情况; 原始数据查询,属于按层查询的特殊情况,查询的是叶子节点,并且叶子节点存储的是原始数据的情况; 树结构查询,指定要查询的多个索引字段,并将查询结果组合成一颗新树返回,支持聚合; 列表结构查询,列表是数据最常用的展示方式,查询过程同树结构查询,不过会将树结构平铺成列表返回; 字典值查询,字典维护了某个字段的所有有效值,当查询时不知道如何入手时,可以从字典值范围内选取; 核心概念 节点( Node ) 节点分为根节点、树枝节点、叶子节点,所有的节点都不存实际的字段值,而是存储 number 类型的字典 key ; 节点可以存储原始数据的某个字段,也可以存储多个字段的组合和映射(如成对出现的日期范围); 叶子节点也可以不存储原始数据,适用于树中的字段已经能够满足查询条件的情况,比如一个索引不够想多做几个辅助查询; 节点的类型目前有两种,treeMap 和 hashMap ,如果想做范围和比较查询,例如价格,金额,日期等,就用 treeMap ,如果字段是枚举类型,只用到等值、多值查询,用 hashMap 足够,其次是增删改性能的差别; 字典( Dict ) 前缀树后续层级的节点中,同一个字段值可能会出现多次,如果直接将重复的值存储在树节点上,会比较浪费空间,所以想到为每个字段建立一个全局唯一的映射关系,也就是字典,字典的 key 对应一个 number 类型的 id ,字典的 value 对应实际的值,树节点上只需要存储字典 key 就可以了,可以节省空间; 这个映射关系主要分为两类,一种是类数字类型,比如字段是日期,金额,数字编号等,可以唯一转换成一个 number 类型的字典 key ,这样做的好处是可以做范围查询,另一种是数据本身无法对应这种数字类型的 id ,是由字典去分配一个自增 id ,这种情况下这个字段是不支持范围查询的; 所以树节点上存储的实际上就是字典 key ,是 number 类型的,只要是 number 的子类就行,如果字典范围比较小,可以尽量映射成范围较小的数据结构洁身空间; 选用 number 类型的另外一个好处是一般支持 comparable 接口,这样节点就可以使用 sortedMap ,比如 treeMap ,在例如金额的范围,比较,聚合查询的时候更有优势,对比 hashMap ,可以降低时间复杂度; 字典是和字段绑定的,并且是支持复用的,如果两棵前缀树用到了同一个字段,用同一个字典也行,可以节省空间; 属性( Property ) 属性描述了选取数据实体的哪个字段作为一个树节点,并指定了这个字段值和字典 key 的映射关系; 属性的类型目前有两种,一种是 simpleProperty ,适用于枚举类型,不需要比较和范围查询,另一种 CustomProperty ,可以手动指定和字典 key 的映射关系,映射成一个数字,可以支持范围和比较查询; 配置( Configuration ) 配置描述了字典树的建立,有哪些字段,字段的顺序关系,是否需要快速删除等等; 快速开始 新建前缀树 1.作为索引,并查询原始数据 比如一个对象叫 TrainSourceDO ,是一个火车票资源地实体,希望为出发城市、抵达城市、价格、坐席类型建立索引,并且能够查询到数据本身,可以按照以下配置; 这里的 setPropertyMapper 是指定希望哪个字段作为要建立索引的字段,setDictKeyMapper 指定了索引字段和字典 key (树上实际存储的数据)映射关系; 这里的价格我们希望是能够支持范围和比较查询的,并且为了提高查询性能,所以指定了用 treeMap ; 最终前缀树节点的顺序是按照添加顺序来的,也就是出发城市作为第一个节点,原始数据作为尾部节点,所以是可以查询原始数据的; Configuration configuration = new Configuration(); // 出发城市 CustomizedProperty<TrainSourceDO, Integer> depCityIdProperty = new CustomizedProperty<>("depCityId"); depCityIdProperty.setPropertyMapper(TrainSourceDO::getDepartureCityId); depCityIdProperty.setDictKeyMapper(r -> r); configuration.addProperty(depCityIdProperty); // 抵达城市 CustomizedProperty<TrainSourceDO, Integer> arrCityIdProperty = new CustomizedProperty<>("arrCityId"); arrCityIdProperty.setPropertyMapper(TrainSourceDO::getArrivalCityId); arrCityIdProperty.setDictKeyMapper(r -> r); configuration.addProperty(arrCityIdProperty); // 价格 CustomizedProperty<TrainSourceDO, Integer> arrDistrictIdProperty = new CustomizedProperty<>("price", NodeType.TREE_MAP); arrDistrictIdProperty.setPropertyMapper(t -> ((Double) t.getMinRealPrice()).intValue()); arrDistrictIdProperty.setDictKeyMapper(r -> r); configuration.addProperty(arrDistrictIdProperty); // 坐席类型 SimpleProperty<TrainSourceDO, String> seatClassProperty = new SimpleProperty<>("seatClass", DictKeyType.BYTE); seatClassProperty.setPropertyMapper(TrainSourceDO::getSeatClass); configuration.addProperty(seatClassProperty); // 数据 CustomizedProperty<TrainSourceDO, TrainSourceDO> dataProperty = new CustomizedProperty<>("data"); dataProperty.setPropertyMapper(Function.identity()); dataProperty.setDictKeyMapper(TrainSourceDO::getId); configuration.addProperty(dataProperty); // 新建前缀树 MapTrie<TrainSourceDO> trie = new MapTrie<>(configuration); 2.用作索引,只查询索引 同上,只是尾部节点不再是数据了; Configuration configuration = new Configuration(); // 出发城市 CustomizedProperty<TrainSourceDO, Integer> depCityIdProperty = new CustomizedProperty<>("depCityId"); depCityIdProperty.setPropertyMapper(TrainSourceDO::getDepartureCityId); depCityIdProperty.setDictKeyMapper(r -> r); configuration.addProperty(depCityIdProperty); // 抵达城市 CustomizedProperty<TrainSourceDO, Integer> arrCityIdProperty = new CustomizedProperty<>("arrCityId"); arrCityIdProperty.setPropertyMapper(TrainSourceDO::getArrivalCityId); arrCityIdProperty.setDictKeyMapper(r -> r); configuration.addProperty(arrCityIdProperty); // 新建前缀树 MapTrie<TrainSourceDO> trie = new MapTrie<>(configuration); 3.用于压缩 将所有字段都作为前缀树的节点,反射构建; Configuration configuration = new Configuration(); Field[] fields = ReflectUtil.getFields(TrainSourceDO.class); for (Field field : fields) { if (Number.class.isAssignableFrom(field.getType())) { CustomizedProperty customizedProperty = new CustomizedProperty<>(field.getName()); customizedProperty.setPropertyMapper(e -> ReflectUtil.getFieldValue(e, field)); customizedProperty.setDictKeyMapper(r -> r); configuration.addProperty(customizedProperty); } else { SimpleProperty simpleProperty = new SimpleProperty<>(field.getName()); simpleProperty.setPropertyMapper(e -> ReflectUtil.getFieldValue(e, field)); configuration.addProperty(simpleProperty); } } // 新建前缀树 MapTrie<TrainSourceDO> trie = new MapTrie<>(configuration); 再利用 resultBuilder 可以将数据完整的查询出来,反射构建; ResultBuilder<TrainSourceDO> resultBuilder = new ResultBuilder<>(TrainSourceDO::new); Field[] fields = ReflectUtil.getFields(TrainSourceDO.class); for (Field field : fields) { resultBuilder.addSetter(field.getName(), (t, r) -> ReflectUtil.setFieldValue(t, field, r)); } return resultBuilder; 不带虚拟头节点的话,前缀树就是一个梯形结构,所以将选择性比较高的字段排在后面能够更好的压缩数据,可以先建立一次前缀树,拿到所有字段的字典值大小排序后再按照大小重新构建一次; // 拿到每个字段的字典值大小 Map<String, Integer> dictSizes = trie1.dictSizes(); // 按照字段的大小排序 CollectionUtil.sort(configuration2.getProperties(), Comparator.comparing(e -> dictSizes.get(e.name()))); // 重新构建 MapTrie<TrainSourceDO> trie2 = new MapTrie<>(configuration2); for (TrainSourceDO data : dataList) { trie2.insert(data); } 添加数据 直接 insert 就行,时间复杂度是 O(h),h 是前缀树高度,也就是建立索引的字段数量 List<TrainSourceDO> dataList = getDataList("train_resource_3000.json"); for (TrainSourceDO data : dataList) { trie.insert(data); } 删除数据 1.根据数据本身删除; 数据本身包含了所有建立索引的字段,所以删除效率较高,复杂度 O(h) List<TrainSourceDO> dataToErase = RandomUtil.randomEles(dataList, 10); for (TrainSourceDO data : dataToErase) { trie.erase(data); } 2.根据条件删除 尽量给出尽可能多的字段,可以提高删除的效率,给出首部的字段删除效率高一点,直接给出尾部的字段需要循环查找,删除效率低; Criteria criteria = new Criteria().addCriterion(Condition.BETWEEN, 0, 1005, "depCityId"); trie.erase(criteria); 有一种特殊情况,如果希望只根据 id 删除,然后尽量提高删除的效率的话,可以先根据尾部节点的字典拿到该数据,然后再删除,时间复杂度 O(1)+O(h); // 数据 CustomizedProperty<TrainSourceDO, TrainSourceDO> dataProperty = new CustomizedProperty<>("data", NodeType.TREE_MAP); dataProperty.setPropertyMapper(Function.identity()); dataProperty.setDictKeyMapper(TrainSourceDO::getId); configuration.addProperty(dataProperty); // 先根据字典拿到数据,然后再删除 long id = 143859138L; TrainSourceDO eraseData = (TrainSourceDO) trie.dictValues("data", id).iterator().next(); trie.erase(eraseData); 查询数据 1.按层查询 比如盲盒场景中,用户都是选择出发地然后随机抵达地,这里出发地是固定的,所以可以出发地为条件,拿到有效抵达地,出发日期什么的; List<Integer> queryDepCityList = Lists.newArrayList(144, 145, 146, 900); List<Integer> indexList1 = dataList.stream().filter(e -> queryDepCityList.contains(e.getDepartureCityId())).map(TrainSourceDO::getArrivalCityId).distinct().sorted() .collect(Collectors.toList()); Criteria criteria = new Criteria(); criteria.addCriterion(Condition.IN, queryDepCityList, "depCityId"); List<Integer> indexList2 = trie.<Integer> propertySearch(criteria, "arrCityId").stream().sorted().collect(Collectors.toList()); 2.原始数据查询 有时候索引中并不包含数据的所有字段,需要拿到原始数据的完整字段进一步过滤,可以直接查询原始数据; Criteria criteria = new Criteria(); criteria.addCriterion(Condition.IN, queryDepCityList, "depCityId"); List<TrainSourceDO> dataList2 = trie.dataSearch(criteria).stream().sorted(Comparator.comparing(TrainSourceDO::getId)).collect(Collectors.toList()); 3.树结构查询 树结构看起来比较直观,也可以指定要查询的多个字段组合成一颗树返回; Criteria criteria = new Criteria(); criteria.addCriterion(Condition.IN, queryDepCityList, "depCityId"); Aggregations aggregations = new Aggregations(); Object result = trie.treeSearch(criteria, aggregations, "depCityId", "arrCityId", "id"); 4.列表结构查询 同树结构查询,不过平铺成了列表,列表是最常用的数据返回方式; 是支持聚合的,比如例如出发城市、抵达城市、出发日期、价格构建一颗树,然后对价格进行聚合,就用字典树实现了低价日历,以下是伪代码; Trie<FlightUnitVO> trie = inlandFlightTrieIndexManager.getTrie(); Criteria criteria = buildCriteriaByQueryCondition(request.getQueryCondition()); Aggregations aggregations = new Aggregations(); aggregations.addAggregation(Aggregation.MIN, FlightTrieIndexNames.INDEX_PRICE); ResultBuilder<ListSearchResponse> resultBuilder = new ResultBuilder<>(ListSearchResponse::new); resultBuilder.addSetter(FlightTrieIndexNames.INDEX_DEP_CITY_CODE, ListSearchResponse::setDepCityCode); resultBuilder.addSetter(FlightTrieIndexNames.INDEX_ARR_CITY_CODE, ListSearchResponse::setArrCityCode); resultBuilder.addSetter(FlightTrieIndexNames.INDEX_DEP_DATE, ListSearchResponse::setDate); resultBuilder.addSetter(FlightTrieIndexNames.INDEX_PRICE, ListSearchResponse::setMinPrice); List<ListSearchResponse> result = trie.listSearch(criteria, aggregations, resultBuilder); return R.ok(result); 5.字典值查询 常见的情况是作为下拉框的 options ; List<Integer> dataList2 = trie.<Integer>dictValues("depCityId").stream().sorted().collect(Collectors.toList()); 或者希望通过 id 拿到原始数据的特殊情况,比直接从树上拿更快,O(1)的复杂度; long id = 143859138L; TrainSourceDO eraseData = (TrainSourceDO) trie.dictValues("data", id).iterator().next(); 序列化和反序列化 使用的是 protobuf 序列化,对比原始 json 数据,序列化后的大小为原始 json 的 1/5 ,也适用于数据 dump 分析; // 序列化 MapTrie<TrainSourceDO> trie1 = new MapTrie<>(buildConfiguration3()); for (TrainSourceDO data : dataList) { trie1.insert(data); } File dumpFile = new File(RESOUCE_FOLDER + "train_resource_dump.dat"); if (dumpFile.exists()) { dumpFile.delete(); } FileUtil.writeBytes(trie1.serialize(), dumpFile); // 反序列化 MapTrie<TrainSourceDO> trie2 = new MapTrie<>(buildConfiguration3()); trie2.deserialize(FileUtil.readBytes(dumpFile)); 项目 性能分析和对比 树和位图 1.树 树中的索引条目和行之间是一对一的关系; 适用于大量的增删改查; 适用于选择性高的列; 2.位图 位图的一个索引条目对应多条数据,每个 bit 位对应一行,占用空间非常小,很好地利用了 CPU Cache 的空间局部性; 适用于高度重复且读多写少的数据(低基数,选择性低); 适合 OR 操作; update 成本比较高; 最早项目中用的就是位图,类似倒排索引,位图存在这样几个问题; 位图并不是很适合为价格,日期这种基数比较高的字段建立索引,所以一般针对价格,日期的查询,还需要拿到原始数据再进行一次遍历后查询; 如果一个字段,比如出发城市有 100 个,那么每新增一个城市就需要新增一个位图,这个位图如果不压缩的话,占用空间还是很大的,比如现在有 60w 的数据,那么每个索引在不压缩的情况下就是 600000/8/1024 = 73kb ; 位图更新的成本比较高,因为涉及到多个索引,直接更新还可能会引入一致性问题,所以一般不会直接更新原始的数据。拿 es 来举例,删除或者更新会将原始的文档 id 标记为删除,然后新增,最后在段合并的时候将这些无效的数据清理掉。所以更新的次数多了,位图中就会出现很多无效的占用空间的数据,导致空间占用越来越高,所以还需要在业务低峰期定期重建索引; 前缀树和 B+树 都是多路查找树; 查询效率都比较稳定; 数据都是存在叶子节点上; 非叶子结点相当于是叶子结点的索引; B+Tree 更适合磁盘存储,可以使用磁盘的 Block (空间局部性和磁盘预读); Trie 不适用于存储在随机访问比较慢的介质上,当数据非常庞大并且存储在磁盘上时,数据结构的效率更多地取决于磁盘块访问的数量,而不是所有操作的总量。B+ Tree 在一个节点(可视为“数据块”)中包含许多记录,因此所需的块访问次数比 Trie 少得多。 B+树更适合操作系统的文件索引和数据库索引; B+树的叶子节点增加了链指针,主要是为了加快检索多个相邻叶节点的效率,可以实现顺序查找; 前缀树的种类和变种 prefix tree ; suffix tree ; radix tree(patricia tree, compact prefix tree); crit-bit tree ; double array trie ; ternary trie ; Kart-trie ; 生产和个人实践 盲盒项目的背景和痛点 ​ 在盲盒的开盒流程中,会对本地资源预筛后再去请求实时的搜索接口,为了提高对这份资源的检索速度,用到了位图索引; ​ 资源筛选的流程中,用户的出发地是确定的,日期,价格区间这些是随机变量,先随机日期,然后随机价格区间; 问题 1:开盒成功率低 ​ 日期随机可以有两种做法,一种是从配置上指定的固定日期区间随机,另一种是拿到这个出发地下有效的出发日期然后随机。早期一直是用的第一种做法,直到目的地盲盒的出现,资源的数量太少了,对应的有效日期也变少了,所以固定日期随机会导致开盒成功率降低很多。这个时候想到了有效日期随机,先拿到这个出发地下所有有效日期,再从这些有效日期中随机,可以提高开盒成功率; ​ 如果用位图实现的话,为了得到指定出发地下的所有有效日期,需要过滤出所有原始数据,拿到日期去重后再随机,后面的随机价格区间同理,需要根据出发地和日期再过滤一次,这样查下来效率还是很低的; ​ 所以想到了使用前缀树这种结构,如果按照出发地,日期,价格区间建立节点并依次查询,可以有效减少查询范围; 问题 2:资源预校验效率低 ​ 有些活动的库存数量是有限的,为了尽量提高开盒成功率,所以在用户实际开盒前会做一次资源预校验,根据用户的出发地和业务的一些策略配置,判断用户有没有有效的抵达地,如果用户没有有效抵达地资源,就提前拦截掉,避免无效的库存消耗; ​ 如果每次请求方每次都过来查显然是不行的,所以限制请求方在场次开始前只查询一次,结果包含所有的有效出发地和抵达地,然后由请求方缓存起来。这个结果是和活动场次相关的,毕竟每个活动场次里面配置的产品和策略都不一样,用这个配置去全量的资源池中过滤出有效的出发抵达地返回; ​ 随着活动场次越来越多和策略配置的精细化,即使是每个场次只查询一次,也会带来很大的查询压力以及可能的超时问题,所以想到了由服务提供方这边也建立一份缓存,定时刷新; ​ 这份缓存就很适合用前缀树实现,按照活动、场次、产品、出发城市、出发日期、抵达城市构建; ​ 有两个场景可以使用这份缓存: ​ 1.查询条件指定场次,查询结果指定出发城市+抵达城市,就是资源预校验的结果; ​ 2.场次确定了,那么从这个场次相关的预校验缓存里面去拿到的有效出发日期、有效价格区间、有效抵达地,会进一步减少数据范围,提高查询效率; 用于资源分析 实现低价日历
  16. 小白用户,求大佬们点评下这个备份方案是否可行~ 背景:4 盘位 NAS ( 464c ),没有做 RAID ,2 块 SSD ,2 块 HDD 。主要去备份照片,担心数据丢失。 方案: 1 )定时(周粒度)把手机照片通过 QFile 同步到 NAS 的 SSD1 盘中。 2 )定时(月粒度)通过 HBS3 做**同步**到 HDD1 盘中。定时还通过 HBS3 做**备份**到 HDD2 盘中。 3 )定时(年粒度)通过 HBS3 做**同步**到移动硬盘中。 附: 1 )不考虑 raid 的原因就是感觉 raid 也会出问题,还占用存储,不如直接做同步、备份来的划算 2 )主要数据就是照片等,不考虑影片这类备份(同步)。 3 )没有同步到网盘就是担心网盘的隐私等问题。 4 )另外想"吐槽"下,感觉威联通的很多软件的功能都有交叠重复,都不知道用哪个比较好=_=
  17. 想写个简单的 Android 软件,然后去看 Google 的教程结果都是 kotlin 的示例。Java 已经被抛弃了吗?如果还能用 Java 去哪里找比较新的 Java Android 教程。
  18. 三个月前,折腾了两个网站,今天给大家唠唠. BTBK - 不吐不快,匿名社区 https://btbk.org/ BTBK 匿名社区. 逼乎 - 与世界分享你的装逼技巧与水平 https://www.ebihu.com/ 逼乎社区. _ 关于逼乎:_ 18 年就建立过一个叫“逼乎”的网站,大概 21 年关闭了。注册会员近 2000 ,也产生了一些有趣的评论和话题。这次又看到一个手痒的域名,因为一个域名搞了一个网站。 我的初心是希望吸引一些热爱吹牛皮,又可以吹得很好的人,在这里互吹。恶搞,装逼本就是一种趣味,只要控制好不人身攻击,就可以成为一个很好的小众站点。 目前的现状是:上线两个多月,因为这个名称,确实吸引了不少用户,注册用户每天都在上涨,但大家就是不发帖,都是占位置。 不知 V 站有没有运营达人,能对这类情况给出一些建议。。。。。。。。。。。。。。。。。。。。。 _ 关于 BTBK:_ 随着年龄增长,对这个社会运转规则了解的越来越多之后,发现能自由沟通,表达的东西越来越少,处处敏感,处处都是人情世故。这个不能讲,那个不能抱怨,特码的还想出来一个”X 能量“的词儿,让你自我阉割。真的好难受。 哪怕是工作上的一些吐槽,也担心影响家人,叨扰朋友。自己的孩子快要出生了,昨天自己在楼下修车挡泥板,没留意到旁边汽车里竟然有人,一会儿老哥估计是因为我敲打螺丝打扰他了,打开车门离开了。 我在想,如果有一天孩子出生,我也要或者这么憋屈,有话不能说,有家不能回,我天天赚钱累死累活到底为了啥。 也因为多年前就感觉树洞挺好的,那时候很多论坛还可以自由发帖,现在管得太严,索性自己鼓捣了一个网站。我想自己生活憋屈没处写的牢骚,别人肯定也有,也没搞什么手机号登录之类的,也不想盈利,有人用就够了。 前段时间去抖音小红书上方发了不少帖子,一开始还想吸引点儿人,结果两个手机号,都被封了。麻蛋不搞了,没人用算了。但最近发现开始零零散散有人了,如我所料,基本都离不开下半身那点事。 数据上,每日新增和发帖量都比逼乎高 内容上,最初的灵感来源于知乎话题:“有哪些你只能匿名说出来的秘密”,违法犯罪的话题肯定是不能聊的,匿名也不能等于犯罪,本心是希望给大家提供一个合理的情绪诉说和沟通渠道,虽然标题带了“树洞”两个字,但又不想一直做个树洞。 现在就卡在“自己也不知道该如何做 BTBK 的内容和人群定位”的尴尬阶段,只是“说秘密”感觉有点宽泛。 如果说上面的逼乎是玩票性质,那这个 BTBK 就真的是希望有人用,并且可以帮到别人。不知运营大佬如何看待这个问题? _ 总结:_ 两个网站,起初最看好的逼乎,因为有噱头,自带流量。但三个月下来,各种数据较 BTBK 落了下风。 两个站同时运营不现实, 大家更看好哪个站点?理由是什么?有啥建议? V2 作为技术大佬社区,有啥技术方面的建议? ** BTBK 匿名社区. 逼乎社区. **
  19. 我有一个闲鱼账号有几千个交易记录,几千条积极的好评,只有 2 条差评。 交易额超百万,但我已经不在做这个业务了,有转出的价值吗? ps:账号是仅销售一种产品类型,所以如果有价值能转出就转出,确定无法转出我就用这个账号开展其他的业务。
  20. 电信的 189 邮箱,移动的 139 邮箱,联通的沃邮箱,都可以重置密码然后添加到一些邮件应用,地址就是手机号跟邮箱后缀的格式。 适合一些本就知道你的手机号 && 需要提供邮箱地址 && 用运营商邮箱不会让隐私或者安全变得更糟的服务,它有你哪个手机号,你就用哪个手机号的运营商邮箱,如此可以少提供一项信息给对方,在不得不用的无奈场景中也算提升了一点点隐私性了。
  21. 会议预定 OA 都有,不需要管,OA 数据有接口开放, 想做一个 APP ,装安装平板上面,放于会议室门口,用于显示会议室预定信息 需要做两个程序 server:java 一个服务器程序 ,简易 WEB ,从 OA 拉会议室清单,人工绑定前端 APP ,另外定时从 OA 同步会议清单,把这些会议返回给 APP APP: 获取平板唯一标识,提交到服务器,服务器返回会议清单(没绑定就返回空),APP 显示出来表格 最后交付全部源码,这样的一个需求大约多少¥
  22. 想修改一个开源 macOS app ,项目是 objc + xib 找了半天没找到 xib interface builder 官方完整文档(我想了一下这种文档岂不是还要有 xcode 的截图?然后还有 xcode 版本问题!),都是一些零碎的博客文章 有 macOS app 开发者知道这该上哪学吗,你们自己是如何学的,有推荐的书吗 现在都是 swiftui
  23. 很久没遇到过死机了,最近更新 masOS 15.0 后,今天遇到了死机,Raycast 输入内容的时候卡住,然后只能按电源键重启了。
  24. 试过人体工学椅,皮椅,换了好几把,始终还是坐久了累。 终于明白再舒服的椅子都比不过沙发葛优躺。 于是就在想,这种姿势下能玩电脑应该就是最佳方案