You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@flink.apache.org by GitBox <gi...@apache.org> on 2020/05/06 10:41:13 UTC

[GitHub] [flink] klion26 commented on a change in pull request #11979: [FLINK-17291][docs] Translate 'docs/training/event_driven.zh.md' to C…

klion26 commented on a change in pull request #11979:
URL: https://github.com/apache/flink/pull/11979#discussion_r420585639



##########
File path: docs/training/event_driven.zh.md
##########
@@ -29,19 +29,18 @@ under the License.
 
 ## Process Functions

Review comment:
       “Process Functions" 个人感觉也需要翻译

##########
File path: docs/training/event_driven.zh.md
##########
@@ -29,19 +29,18 @@ under the License.
 
 ## Process Functions
 
-### Introduction
+### 介绍
 
-A `ProcessFunction` combines event processing with timers and state, making it a powerful building
-block for stream processing applications. This is the basis for creating event-driven applications
-with Flink. It is very similar to a `RichFlatMapFunction`, but with the addition of timers.
+`ProcessFunction` 将事件处理与 Timer 和 State 结合在一起,使其成为流处理应用的强大构建模块。
+这是使用 Flink 创建事件驱动的应用程序的基础。它和 `RichFlatMapFunction` 十分相似, 但是增加了 Timer。

Review comment:
       ```suggestion
   这是使用 Flink 创建事件驱动应用程序的基础。它和 `RichFlatMapFunction` 十分相似, 但是增加了 Timer。
   ```

##########
File path: docs/training/event_driven.zh.md
##########
@@ -29,19 +29,18 @@ under the License.
 
 ## Process Functions
 
-### Introduction
+### 介绍
 
-A `ProcessFunction` combines event processing with timers and state, making it a powerful building
-block for stream processing applications. This is the basis for creating event-driven applications
-with Flink. It is very similar to a `RichFlatMapFunction`, but with the addition of timers.
+`ProcessFunction` 将事件处理与 Timer 和 State 结合在一起,使其成为流处理应用的强大构建模块。

Review comment:
       “`ProcessFunction` 将事件处理与 Timer 和 State 结合在一起” 这句话读起来有一点点拗口,能否改成 ”将事件处理与 Timer,State 结合在一起“ 或者其他的描述方式呢?

##########
File path: docs/training/event_driven.zh.md
##########
@@ -61,11 +60,10 @@ DataStream<Tuple3<Long, Long, Float>> hourlyTips = fares
         .process(new PseudoWindow(Time.hours(1)));
 {% endhighlight %}
 
-In this code snippet a `KeyedProcessFunction` called `PseudoWindow` is being applied to a keyed
-stream, the result of which is a `DataStream<Tuple3<Long, Long, Float>>` (the same kind of stream
-produced by the implementation that uses Flink's built-in time windows).
+在这个代码片段中,一个名为 `PseudoWindow` 的 `KeyedProcessFunction` 被应用于 KeyedStream ,
+其结果是一个 `DataStream<Tuple3<Long, Long, Float>>` (与使用 Flink 内置时间窗口的实现生成的流相同)。
 
-The overall outline of `PseudoWindow` has this shape:
+`PseudoWindow` 的总体轮廓示意如下:
 
 {% highlight java %}
 // Compute the sum of the tips for each driver in hour-long windows.

Review comment:
       这里的注释也一起翻译下?
   以及下面其他代码的注释

##########
File path: docs/training/event_driven.zh.md
##########
@@ -61,11 +60,10 @@ DataStream<Tuple3<Long, Long, Float>> hourlyTips = fares
         .process(new PseudoWindow(Time.hours(1)));
 {% endhighlight %}
 
-In this code snippet a `KeyedProcessFunction` called `PseudoWindow` is being applied to a keyed
-stream, the result of which is a `DataStream<Tuple3<Long, Long, Float>>` (the same kind of stream
-produced by the implementation that uses Flink's built-in time windows).
+在这个代码片段中,一个名为 `PseudoWindow` 的 `KeyedProcessFunction` 被应用于 KeyedStream ,

Review comment:
       ```suggestion
   在这个代码片段中,一个名为 `PseudoWindow` 的 `KeyedProcessFunction` 被应用于 KeyedStream,
   ```

##########
File path: docs/training/event_driven.zh.md
##########
@@ -106,21 +104,20 @@ public static class PseudoWindow extends
 }
 {% endhighlight %}
 
-Things to be aware of:
+注意事项:
 
-* There are several types of ProcessFunctions -- this is a `KeyedProcessFunction`, but there are also
-  `CoProcessFunctions`, `BroadcastProcessFunctions`, etc. 
+* 有几种类型的 ProcessFunctions -- 不仅包括 `KeyedProcessFunction`, 还包括
+  `CoProcessFunctions`、 `BroadcastProcessFunctions` 等. 

Review comment:
       ```suggestion
     `CoProcessFunctions`、`BroadcastProcessFunctions` 等. 
   ```

##########
File path: docs/training/event_driven.zh.md
##########
@@ -106,21 +104,20 @@ public static class PseudoWindow extends
 }
 {% endhighlight %}
 
-Things to be aware of:
+注意事项:
 
-* There are several types of ProcessFunctions -- this is a `KeyedProcessFunction`, but there are also
-  `CoProcessFunctions`, `BroadcastProcessFunctions`, etc. 
+* 有几种类型的 ProcessFunctions -- 不仅包括 `KeyedProcessFunction`, 还包括

Review comment:
       ```suggestion
   * 有几种类型的 ProcessFunctions -- 不仅包括 `KeyedProcessFunction`,还包括
   ```

##########
File path: docs/training/event_driven.zh.md
##########
@@ -136,13 +133,12 @@ public void open(Configuration conf) {
 }
 {% endhighlight %}
 
-Because the fare events can arrive out of order, it will sometimes be necessary to process events
-for one hour before having finished computing the results for the previous hour. In fact, if the
-watermarking delay is much longer than the window length, then there may be many windows open
-simultaneously, rather than just two. This implementation supports this by using a `MapState` that
-maps the timestamp for the end of each window to the sum of the tips for that window.
+由于票价事件(fare-event)可能会乱序到达,有时需要在计算完前一小时的结果之前处理一小时的事件。
+实际上,如果 Watermark 延迟比窗口长度长得多,则可能有多个窗口同时打开,而不仅仅是两个。
+此实现通过使用 `MapState` 来支持处理这一点,该 `MapState` 将每个窗口的结束时间戳映射到该窗口的 tips 

Review comment:
       这里 tips 是不是翻译会更好一些

##########
File path: docs/training/event_driven.zh.md
##########
@@ -202,52 +196,48 @@ public void onTimer(
 }
 {% endhighlight %}
 
-Observations:
+观察:
 
-* The `OnTimerContext context` passed in to `onTimer` can be used to determine the current key.
+* 传递给 `onTimer` 的 `OnTimerContext context` 可用于确定当前 key。
 
-* Our pseudo-windows are being triggered when the current watermark reaches the end of each hour, at
-  which point `onTimer` is called. This onTimer method removes the related entry from `sumOfTips`,
-  which has the effect of making it impossible to accommodate late events. This is the equivalent of
-  setting the allowedLateness to zero when working with Flink's time windows.
+* 我们的 pseudo-windows 在当前 Watermark 到达每小时结束时触发,此时调用 `onTimer`。
+  这个 `onTimer` 方法从 `sumOfTips` 中删除相关的条目,这样做的效果是不可能容纳延迟的事件。
+  这相当于在使用 Flink 的时间窗口时将 allowedLateness 设置为零。
 
-### Performance Considerations
+### 性能考虑
 
-Flink provides `MapState` and `ListState` types that are optimized for RocksDB. Where possible,
-these should be used instead of a `ValueState` object holding some sort of collection. The RocksDB
-state backend can append to `ListState` without going through (de)serialization, and for `MapState`, each
-key/value pair is a separate RocksDB object, so `MapState` can be efficiently accessed and updated.
+在可能的情况下,应该使用这些对象,而不是持有某种集合的 `ValueState` 对象。

Review comment:
       这个地方可以优化下,现在读起来,会让人感觉很疑惑“这些对象是啥”?
   
   翻译成“在相对于 `ValueState`,更建议使用 `MapState` 和 `ListState`,因为使用 RocksDBStateBackend 的情况下,`MapState` 和 `ListState` 比 `ValueState` 性能更好”是否会好一些呢?
   
   然后再加上 ListState 和 MapState 为什么更好的翻译

##########
File path: docs/training/event_driven.zh.md
##########
@@ -269,38 +259,35 @@ SingleOutputStreamOperator hourlyTips = fares
 hourlyTips.getSideOutput(lateFares).print();
 {% endhighlight %}
 
-Alternatively, you can use two OutputTags with the
-same name to refer to the same side output, but if you do, they must have the same type.
+或者,可以使用两个同名的 OutputTag 来引用同一个旁路输出,但如果这样做,它们必须具有相同的类型。
 
 {% top %}
 
-## Closing Remarks
+## 结语
 
-In this example you have seen how a `ProcessFunction` can be used to reimplement a straightforward time
-window. Of course, if Flink's built-in windowing API meets your needs, by all means, go ahead and
-use it. But if you find yourself considering doing something contorted with Flink's windows, don't
-be afraid to roll your own.
+在本例中,你已经了解了如何使用 `ProcessFunction` 重新实现一个简单的时间窗口。
+当然,如果 Flink 内置的窗口 API 能够满足你的开发需求,那么一定要优先使用它。
+但如果你发现自己在考虑用 Flink 的窗口做些错综复杂的事情,不要害怕自己动手。
 
-Also, `ProcessFunctions` are useful for many other use cases beyond computing analytics. The hands-on
-exercise below provides an example of something completely different.
+此外,`ProcessFunctions` 对于计算分析之外的许多其他用例也很有用。
+下面的实践练习提供了一个完全不同的例子。
 
-Another common use case for ProcessFunctions is for expiring stale state. If you think back to the
-[Rides and Fares Exercise](https://github.com/apache/flink-training/tree/{% if site.is_stable %}release-{{ site.version_title }}{% else %}master{% endif %}/rides-and-fares),
-where a `RichCoFlatMapFunction` is used to compute a simple join, the sample solution assumes that
-the TaxiRides and TaxiFares are perfectly matched, one-to-one for each `rideId`. If an event is lost,
-the other event for the same `rideId` will be held in state forever. This could instead be implemented
-as a `KeyedCoProcessFunction`, and a timer could be used to detect and clear any stale state.
+ProcessFunctions 的另一个常见用例是过期过时 State。如果你回想一下
+[Rides and Fares Exercise](https://github.com/apache/flink-training/tree/{% if site.is_stable %}release-{{ site.version_title }}{% else %}master{% endif %}/rides-and-fares),
+其中使用 `RichCoFlatMapFunction` 来计算简单 Join,那么示例解决方案假设 TaxiRides 和 TaxiFares 
+完全匹配,每个 `rideId` 一对一。如果某个事件丢失,则同一 `rideId` 的另一个事件将永远保持 State。

Review comment:
       “每个 `rideId` 一对一” 建议再补充一下,什么东西一对一,现在的描述中,会让人比秒疑惑
   “则同一 `rideId` 的另一个事件将永远保持 State” 改成“则同一 `rideId` 的另一个事件对 State 则永远不会被清理掉” 是否会更好一些呢?

##########
File path: docs/training/event_driven.zh.md
##########
@@ -106,21 +104,20 @@ public static class PseudoWindow extends
 }
 {% endhighlight %}
 
-Things to be aware of:
+注意事项:
 
-* There are several types of ProcessFunctions -- this is a `KeyedProcessFunction`, but there are also
-  `CoProcessFunctions`, `BroadcastProcessFunctions`, etc. 
+* 有几种类型的 ProcessFunctions -- 不仅包括 `KeyedProcessFunction`, 还包括
+  `CoProcessFunctions`、 `BroadcastProcessFunctions` 等. 
 
-* A `KeyedProcessFunction` is a kind of `RichFunction`. Being a `RichFunction`, it has access to the `open`
-  and `getRuntimeContext` methods needed for working with managed keyed state.
+* `KeyedProcessFunction` 是一种 `RichFunction`。作为 `RichFunction`,它可以访问使用 Managed Keyed State 所需的 `open`
+  和 `getRuntimeContext` 方法。
 
-* There are two callbacks to implement: `processElement` and `onTimer`. `processElement` is called
-  with each incoming event; `onTimer` is called when timers fire. These can be either event time or
-  processing time timers. Both `processElement` and `onTimer` are provided with a context object
-  that can be used to interact with a `TimerService` (among other things). Both callbacks are also
-  passed a `Collector` that can be used to emit results.
+* 有两个回调方法须要实现: `processElement` 和 `onTimer`。`processElement` 与每个传入事件一起调用;
+  当计时器触发时调用 `onTimer`。它们可以是事件时间(event time)timer,也可以是处理时间(processing time)timer。
+  `processElement` 和 `onTimer` 都提供了一个上下文对象,该对象可用于与 `TimerService` 交互(除其他外)。
+  这两个回调还传递了一个可用于发出结果的 `Collector`。
 
-#### The `open()` method
+#### `open()` 方法
 
 {% highlight java %}
 // Keyed, managed state, with an entry for each window, keyed by the window's end time.

Review comment:
       这里的注释能否也翻译一下呢

##########
File path: docs/training/event_driven.zh.md
##########
@@ -106,21 +104,20 @@ public static class PseudoWindow extends
 }
 {% endhighlight %}
 
-Things to be aware of:
+注意事项:
 
-* There are several types of ProcessFunctions -- this is a `KeyedProcessFunction`, but there are also
-  `CoProcessFunctions`, `BroadcastProcessFunctions`, etc. 
+* 有几种类型的 ProcessFunctions -- 不仅包括 `KeyedProcessFunction`, 还包括
+  `CoProcessFunctions`、 `BroadcastProcessFunctions` 等. 
 
-* A `KeyedProcessFunction` is a kind of `RichFunction`. Being a `RichFunction`, it has access to the `open`
-  and `getRuntimeContext` methods needed for working with managed keyed state.
+* `KeyedProcessFunction` 是一种 `RichFunction`。作为 `RichFunction`,它可以访问使用 Managed Keyed State 所需的 `open`
+  和 `getRuntimeContext` 方法。
 
-* There are two callbacks to implement: `processElement` and `onTimer`. `processElement` is called
-  with each incoming event; `onTimer` is called when timers fire. These can be either event time or
-  processing time timers. Both `processElement` and `onTimer` are provided with a context object
-  that can be used to interact with a `TimerService` (among other things). Both callbacks are also
-  passed a `Collector` that can be used to emit results.
+* 有两个回调方法须要实现: `processElement` 和 `onTimer`。`processElement` 与每个传入事件一起调用;

Review comment:
       ```suggestion
   * 有两个回调方法须要实现:`processElement` 和 `onTimer`。`processElement` 与每个传入事件一起调用;
   ```
   
   ”`processElement` 与每个传入事件一起调用;“这个有更好的翻译吗?这里是说每次输入都会调用 processElement 这个函数

##########
File path: docs/training/event_driven.zh.md
##########
@@ -202,52 +196,48 @@ public void onTimer(
 }
 {% endhighlight %}
 
-Observations:
+观察:
 
-* The `OnTimerContext context` passed in to `onTimer` can be used to determine the current key.
+* 传递给 `onTimer` 的 `OnTimerContext context` 可用于确定当前 key。
 
-* Our pseudo-windows are being triggered when the current watermark reaches the end of each hour, at
-  which point `onTimer` is called. This onTimer method removes the related entry from `sumOfTips`,
-  which has the effect of making it impossible to accommodate late events. This is the equivalent of
-  setting the allowedLateness to zero when working with Flink's time windows.
+* 我们的 pseudo-windows 在当前 Watermark 到达每小时结束时触发,此时调用 `onTimer`。
+  这个 `onTimer` 方法从 `sumOfTips` 中删除相关的条目,这样做的效果是不可能容纳延迟的事件。
+  这相当于在使用 Flink 的时间窗口时将 allowedLateness 设置为零。
 
-### Performance Considerations
+### 性能考虑
 
-Flink provides `MapState` and `ListState` types that are optimized for RocksDB. Where possible,
-these should be used instead of a `ValueState` object holding some sort of collection. The RocksDB
-state backend can append to `ListState` without going through (de)serialization, and for `MapState`, each
-key/value pair is a separate RocksDB object, so `MapState` can be efficiently accessed and updated.
+在可能的情况下,应该使用这些对象,而不是持有某种集合的 `ValueState` 对象。
+Flink 提供了为 RocksDB 优化的 `MapState` 和 `ListState` 类型。
+在可能的情况下,应该使用这些对象,而不是持有某种集合的 `ValueState` 对象。
+RocksDB State Backend 可以附加到 `ListState`,而无需进行(反)序列化,
+对于 `MapState`,每个 key/value 都是一个单独的 RocksDB 对象,因此可以有效地访问和更新 `MapState`。
 
 {% top %}
 
 ## Side Outputs
 
-### Introduction
+### 介绍
 
-There are several good reasons to want to have more than one output stream from a Flink operator, such as reporting:
+有几个很好的理由希望从 Flink 算子获得多个输出流,如下报告条目:
 
-* exceptions
-* malformed events
-* late events
-* operational alerts, such as timed-out connections to external services
+* 异常情况(exceptions)
+* 格式错误的事件(malformed events)
+* 迟到的事件(late events)
+* operator 告警(operational alerts),如与外部服务的连接超时
 
-Side outputs are a convenient way to do this. Beyond error reporting, side outputs are also
-a good way to implement an n-way split of a stream.
+旁路输出(Side outputs)是一种方便的方法。除了错误报告之外,旁路输出也是实现流的 n 路分割的好方法。
 
-### Example
+### 示例
 
-You are now in a position to do something with the late events that were ignored in the previous
-section.
+现在你可以对上一节中忽略的延迟事件执行某些操作。
 
-A side output channel is associated with an `OutputTag<T>`. These tags have generic types that
-correspond to the type of the side output's `DataStream`, and they have names.
+Side output channel 与 `OutputTag<T>` 相关联。这些标记具有与 Side output 的 `DataStream` 类型相对应的泛型类型,并且它们具有名称。

Review comment:
       “这些标记具有与 Side output 的 `DataStream` 类型相对应的泛型类型,并且它们具有名称。” 如果翻译成 “这些标记拥有自己的名称,并与对应 `DataStream` 类型一致”是否会好一些呢?
   现在的翻译中,最后一句“并且它们具有名称”感觉有点奇怪

##########
File path: docs/training/event_driven.zh.md
##########
@@ -202,52 +196,48 @@ public void onTimer(
 }
 {% endhighlight %}
 
-Observations:
+观察:

Review comment:
       这个有更好的翻译吗?现在这样显得优点突兀

##########
File path: docs/training/event_driven.zh.md
##########
@@ -136,13 +133,12 @@ public void open(Configuration conf) {
 }
 {% endhighlight %}
 
-Because the fare events can arrive out of order, it will sometimes be necessary to process events
-for one hour before having finished computing the results for the previous hour. In fact, if the
-watermarking delay is much longer than the window length, then there may be many windows open
-simultaneously, rather than just two. This implementation supports this by using a `MapState` that
-maps the timestamp for the end of each window to the sum of the tips for that window.
+由于票价事件(fare-event)可能会乱序到达,有时需要在计算完前一小时的结果之前处理一小时的事件。

Review comment:
       这里说的意思是指“由于乱序,可能需要在输出前一小时结果前,处理下一小时的数据” -- 因为这样能够保证“乱序造成的迟到数据”得到正确处理(放到前一个小时中)
   这里可以重新组织下语言看怎么描述更好一些

##########
File path: docs/training/event_driven.zh.md
##########
@@ -106,21 +104,20 @@ public static class PseudoWindow extends
 }
 {% endhighlight %}
 
-Things to be aware of:
+注意事项:
 
-* There are several types of ProcessFunctions -- this is a `KeyedProcessFunction`, but there are also
-  `CoProcessFunctions`, `BroadcastProcessFunctions`, etc. 
+* 有几种类型的 ProcessFunctions -- 不仅包括 `KeyedProcessFunction`, 还包括
+  `CoProcessFunctions`、 `BroadcastProcessFunctions` 等. 
 
-* A `KeyedProcessFunction` is a kind of `RichFunction`. Being a `RichFunction`, it has access to the `open`
-  and `getRuntimeContext` methods needed for working with managed keyed state.
+* `KeyedProcessFunction` 是一种 `RichFunction`。作为 `RichFunction`,它可以访问使用 Managed Keyed State 所需的 `open`
+  和 `getRuntimeContext` 方法。
 
-* There are two callbacks to implement: `processElement` and `onTimer`. `processElement` is called
-  with each incoming event; `onTimer` is called when timers fire. These can be either event time or
-  processing time timers. Both `processElement` and `onTimer` are provided with a context object
-  that can be used to interact with a `TimerService` (among other things). Both callbacks are also
-  passed a `Collector` that can be used to emit results.
+* 有两个回调方法须要实现: `processElement` 和 `onTimer`。`processElement` 与每个传入事件一起调用;
+  当计时器触发时调用 `onTimer`。它们可以是事件时间(event time)timer,也可以是处理时间(processing time)timer。

Review comment:
       这里如果翻译成 “基于事件时间(event time)的 timer,基于处理时间(processing time)的 timer”会更好一些吗?

##########
File path: docs/training/event_driven.zh.md
##########
@@ -106,21 +104,20 @@ public static class PseudoWindow extends
 }
 {% endhighlight %}
 
-Things to be aware of:
+注意事项:
 
-* There are several types of ProcessFunctions -- this is a `KeyedProcessFunction`, but there are also
-  `CoProcessFunctions`, `BroadcastProcessFunctions`, etc. 
+* 有几种类型的 ProcessFunctions -- 不仅包括 `KeyedProcessFunction`, 还包括
+  `CoProcessFunctions`、 `BroadcastProcessFunctions` 等. 
 
-* A `KeyedProcessFunction` is a kind of `RichFunction`. Being a `RichFunction`, it has access to the `open`
-  and `getRuntimeContext` methods needed for working with managed keyed state.
+* `KeyedProcessFunction` 是一种 `RichFunction`。作为 `RichFunction`,它可以访问使用 Managed Keyed State 所需的 `open`
+  和 `getRuntimeContext` 方法。
 
-* There are two callbacks to implement: `processElement` and `onTimer`. `processElement` is called
-  with each incoming event; `onTimer` is called when timers fire. These can be either event time or
-  processing time timers. Both `processElement` and `onTimer` are provided with a context object
-  that can be used to interact with a `TimerService` (among other things). Both callbacks are also
-  passed a `Collector` that can be used to emit results.
+* 有两个回调方法须要实现: `processElement` 和 `onTimer`。`processElement` 与每个传入事件一起调用;
+  当计时器触发时调用 `onTimer`。它们可以是事件时间(event time)timer,也可以是处理时间(processing time)timer。
+  `processElement` 和 `onTimer` 都提供了一个上下文对象,该对象可用于与 `TimerService` 交互(除其他外)。

Review comment:
       “除其他外” 感觉怪怪的,暂时给不出一个更好的翻译,可以看其他人有没有更好的建议

##########
File path: docs/training/event_driven.zh.md
##########
@@ -269,38 +259,35 @@ SingleOutputStreamOperator hourlyTips = fares
 hourlyTips.getSideOutput(lateFares).print();
 {% endhighlight %}
 
-Alternatively, you can use two OutputTags with the
-same name to refer to the same side output, but if you do, they must have the same type.
+或者,可以使用两个同名的 OutputTag 来引用同一个旁路输出,但如果这样做,它们必须具有相同的类型。
 
 {% top %}
 
-## Closing Remarks
+## 结语
 
-In this example you have seen how a `ProcessFunction` can be used to reimplement a straightforward time
-window. Of course, if Flink's built-in windowing API meets your needs, by all means, go ahead and
-use it. But if you find yourself considering doing something contorted with Flink's windows, don't
-be afraid to roll your own.
+在本例中,你已经了解了如何使用 `ProcessFunction` 重新实现一个简单的时间窗口。
+当然,如果 Flink 内置的窗口 API 能够满足你的开发需求,那么一定要优先使用它。
+但如果你发现自己在考虑用 Flink 的窗口做些错综复杂的事情,不要害怕自己动手。
 
-Also, `ProcessFunctions` are useful for many other use cases beyond computing analytics. The hands-on
-exercise below provides an example of something completely different.
+此外,`ProcessFunctions` 对于计算分析之外的许多其他用例也很有用。
+下面的实践练习提供了一个完全不同的例子。
 
-Another common use case for ProcessFunctions is for expiring stale state. If you think back to the
-[Rides and Fares Exercise](https://github.com/apache/flink-training/tree/{% if site.is_stable %}release-{{ site.version_title }}{% else %}master{% endif %}/rides-and-fares),
-where a `RichCoFlatMapFunction` is used to compute a simple join, the sample solution assumes that
-the TaxiRides and TaxiFares are perfectly matched, one-to-one for each `rideId`. If an event is lost,
-the other event for the same `rideId` will be held in state forever. This could instead be implemented
-as a `KeyedCoProcessFunction`, and a timer could be used to detect and clear any stale state.
+ProcessFunctions 的另一个常见用例是过期过时 State。如果你回想一下

Review comment:
       这里将“过期”翻译成“清理”会更好一些吗?

##########
File path: docs/training/event_driven.zh.md
##########
@@ -173,18 +169,16 @@ public void processElement(
 }
 {% endhighlight %}
 
-Things to consider:
+需要考虑的事项:
 
-* What happens with late events? Events that are behind the watermark (i.e., late) are being
-  dropped. If you want to do something better than this, consider using a side output, which is
-  explained in the [next section]({% link training/event_driven.zh.md
-  %}#side-outputs).
+* 延迟的事件怎么办?watermark 后面的事件(即延迟的)正在被删除。
+  如果你想做一些比这更高级的操作,可以考虑使用旁路输出(Side outputs),这将在
+  [下一节]({% link training/event_driven.zh.md%}#side-outputs)中解释。
 
-* This example uses a `MapState` where the keys are timestamps, and sets a `Timer` for that same
-  timestamp. This is a common pattern; it makes it easy and efficient to lookup relevant information
-  when the timer fires.
+* 本例使用一个 `MapState`,其中 keys 是时间戳( timestamp ),并为同一时间戳设置一个 Timer。

Review comment:
       ```suggestion
   * 本例使用一个 `MapState`,其中 keys 是时间戳(timestamp),并为同一时间戳设置一个 Timer。
   ```




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org