public abstract class Window {
/**
* Gets the largest timestamp that still belongs to this window.
*
* @return The largest timestamp that still belongs to this window.
*/
public abstract long maxTimestamp();
}
// 判断两个时间窗口是否有交集
public boolean intersects(TimeWindow other) {
return this.start <= other.end && this.end >= other.start;
}
/**
* Returns the minimal window covers both this window and the given window.
*/
// 返回两个window的并集
public TimeWindow cover(TimeWindow other) {
return new TimeWindow(Math.min(start, other.start), Math.max(end, other.end));
}
// T 为元素类型,W为窗口类型
@PublicEvolving
public abstract class WindowAssigner implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Returns a {@code Collection} of windows that should be assigned to the element.
*
* @param element The element to which windows should be assigned.
* @param timestamp The timestamp of the element.
* @param context The {@link WindowAssignerContext} in which the assigner operates.
*/
// 获取包含元素的window集合
// 参数解释element: 进入窗口的元素。timestamp:元素的时间戳即event time。context:WindowAssigner上下文对象,需要用于携带processing time。
public abstract Collection assignWindows(T element, long timestamp, WindowAssignerContext context);
/**
* Returns the default trigger associated with this {@code WindowAssigner}.
*/
// 获取默认的触发器
public abstract Trigger getDefaultTrigger(StreamExecutionEnvironment env);
/**
* Returns a {@link TypeSerializer} for serializing windows that are assigned by
* this {@code WindowAssigner}.
*/
// 获取window的序列化器
public abstract TypeSerializer getWindowSerializer(ExecutionConfig executionConfig);
/**
* Returns {@code true} if elements are assigned to windows based on event time,
* {@code false} otherwise.
*/
// 如果窗口是基于event time的,返回true。否则返回false
public abstract boolean isEventTime();
/**
* A context provided to the {@link WindowAssigner} that allows it to query the
* current processing time.
*
*
This is provided to the assigner by its containing
* {@link org.apache.flink.streaming.runtime.operators.windowing.WindowOperator},
* which, in turn, gets it from the containing
* {@link org.apache.flink.streaming.runtime.tasks.StreamTask}.
*/
public abstract static class WindowAssignerContext {
/**
* Returns the current processing time.
*/
// 获取当前的processing time。在使用processing time类型的window时候会使用此方法。
public abstract long getCurrentProcessingTime();
}
}
@PublicEvolving
public class TumblingEventTimeWindows extends WindowAssigner {
private static final long serialVersionUID = 1L;
// 窗口大小
private final long size;
// 窗口偏移
private final long offset;
protected TumblingEventTimeWindows(long size, long offset) {
// offset大小必须位于0和size之间
if (offset < 0 || offset >= size) {
throw new IllegalArgumentException("TumblingEventTimeWindows parameters must satisfy 0 <= offset < size");
}
this.size = size;
this.offset = offset;
}
@Override
public Collection assignWindows(Object element, long timestamp, WindowAssignerContext context) {
if (timestamp > Long.MIN_VALUE) {
// Long.MIN_VALUE is currently assigned when no timestamp is present
// 获取到的start值为刚好不大于timestamp的size的整数倍,再加上offset和windowSize取模的值
long start = TimeWindow.getWindowStartWithOffset(timestamp, offset, size);
return Collections.singletonList(new TimeWindow(start, start + size));
} else {
throw new RuntimeException("Record has Long.MIN_VALUE timestamp (= no timestamp marker). " +
"Is the time characteristic set to 'ProcessingTime', or did you forget to call " +
"'DataStream.assignTimestampsAndWatermarks(...)'?");
}
}
@Override
public Trigger getDefaultTrigger(StreamExecutionEnvironment env) {
return EventTimeTrigger.create();
}
@Override
public String toString() {
return "TumblingEventTimeWindows(" + size + ")";
}
/**
* Creates a new {@code TumblingEventTimeWindows} {@link WindowAssigner} that assigns
* elements to time windows based on the element timestamp.
*
* @param size The size of the generated windows.
* @return The time policy.
*/
public static TumblingEventTimeWindows of(Time size) {
return new TumblingEventTimeWindows(size.toMilliseconds(), 0);
}
/**
* Creates a new {@code TumblingEventTimeWindows} {@link WindowAssigner} that assigns
* elements to time windows based on the element timestamp and offset.
*
*
For example, if you want window a stream by hour,but window begins at the 15th minutes
* of each hour, you can use {@code of(Time.hours(1),Time.minutes(15))},then you will get
* time windows start at 0:15:00,1:15:00,2:15:00,etc.
*
*
Rather than that,if you are living in somewhere which is not using UTC±00:00 time,
* such as China which is using UTC+08:00,and you want a time window with size of one day,
* and window begins at every 00:00:00 of local time,you may use {@code of(Time.days(1),Time.hours(-8))}.
* The parameter of offset is {@code Time.hours(-8))} since UTC+08:00 is 8 hours earlier than UTC time.
*
* @param size The size of the generated windows.
* @param offset The offset which window start would be shifted by.
* @return The time policy.
*/
public static TumblingEventTimeWindows of(Time size, Time offset) {
return new TumblingEventTimeWindows(size.toMilliseconds(), offset.toMilliseconds());
}
@Override
public TypeSerializer getWindowSerializer(ExecutionConfig executionConfig) {
return new TimeWindow.Serializer();
}
@Override
public boolean isEventTime() {
return true;
}
}
@PublicEvolving
public class SlidingEventTimeWindows extends WindowAssigner {
private static final long serialVersionUID = 1L;
// 窗口大小(跨度)
private final long size;
// 窗口滑动距离
private final long slide;
// 偏移量
private final long offset;
protected SlidingEventTimeWindows(long size, long slide, long offset) {
// offset必须小于slide,并且size必须大于0
if (Math.abs(offset) >= slide || size <= 0) {
throw new IllegalArgumentException("SlidingEventTimeWindows parameters must satisfy " +
"abs(offset) < slide and size > 0");
}
this.size = size;
this.slide = slide;
this.offset = offset;
}
@Override
public Collection assignWindows(Object element, long timestamp, WindowAssignerContext context) {
if (timestamp > Long.MIN_VALUE) {
// 对于SlidingWindow,窗口之间会有重叠。在某一时间点会有size/slide个窗口包含它
List windows = new ArrayList<>((int) (size / slide));
// 获取到的start值为刚好不大于timestamp的size的整数倍,再加上offset和windowSize取模的值
long lastStart = TimeWindow.getWindowStartWithOffset(timestamp, offset, slide);
for (long start = lastStart;
start > timestamp - size;
start -= slide) {
// 从startStart开始,每次减去一个slide。之间所有的窗口都会包含该元素,需要返回
// 循环的时候start必须要大于timestamp - size。如果start < timestamp - size,那么(start + size) 将会小于timestamp,即end < timestamp,窗口不可能包含这个元素
windows.add(new TimeWindow(start, start + size));
}
return windows;
} else {
// 忘记设置env使用event time或者没有指定timestamp字段,会导致timestamp为LONG.MIN_VALUE
throw new RuntimeException("Record has Long.MIN_VALUE timestamp (= no timestamp marker). " +
"Is the time characteristic set to 'ProcessingTime', or did you forget to call " +
"'DataStream.assignTimestampsAndWatermarks(...)'?");
}
}
public long getSize() {
return size;
}
public long getSlide() {
return slide;
}
// 默认使用event time trigger
@Override
public Trigger getDefaultTrigger(StreamExecutionEnvironment env) {
return EventTimeTrigger.create();
}
@Override
public String toString() {
return "SlidingEventTimeWindows(" + size + ", " + slide + ")";
}
/**
* Creates a new {@code SlidingEventTimeWindows} {@link WindowAssigner} that assigns
* elements to sliding time windows based on the element timestamp.
*
* @param size The size of the generated windows.
* @param slide The slide interval of the generated windows.
* @return The time policy.
*/
public static SlidingEventTimeWindows of(Time size, Time slide) {
return new SlidingEventTimeWindows(size.toMilliseconds(), slide.toMilliseconds(), 0);
}
/**
* Creates a new {@code SlidingEventTimeWindows} {@link WindowAssigner} that assigns
* elements to time windows based on the element timestamp and offset.
*
*
For example, if you want window a stream by hour,but window begins at the 15th minutes
* of each hour, you can use {@code of(Time.hours(1),Time.minutes(15))},then you will get
* time windows start at 0:15:00,1:15:00,2:15:00,etc.
*
*
Rather than that,if you are living in somewhere which is not using UTC±00:00 time,
* such as China which is using UTC+08:00,and you want a time window with size of one day,
* and window begins at every 00:00:00 of local time,you may use {@code of(Time.days(1),Time.hours(-8))}.
* The parameter of offset is {@code Time.hours(-8))} since UTC+08:00 is 8 hours earlier than UTC time.
*
* @param size The size of the generated windows.
* @param slide The slide interval of the generated windows.
* @param offset The offset which window start would be shifted by.
* @return The time policy.
*/
public static SlidingEventTimeWindows of(Time size, Time slide, Time offset) {
return new SlidingEventTimeWindows(size.toMilliseconds(), slide.toMilliseconds(), offset.toMilliseconds());
}
@Override
public TypeSerializer getWindowSerializer(ExecutionConfig executionConfig) {
return new TimeWindow.Serializer();
}
@Override
public boolean isEventTime() {
return true;
}
}
public abstract class MergingWindowAssigner extends WindowAssigner {
private static final long serialVersionUID = 1L;
/**
* Determines which windows (if any) should be merged.
*
* @param windows The window candidates.
* @param callback A callback that can be invoked to signal which windows should be merged.
*/
// 合并窗口的逻辑
// 参数为:windows: 待合并的窗口集合,callback: 回调函数,用于通知将要被合并的window
public abstract void mergeWindows(Collection windows, MergeCallback callback);
/**
* Callback to be used in {@link #mergeWindows(Collection, MergeCallback)} for specifying which
* windows should be merged.
*/
public interface MergeCallback {
/**
* Specifies that the given windows should be merged into the result window.
*
* @param toBeMerged The list of windows that should be merged into one window.
* @param mergeResult The resulting merged window.
*/
// toBeMerged:将要被合并的window
// mergeResult:合并结果窗口
void merge(Collection toBeMerged, W mergeResult);
}
}
public class EventTimeSessionWindows extends MergingWindowAssigner {
private static final long serialVersionUID = 1L;
// session超时时间,根据session window的定义,相邻的两个元素时间间隔如果超过session超时时间,后面新到来的window会进入新的窗口中
protected long sessionTimeout;
protected EventTimeSessionWindows(long sessionTimeout) {
if (sessionTimeout <= 0) {
throw new IllegalArgumentException("EventTimeSessionWindows parameters must satisfy 0 < size");
}
this.sessionTimeout = sessionTimeout;
}
@Override
public Collection assignWindows(Object element, long timestamp, WindowAssignerContext context) {
//直接返回start为timestamp,end为timestamp + sessionTimeout的window,合并window的操作在WindowOperator中,会生成时间跨度覆盖满足session window定义元素的window。会在后续博客分析
return Collections.singletonList(new TimeWindow(timestamp, timestamp + sessionTimeout));
}
@Override
public Trigger getDefaultTrigger(StreamExecutionEnvironment env) {
return EventTimeTrigger.create();
}
@Override
public String toString() {
return "EventTimeSessionWindows(" + sessionTimeout + ")";
}
/**
* Creates a new {@code SessionWindows} {@link WindowAssigner} that assigns
* elements to sessions based on the element timestamp.
*
* @param size The session timeout, i.e. the time gap between sessions
* @return The policy.
*/
public static EventTimeSessionWindows withGap(Time size) {
return new EventTimeSessionWindows(size.toMilliseconds());
}
/**
* Creates a new {@code SessionWindows} {@link WindowAssigner} that assigns
* elements to sessions based on the element timestamp.
*
* @param sessionWindowTimeGapExtractor The extractor to use to extract the time gap from the input elements
* @return The policy.
*/
// 动态的EventTimeSessionWindow,gap可以随着元素到来调整的
@PublicEvolving
public static DynamicEventTimeSessionWindows withDynamicGap(SessionWindowTimeGapExtractor sessionWindowTimeGapExtractor) {
return new DynamicEventTimeSessionWindows<>(sessionWindowTimeGapExtractor);
}
@Override
public TypeSerializer getWindowSerializer(ExecutionConfig executionConfig) {
return new TimeWindow.Serializer();
}
@Override
public boolean isEventTime() {
return true;
}
/**
* Merge overlapping {@link TimeWindow}s.
*/
//合并重叠的window,方法稍后分析
@Override
public void mergeWindows(Collection windows, MergingWindowAssigner.MergeCallback c) {
TimeWindow.mergeWindows(windows, c);
}
}
TimeWindow.mergeWindows方法。该方法定义了时间窗口的合并逻辑。如下所示:
public static void mergeWindows(Collection windows, MergingWindowAssigner.MergeCallback c) {
// sort the windows by the start time and then merge overlapping windows
List sortedWindows = new ArrayList<>(windows);
// 依照各个window的起始时间对window进行排序
Collections.sort(sortedWindows, new Comparator() {
@Override
public int compare(TimeWindow o1, TimeWindow o2) {
return Long.compare(o1.getStart(), o2.getStart());
}
});
// 为(2)变量的集合类型,存放多组合并结果
List>> merged = new ArrayList<>();
// (2)储存合并的窗口。Tuple的第一个参数含义为合并后的window,第二个参数意义为被合并的各个window
Tuple2> currentMerge = null;
// 逐个合并窗口
for (TimeWindow candidate: sortedWindows) {
// 最开始合并的时候,currentMerge为null
if (currentMerge == null) {
currentMerge = new Tuple2<>();
currentMerge.f0 = candidate;
currentMerge.f1 = new HashSet<>();
currentMerge.f1.add(candidate);
// 如果目前已合并的window(currentMerge)和待合并的窗口(candidate),时间上有交集,则需要将这两个窗口时间合并(取并集),重新赋予Tuple2第一个参数,然后将被合并的窗口(candidate)加入到Tuple第二个参数的集合中
} else if (currentMerge.f0.intersects(candidate)) {
currentMerge.f0 = currentMerge.f0.cover(candidate);
currentMerge.f1.add(candidate);
// 这个分支处理待合并window和当前已合并的window没有交集的情况。
} else {
merged.add(currentMerge);
currentMerge = new Tuple2<>();
currentMerge.f0 = candidate;
currentMerge.f1 = new HashSet<>();
currentMerge.f1.add(candidate);
}
}
// 合并操作结束后将currentMerge结果加入到merged集合
if (currentMerge != null) {
merged.add(currentMerge);
}
for (Tuple2> m: merged) {
// 只有被合并的window个数多于一个的时候,才需要通知window合并
if (m.f1.size() > 1) {
// 通知各个被merge的Window
// Window合并的结果在此处输出
c.merge(m.f1, m.f0);
}
}
}
public interface SessionWindowTimeGapExtractor extends Serializable {
/**
* Extracts the session time gap.
* @param element The input element.
* @return The session time gap in milliseconds.
*/
// 定义了进入window的元素和session timeout值的函数关系
long extract(T element);
}
public Collection assignWindows(T element, long timestamp, WindowAssignerContext context) {
// 调用extractor获取sessionTimeout值,其余的逻辑和传统session window相同
long sessionTimeout = sessionWindowTimeGapExtractor.extract(element);
if (sessionTimeout <= 0) {
throw new IllegalArgumentException("Dynamic session time gap must satisfy 0 < gap");
}
return Collections.singletonList(new TimeWindow(timestamp, timestamp + sessionTimeout));
}
在网上无意中看到淘宝提交的hotspot patch,共四个,有意思,记录一下。
7050685:jsdbproc64.sh has a typo in the package name
7058036:FieldsAllocationStyle=2 does not work in 32-bit VM
7060619:C1 should respect inline and
CREATE TABLE sessions (
id CHAR(32) NOT NULL,
data TEXT,
last_accessed TIMESTAMP NOT NULL,
PRIMARY KEY (id)
);
<?php
/**
* Created by PhpStorm.
* User: michaeldu
* Date
public Vector<CartProduct> delCart(Vector<CartProduct> cart, String id) {
for (int i = 0; i < cart.size(); i++) {
if (cart.get(i).getId().equals(id)) {
cart.remove(i);
问题是首页在火狐、谷歌、所有IE中正常显示,列表页的页面在火狐谷歌中正常,在IE6、7、8中都不中,觉得可能那个地方设置的让IE系列都不认识,仔细查看后发现,列表页中没写HTML模板部分没有添加DTD定义,就是<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3
com.jcraft.jsch.JSchException: Auth cancel
at com.jcraft.jsch.Session.connect(Session.java:460)
at com.jcraft.jsch.Session.connect(Session.java:154)
at cn.vivame.util.ftp.SftpServerAccess.connec
centos p安装
yum -y install tree
mac os安装
brew install tree
首先来看tree的用法
tree 中文解释:tree
功能说明:以树状图列出目录的内容。
语 法:tree [-aACdDfFgilnNpqstux][-I <范本样式>][-P <范本样式
一. 实体类简述
实体类其实就是俗称的POJO,这种类一般不实现特殊框架下的接口,在程序中仅作为数据容器用来持久化存储数据用的
POJO(Plain Old Java Objects)简单的Java对象
它的一般格式就是
public class A{
private String id;
public Str