@Override public PCollection<KV<String, Long>> expand(PCollection<String> actions) { return actions .apply(Window.into(Sessions.withGapDuration(Duration.standardHours(1)))) .apply(Count.perElement()); } }
@Override public boolean equals(Object object) { if (!(object instanceof Sessions)) { return false; } Sessions other = (Sessions) object; return getGapDuration().equals(other.getGapDuration()); }
@Test public void testEquality() { assertTrue( Sessions.withGapDuration(new Duration(10)) .isCompatible(Sessions.withGapDuration(new Duration(10)))); assertTrue( Sessions.withGapDuration(new Duration(10)) .isCompatible(Sessions.withGapDuration(new Duration(20)))); }
@Test public void testVerifyCompatibility() throws IncompatibleWindowException { Sessions.withGapDuration(new Duration(10)) .verifyCompatibility(Sessions.withGapDuration(new Duration(10))); thrown.expect(IncompatibleWindowException.class); Sessions.withGapDuration(new Duration(10)) .verifyCompatibility(FixedWindows.of(new Duration(10))); }
@Override public void verifyCompatibility(WindowFn<?, ?> other) throws IncompatibleWindowException { if (!this.isCompatible(other)) { throw new IncompatibleWindowException( other, String.format( "%s is only compatible with %s.", Sessions.class.getSimpleName(), Sessions.class.getSimpleName())); } }
/** Creates a {@code Sessions} {@link WindowFn} with the specified gap duration. */ public static Sessions withGapDuration(Duration gapDuration) { return new Sessions(gapDuration); }
/** Validates that the output timestamp for aggregate data falls within the acceptable range. */ @Test public void testValidOutputTimes() throws Exception { for (long timestamp : Arrays.asList(200, 800, 700)) { WindowFnTestUtils.validateGetOutputTimestamp( Sessions.withGapDuration(Duration.millis(500)), timestamp); } }
} else if (windowFn instanceof Sessions) { Sessions fn = (Sessions) windowFn; window = window + ", " + fn.getGapDuration().toString(); } else { throw new RuntimeException(
@Before public void setup() { windowFn = Sessions.withGapDuration(Duration.millis(10)); state = InMemoryStateInternals.forKey("dummyKey"); set = new MergingActiveWindowSet<>(windowFn, state); @SuppressWarnings("unchecked") ActiveWindowSet.MergeCallback<IntervalWindow> callback = mock(ActiveWindowSet.MergeCallback.class); this.callback = callback; }
SessionsPayload sessionsPayload = SessionsPayload.newBuilder() .setGapSize(Durations.fromMillis(((Sessions) windowFn).getGapDuration().getMillis())) .build(); return SdkFunctionSpec.newBuilder()
@Override public PCollection<IndexedRecord> expand(PCollection<IndexedRecord> indexedRecordPCollection) { PCollection<IndexedRecord> windowed_items; if (properties.windowLength.getValue() < 1) { TalendRuntimeException.build(CommonErrorCodes.UNEXPECTED_ARGUMENT).setAndThrow(properties.windowLength.getName(), String.valueOf(properties.windowLength.getValue())); } // Session Window if (properties.windowSession.getValue()) { windowed_items = indexedRecordPCollection.apply(Window.<IndexedRecord> into( Sessions.withGapDuration(Duration.millis(properties.windowLength.getValue().intValue())))); return windowed_items; } if (properties.windowSlideLength.getValue() < 1) { // Fixed Window windowed_items = indexedRecordPCollection.apply( Window.<IndexedRecord> into(FixedWindows.of(new Duration(properties.windowLength.getValue().intValue())))); } else { // Sliding Window windowed_items = indexedRecordPCollection.apply( Window.<IndexedRecord> into(SlidingWindows.of(new Duration(properties.windowLength.getValue().intValue())) .every(new Duration(properties.windowSlideLength.getValue().intValue())))); } return windowed_items; }
@Override public PCollection<IndexedRecord> expand(PCollection<IndexedRecord> indexedRecordPCollection) { PCollection<IndexedRecord> windowed_items; if (properties.windowLength.getValue() < 1) { TalendRuntimeException.build(CommonErrorCodes.UNEXPECTED_ARGUMENT).setAndThrow(properties.windowLength.getName(), String.valueOf(properties.windowLength.getValue())); } // Session Window if (properties.windowSession.getValue()) { windowed_items = indexedRecordPCollection.apply(Window.<IndexedRecord> into( Sessions.withGapDuration(Duration.millis(properties.windowLength.getValue().intValue())))); return windowed_items; } if (properties.windowSlideLength.getValue() < 1) { // Fixed Window windowed_items = indexedRecordPCollection.apply( Window.<IndexedRecord> into(FixedWindows.of(new Duration(properties.windowLength.getValue().intValue())))); } else { // Sliding Window windowed_items = indexedRecordPCollection.apply( Window.<IndexedRecord> into(SlidingWindows.of(new Duration(properties.windowLength.getValue().intValue())) .every(new Duration(properties.windowSlideLength.getValue().intValue())))); } return windowed_items; }
Sessions sessions = Sessions.withGapDuration(durationParameter(parameters, 1)); if (parameters.size() == 3) { throw new UnsupportedOperationException(
/** * Test to confirm that {@link Sessions} with the default {@link TimestampCombiner} holds up the * watermark potentially indefinitely. */ @Test public void testInvalidOutputAtEarliest() throws Exception { try { WindowFnTestUtils.validateGetOutputTimestamps( Sessions.withGapDuration(Duration.millis(10)), TimestampCombiner.EARLIEST, ImmutableList.of( (List<Long>) ImmutableList.of(1L, 3L), (List<Long>) ImmutableList.of(0L, 5L, 10L, 15L, 20L))); } catch (AssertionError exc) { assertThat( exc.getMessage(), // These are the non-volatile pieces of the error message that a timestamp // was not greater than what it should be. allOf(containsString("a value greater than"), containsString("was less than"))); } }
@Test public void testConsecutive() throws Exception { Map<IntervalWindow, Set<String>> expected = new HashMap<>(); expected.put(new IntervalWindow(new Instant(1), new Instant(19)), set(1, 2, 5, 9)); expected.put(new IntervalWindow(new Instant(100), new Instant(111)), set(100, 101)); assertEquals( expected, runWindowFn( Sessions.withGapDuration(new Duration(10)), Arrays.asList(1L, 2L, 5L, 9L, 100L, 101L))); }
@Test public void testMerging() throws Exception { Map<IntervalWindow, Set<String>> expected = new HashMap<>(); expected.put(new IntervalWindow(new Instant(1), new Instant(40)), set(1, 10, 15, 22, 30)); expected.put(new IntervalWindow(new Instant(95), new Instant(111)), set(95, 100, 101)); assertEquals( expected, runWindowFn( Sessions.withGapDuration(new Duration(10)), Arrays.asList(1L, 15L, 30L, 100L, 101L, 95L, 22L, 10L))); }
@Test public void testDisplayData() { Duration gapDuration = Duration.standardMinutes(234); Sessions session = Sessions.withGapDuration(gapDuration); assertThat(DisplayData.from(session), hasDisplayItem("gapDuration", gapDuration)); } }
@Test public void testSimple() throws Exception { Map<IntervalWindow, Set<String>> expected = new HashMap<>(); expected.put(new IntervalWindow(new Instant(0), new Instant(10)), set(0)); expected.put(new IntervalWindow(new Instant(10), new Instant(20)), set(10)); expected.put(new IntervalWindow(new Instant(101), new Instant(111)), set(101)); assertEquals( expected, runWindowFn(Sessions.withGapDuration(new Duration(10)), Arrays.asList(0L, 10L, 101L))); }
@Test public void testEarlyAndLateOnMergeSubtriggerMerges() throws Exception { tester = TriggerStateMachineTester.forTrigger( AfterWatermarkStateMachine.pastEndOfWindow() .withEarlyFirings(mockEarly) .withLateFirings(mockLate), Sessions.withGapDuration(Duration.millis(10))); tester.injectElements(1); tester.injectElements(5); // Merging should re-activate the early trigger in the merged window tester.mergeWindows(); verify(mockEarly).onMerge(Mockito.any(OnMergeContext.class)); }
/** * When a user explicitly requests per-key aggregate values have their derived timestamp to be the * end of the window (instead of the earliest possible), the session here should not hold each * other up, even though they overlap. */ @Test public void testValidOutputAtEndTimes() throws Exception { WindowFnTestUtils.validateGetOutputTimestamps( Sessions.withGapDuration(Duration.millis(10)), TimestampCombiner.END_OF_WINDOW, ImmutableList.of( (List<Long>) ImmutableList.of(1L, 3L), (List<Long>) ImmutableList.of(0L, 5L, 10L, 15L, 20L))); }