zipkin 自定义采样率

在第一篇文章的后续部分,这一次我们将编写一些更有用的自定义收集器:用于按给定的标准进行分组,采样输入,批量处理以及在固定大小的窗口上滑动。

分组(计数事件,直方图)

假设您有一些项目的集合,并且想要计算每个项目(相对于equals() )出现在此集合中的次数。 这可以使用Apache Commons Collections中的CollectionUtils.getCardinalityMap()来实现。 此方法采用Iterable<T>并返回Map<T, Integer> ,计算每个项目出现在集合中的次数。 但是,有时我们不使用equals()而是按输入T的任意属性分组。 例如,假设我们有一个Person对象列表,我们想计算男性与女性的数量(即Map<Sex, Integer> )或年龄分布。 有一个内置的收集器Collectors.groupingBy(Function<T, K> classifier) –但是,它从键返回一个映射到映射到该键的所有项。 看到:

import static java.util.stream.Collectors.groupingBy;//...final List<Person> people = //...
final Map<Sex, List<Person>> bySex = people.stream().collect(groupingBy(Person::getSex));

这很有价值,但是在我们的例子中,不必要地构建了两个List<Person> 。 我只想知道人数。 没有内置的这种收集器,但是我们可以用一种非常简单的方式来组成它:

import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;//...final Map<Sex, Long> bySex = people.stream().collect(groupingBy(Person::getSex, HashMap::new, counting()));

这个重载版本的groupingBy()具有三个参数。 如前所述,第一个是键( 分类器 )功能。 第二个参数创建了一个新地图,我们很快就会看到它为什么有用的原因。 counting()是一个嵌套的收集器,它将所有同性的人带到一起,并将它们组合在一起-在我们的示例中,它们只是在到达时对其进行计数。 能够选择地图实现非常有用,例如在构建年龄直方图时。 我们想知道在给定年龄下有多少人-但年龄值应排序:

final TreeMap<Integer, Long> byAge = people.stream().collect(groupingBy(Person::getAge, TreeMap::new, counting()));byAge.forEach((age, count) ->System.out.println(age + ":\t" + count));

我们最终得到了一个从年龄(已排序)到具有该年龄的人数的TreeMap

采样,批处理和滑动窗口

Scala中的IterableLike.sliding()方法允许通过固定大小的滑动窗口查看集合。 该窗口从开始处开始,在每次迭代中移动给定数量的项目。 Java 8中缺少的这种功能允许使用多种有用的运算符,例如计算移动平均值 ,将大集合分成批处理(与Guava中的Lists.partition()比较)或每第n个元素进行采样。 我们将为Java 8实现具有类似行为的收集器。 让我们从单元测试开始,它应该简要描述我们想要实现的目标:

import static com.nurkiewicz.CustomCollectors.sliding@Unroll
class CustomCollectorsSpec extends Specification {def "Sliding window of #input with size #size and step of 1 is #output"() {expect:input.stream().collect(sliding(size)) == outputwhere:input  | size | output[]     | 5    | [][1]    | 1    | [[1]][1, 2] | 1    | [[1], [2]][1, 2] | 2    | [[1, 2]][1, 2] | 3    | [[1, 2]]1..3   | 3    | [[1, 2, 3]]1..4   | 2    | [[1, 2], [2, 3], [3, 4]]1..4   | 3    | [[1, 2, 3], [2, 3, 4]]1..7   | 3    | [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7]]1..7   | 6    | [1..6, 2..7]}def "Sliding window of #input with size #size and no overlapping is #output"() {expect:input.stream().collect(sliding(size, size)) == outputwhere:input | size | output[]    | 5    | []1..3  | 2    | [[1, 2], [3]]1..4  | 4    | [1..4]1..4  | 5    | [1..4]1..7  | 3    | [1..3, 4..6, [7]]1..6  | 2    | [[1, 2], [3, 4], [5, 6]]}def "Sliding window of #input with size #size and some overlapping is #output"() {expect:input.stream().collect(sliding(size, 2)) == outputwhere:input | size | output[]    | 5    | []1..4  | 5    | [[1, 2, 3, 4]]1..7  | 3    | [1..3, 3..5, 5..7]1..6  | 4    | [1..4, 3..6]1..9  | 4    | [1..4, 3..6, 5..8, 7..9]1..10 | 4    | [1..4, 3..6, 5..8, 7..10]1..11 | 4    | [1..4, 3..6, 5..8, 7..10, 9..11]}def "Sliding window of #input with size #size and gap of #gap is #output"() {expect:input.stream().collect(sliding(size, size + gap)) == outputwhere:input | size | gap | output[]    | 5    | 1   | []1..9  | 4    | 2   | [1..4, 7..9]1..10 | 4    | 2   | [1..4, 7..10]1..11 | 4    | 2   | [1..4, 7..10]1..12 | 4    | 2   | [1..4, 7..10]1..13 | 4    | 2   | [1..4, 7..10, [13]]1..13 | 5    | 1   | [1..5, 7..11, [13]]1..12 | 5    | 3   | [1..5, 9..12]1..13 | 5    | 3   | [1..5, 9..13]}def "Sampling #input taking every #nth th element is #output"() {expect:input.stream().collect(sliding(1, nth)) == outputwhere:input  | nth | output[]     | 1   | [][]     | 5   | []1..3   | 5   | [[1]]1..6   | 2   | [[1], [3], [5]]1..10  | 5   | [[1], [6]]1..100 | 30  | [[1], [31], [61], [91]]}
}

在Spock中使用数据驱动的测试,我成功地立即编写了将近40个测试用例,简洁地描述了所有需求。 我希望这些对您来说都是清楚的,即使您以前从未看过这种语法。 我已经假设存在方便的工厂方法:

public class CustomCollectors {public static <T> Collector<T, ?, List<List<T>>> sliding(int size) {return new SlidingCollector<>(size, 1);}public static <T> Collector<T, ?, List<List<T>>> sliding(int size, int step) {return new SlidingCollector<>(size, step);}}

收藏家接连收到物品的事实使工作更加困难。 当然,首先收集整个列表并在列表上滑动会比较容易,但是却很浪费。 让我们迭代构建结果。 我什至不假装通常可以并行执行此任务,所以我将不实现combiner()

public class SlidingCollector<T> implements Collector<T, List<List<T>>, List<List<T>>> {private final int size;private final int step;private final int window;private final Queue<T> buffer = new ArrayDeque<>();private int totalIn = 0;public SlidingCollector(int size, int step) {this.size = size;this.step = step;this.window = max(size, step);}@Overridepublic Supplier<List<List<T>>> supplier() {return ArrayList::new;}@Overridepublic BiConsumer<List<List<T>>, T> accumulator() {return (lists, t) -> {buffer.offer(t);++totalIn;if (buffer.size() == window) {dumpCurrent(lists);shiftBy(step);}};}@Overridepublic Function<List<List<T>>, List<List<T>>> finisher() {return lists -> {if (!buffer.isEmpty()) {final int totalOut = estimateTotalOut();if (totalOut > lists.size()) {dumpCurrent(lists);}}return lists;};}private int estimateTotalOut() {return max(0, (totalIn + step - size - 1) / step) + 1;}private void dumpCurrent(List<List<T>> lists) {final List<T> batch = buffer.stream().limit(size).collect(toList());lists.add(batch);}private void shiftBy(int by) {for (int i = 0; i < by; i++) {buffer.remove();}}@Overridepublic BinaryOperator<List<List<T>>> combiner() {return (l1, l2) -> {throw new UnsupportedOperationException("Combining not possible");};}@Overridepublic Set<Characteristics> characteristics() {return EnumSet.noneOf(Characteristics.class);}}

我花了很多时间来编写此实现,尤其是正确的finisher()所以请不要害怕。 关键部分是一个buffer ,它可以收集项目,直到可以形成一个滑动窗口为止。 然后丢弃“最旧”的物品,并step向前滑动窗口。 我对这种实现并不特别满意,但是测试正在通过。 sliding(N) (与sliding(N, 1)同义词)将允许计算N项目的移动平均值。 sliding(N, N)将输入分成大小为N批次。 sliding(1, N)获取第N个元素(样本)。 希望您会发现这个收藏家有用,喜欢!

翻译自: https://www.javacodegeeks.com/2014/07/grouping-sampling-and-batching-custom-collectors-in-java-8.html

zipkin 自定义采样率

zipkin 自定义采样率_分组,采样和批处理– Java 8中的自定义收集器相关推荐

  1. 分组,采样和批处理– Java 8中的自定义收集器

    在第一篇文章的后续部分,这次我们将编写一些更有用的自定义收集器:用于按给定的标准进行分组,采样输入,批处理和在固定大小的窗口上滑动. 分组(计数事件,直方图) 假设您有一些项目的集合,并且想要计算每个 ...

  2. Java httpClient中实现自定义DNS服务器地址配置

    这个故事从一个小的需求开始. 在知乎编辑器中,链接插入以后可以选择转化为一个链接卡片,用户体验太棒了.这么好的点子,我们必须学(chao)习(xi)过来啊. 这个事情就这么被安排给了我们的前端同学.. ...

  3. 自定义按键_雷柏VT300S号称吃鸡鼠标,能够自定义10个编程按键

    在众多的电竞游戏鼠标中,我相信大家对于雷柏这个品牌一定不会陌生,笔者一直都认为雷柏的电竞游戏鼠标还是非常不错的,性价比也非常的高,而且针对电竞游戏上的优化也做的非常到位,笔者之前也用过雷柏的无线办公系 ...

  4. 微信小程序进度条组件自定义数字_微信小程序之圆形进度条(自定义组件)

    前言 昨天在微信小程序实现了圆形进度条,今天想把这个圆形进度条做成一个组件,方便以后直接拿来用. 根据官方文档自定义组件一步一步来 创建自定义组遇新是直朋能到件 第一步创建项遇新是直朋能到分览目结构 ...

  5. uniapp光标自动定义到文本框_如何在Mac上的照片应用中创建自定义日历

    我花了很多时间为我最好的朋友考虑一份甜蜜的礼物.当我陷入沉思时,我想到了在Mac上使用"照片"应用制作自定义日历的想法.告诉你什么:我的朋友真的很喜欢个性化的日历,上面装饰着令人难 ...

  6. 键盘一键自定义组合工具_为开发人员提供社区,通讯和自定义工具的组合

    键盘一键自定义组合工具 开源开发人员可以通过指导和影响开源社区各个方面的能力,为任何依赖开源软件的公司创造巨大的价值. 这使公司可以塑造他们所依赖的工具,并使它们更适合公司的需求,这种现象也称为&qu ...

  7. 谷歌地图创建自定义位置_如何使用Google Home为任何命令创建自定义快捷方式

    谷歌地图创建自定义位置 Google Home can do a lot of really awesome stuff with voice commands, but some of them c ...

  8. java友盟自定义行为_实现友盟推送消息的完全自定义处理

    1,下面的前提是必须申请了友盟且有app key 3,若开发者需要实现对消息的完全自定义处理,则可以继承 UmengBaseIntentService, 实现自己的Service来完全控制达到消息的处 ...

  9. java swing 字体设置_如何在Java SWING中设置自定义字体的大小和其他属性(粗体,斜体等)...

    通常,当我初始化我想在SWING应用程序中使用的字体时,我这样做: public static final Font TITLEFONT = new Font("Calibri", ...

最新文章

  1. python笔记基础
  2. 【数字信号处理】傅里叶变换性质 ( 序列傅里叶变换共轭对称性质 | 实序列的幅频特性偶对称 | 实序列相频特性奇对称 | 示例说明 )
  3. nginx与Apache的涉及的计算机原理说明
  4. 推荐5款学Java开发的必备工具
  5. 分布式系统session一致性的问题
  6. AngularJS中Directive指令系列 - 基本用法
  7. 大端小端模式判断以及数据转换
  8. vc mysql 查询_VC++数据库模糊查询及精确查询示例代码分享
  9. c++ vector排序_个性化推荐系统源代码之基于LR模型的推荐系统离线排序方案
  10. FF“流产”后 许家印开始了自己的造车之路
  11. python︱利用dlib和opencv实现简单换脸、人脸对齐、关键点定位与画图
  12. Android 自动接听来电
  13. 从零开始系类——电子元器件识别与检测技术
  14. 【Kay】MySQL必会常用函数
  15. 音视频即时通讯—视频客服系统开发
  16. 差分数组:PIPI的区间操作Ⅰ
  17. MogaFX—ServiceNow的Bill McDermott正在关注货币汇率
  18. 27、什么是DOM和BOM
  19. 自动聚焦技术(AF)
  20. hdu 4544 优先队列+贪心

热门文章

  1. Binary Search
  2. codeforces1301 F. Super Jaber(多源bfs+枚举)
  3. BZOJ5358: [Lydsy1805月赛]口算训练
  4. Zookeeper面试题
  5. 青蛙跳台阶的问题——Fibonacci
  6. 独占锁、共享锁、更新锁,乐观锁、悲观锁
  7. JS实现星星评分功能实例代码(两种方法)
  8. Java编程:Java的反射机制中的 getComponentType() 方法
  9. isnull PK <=>
  10. 2018蓝桥杯省赛---java---C---2(猴子分香蕉)