← 中文资源

简体中文版本

数据新鲜度

数据新鲜度衡量数据集有多新:世界发生变化到消费方看到它之间的滞后。

阅读英文原文

概念定义

数据新鲜度是某数据集最新记录相对于它代表的事件的“年龄”。它以 SLA 表述——例如“订单落后源不超过 15 分钟”——并作为实际测量而非承诺来监控。它与延迟不同:延迟是产生一次更新所需的时间,而新鲜度是消费方读取时整张表的陈旧程度。

为什么重要

用一小时前的事件打分的欺诈模型,或只显示昨日汇总的看板,都可能理直气壮地给出错误结论。新鲜度把“流水线跑过了”变成“数据对这个决策足够新”,而后者才是消费方真正依赖的性质。它也设定了正确预期:并非每张表都要秒级,明确目标可以防止过度工程。

如何治理

为每个数据集按其决策绑定一个新鲜度目标,并在流水线中测量最新记录的年龄。对数据本身告警而不只对任务告警,好让“成功但零写入”的运行也能暴露。用增量摄取替代全量重载来缩短滞后,当某张表不可避免地落后时优雅降级——把结果标记为陈旧,而不是当成最新数据提供。

代码示例

<table>
  <caption>
    Employee Directory - Q1 2025
  </caption>

  <colgroup>
    <col class="name-col">
    <col class="dept-col">
    <col class="role-col">
    <col class="salary-col">
  </colgroup>

  <thead>
    <tr>
      <th scope="col">Name</th>
      <th scope="col">Department</th>
      <th scope="col">Role</th>
      <th scope="col" class="numeric">Salary</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <th scope="row">Alice Johnson</th>
      <td>Engineering</td>
      <td>Senior Developer</td>
      <td class="numeric">$95,000</td>
    </tr>
    <tr>
      <th scope="row">Bob Smith</th>
      <td>Marketing</td>
      <td>Manager</td>
      <td class="numeric">$85,000</td>
    </tr>
    <tr>
      <th scope="row">Carol Davis</th>
      <td>Engineering</td>
      <td>Team Lead</td>
      <td class="numeric">$110,000</td>
    </tr>
  </tbody>

  <tfoot>
    <tr>
      <th scope="row" colspan="3">Average Salary</th>
      <td class="numeric">$96,667</td>
    </tr>
  </tfoot>
</table>

<style>
  table { border-collapse: collapse; width: 100%; }
  th, td { padding: 0.75rem; text-align: left; border-bottom: 1px solid #ddd; }
  .numeric { text-align: right; }
  caption { font-weight: bold; margin-bottom: 0.5rem; }
</style>
import java.util.List;
import java.util.Objects;

public class RecordClasses {

    public record Point(int x, int y) {
        public Point {
            if (x < 0 || y < 0) {
                throw new IllegalArgumentException(
                    "Coordinates must be non-negative");
            }
        }

        public double distanceTo(Point other) {
            return Math.sqrt(
                Math.pow(x - other.x, 2) +
                Math.pow(y - other.y, 2)
            );
        }
    }

    public record Rectangle(Point topLeft, Point bottomRight) {
        public int width() {
            return bottomRight.x() - topLeft.x();
        }
        public int height() {
            return bottomRight.y() - topLeft.y();
        }
        public int area() {
            return width() * height();
        }
    }

    public record Employee(
        String name,
        String department,
        double salary,
        List<String> skills
    ) {
        public Employee {
            Objects.requireNonNull(name);
            skills = List.copyOf(skills);
        }
    }

    public static void main(String[] args) {
        Point p1 = new Point(0, 0);
        Point p2 = new Point(3, 4);
        System.out.println("Distance: " + p1.distanceTo(p2));

        Rectangle rect = new Rectangle(p1, p2);
        System.out.println("Area: " + rect.area());

        Employee emp = new Employee("Alice", "Engineering", 95000,
            List.of("Java", "Python", "SQL"));
        System.out.println(emp);
    }
}