跳到主要内容
一百八十五条数据,一个时间戳

一百八十五条数据,一个时间戳

原石
原石

· 阅读约 4 分钟

先把数据贴上:

Wok N Go    Dallas    8.99    2026-08-13

店名,城市,价格,验证日期。这是 CheapFoodMap 上的一行。这个网站只干一件事:把十美元以下的平价饭馆标在地图上。休斯顿六十七家,芝加哥五十九家,费城五十九家——三个城市加起来一百八十五条,达拉斯还没往里算。

一百八十五条。我手头有些项目的依赖清单都比这个长。

我第一反应是,这也太土了。页面上能做的操作就一个:筛选,按质量,或者按投票数。像零几年的黄页。第二反应来得慢一点:土得对。

这个产品的全部领域模型,一个 struct 装得下:

struct spot {
    char  *name;
    char  *city;
    double price;        /* verified */
    time_t verified_at;
    int    votes;
};

五个字段。没有外键,没有继承层级,没有“以后要支持视频点评”预留的坑。全量塞进内存,比一张缩略图还小。至于那个筛选功能,在 C 里就是一个比较函数:

int by_votes(const void *a, const void *b) {
    return ((const struct spot *)b)->votes
         - ((const struct spot *)a)->votes;
}

这个函数我在草稿里写了三遍。第一遍想搞字段参数化,第二遍加了个稳定性说明,第三遍全删了,就这五行最顺眼。评审会上能聊一个季度的功能,落地是一次 qsort。两百个点的排序,任何更聪明的结构都是白搭。

换一个正经团队来做这个需求,会得到什么。立项,招人,然后是账号体系、评论、图片审核、App、推送、“发现页”,最好再来一套个性化推荐。一年以后,地图上还是那两百个点,但每个点后面挂了七张表和三个服务。

推荐什么?一百八十五条数据,能排的维度一只手数得过来。推荐系统在这里的唯一产出,是把“按投票排序”从五毫秒做到五十毫秒,顺便让三个人全职维护它。加那层的理由永远是“以后用户多了怎么办”。用户多了再加,是工程;现在就加,是替未来的人预支麻烦。那一层不该存在。

说回开头那行数据。四个字段里,最贵的不是价格,是最后那个日期。

二〇二六年八月十三号。前天。意思是:有一个人,前天,在达拉斯,买了一个八块九毛九的午市碗,然后把这个价格填了回去。这个动作没有任何环节可以外包。价格会烂,通胀、换菜单、老板换了午市策略,一碗饭的价格半衰期也就几个月。这个数是我拍的,别引用。但方向我认:不带日期的价格是噪音,甚至是负资产。你照着去年的价格开二十分钟车过去,油钱都够补差价了。

所以看它的栏目设置:“午餐特价”,“最新发现”。最新发现。它在把“新鲜”本身当内容运营。投票可以刷,价格可以爬,唯独 verified_at 这一列,机器量产不出来。

把话说难听点。今天你让一个 LLM 生成一万个平价餐馆条目,它会给你一万个看起来无比合理的东西:店名通顺,价格合理,坐标落在真实街区上。看起来对。它学过太多看起来对的坏例子。这种数据灌进地图,等于往汤里兑水——总量上去了,你得一口一口尝出哪里是兑的。

生成已经免费了。验证越来越贵。那个前天在达拉斯吃碗的人,价值密度比一整套推荐系统高。这话放在几年前我不敢说这么满,现在敢。

说句题外话。我那个玩具键值存储,最早只有 get 和 set,后来我给每条数据加了过期字段,读的时候顺手查一下:

if (e->expire && e->expire < now)
    return NOT_FOUND;   /* 馊了,就当没有 */

懒删除,不扫全表。当时加这个纯属顺手,现在想想理由是同一个:数据有保质期,馊了的数据比没有数据更坏。一个不带过期时间的缓存值,和一个不带验证日期的菜单价格,是同一种事故。

扯回来。

别问我为什么半夜在研究八块钱的碗 😅。但这个网站确实改了我一个习惯:以前看一个数据产品,先数它有什么功能;现在先找它的时间戳。找不到的,默认整份数据已经死了,只是没人通知它。

以后判断一份数据值不值得信,我只看一件事:它敢不敢把验证日期印在明面上。CheapFoodMap 印了,印在每一条旁边。就冲这个,它那两百个点比很多“智能”地图都干净。

原石
原石

把代码当文章写的系统工程师,以源码立论、单线程式拒绝复杂度。

查看主页 →