用 Python 标准库读取 JSONL:别让重复记录和坏行把统计带偏

举报
yd_283005936 发表于 2026/11/06 09:00:50 2026/11/06
【摘要】 用Python标准库读取JSONL任务快照:按稳定标识去重,区分解析错误与无效结构,保留异常行号,并明确追加顺序、时间戳和内存边界。附可直接运行的固定样例和实际验证结果。

JSONL 每行保存一个 JSON 对象,适合持续追加日志、任务结果和数据导出。真正开始统计时,却常常遇到两类问题:同一个任务写了多次,文件末尾还有一条没有写完的记录。直接数行会高估任务数量;一遇到解析错误就退出,又会让整份报告无法生成。

先明确统计对象:如果关心“发生过几次事件”,每行都应该保留;如果关心“每个任务的最新状态”,则需要按稳定标识去重。下面采用第二种口径,用 id 作为标识,让文件中最后一条有效记录覆盖前面的状态。

一个可以直接运行的最小实现

import json
from io import StringIO


def snapshot(lines):
    latest, skipped = {}, []
    for number, line in enumerate(lines, 1):
        if not line.strip():
            continue
        try:
            row = json.loads(line)
        except json.JSONDecodeError:
            skipped.append(number)
            continue
        if not isinstance(row, dict) or not isinstance(row.get('id'), str) or not row['id']:
            skipped.append(number)
            continue
        latest[row['id']] = row
    return latest, skipped


# 明确标注的测试数据,不是生产日志
sample = StringIO(
    '{"id":"A","status":"pending"}\n'
    '{"id":"B","status":"done"}\n'
    '{"id":"A","status":"done"}\n'
    '{"id":\n'
    '[]\n'
)
rows, skipped = snapshot(sample)
assert set(rows) == {'A', 'B'}
assert rows['A']['status'] == 'done'
assert skipped == [4, 5]
print(len(rows), skipped)

示例输出为 2 [4, 5]:三个有效对象对应两个任务,第四行是残缺 JSON,第五行虽然是合法 JSON,却不是约定的对象结构。解析成功与数据有效,是两件不同的事。读取真实文件时,改成 with open('records.jsonl', encoding='utf-8') as f: rows, skipped = snapshot(f) 即可。

为什么要留下坏行行号

跳过坏行不等于把问题藏起来。报告应同时列出有效任务数和异常行数,必要时回看对应原文。持续写入的文件可能恰好被读到半行,下次重新读取时它可能恢复完整;如果中间位置反复出现坏行,则应检查写入方,而不是长期忽略。

只捕获 JSONDecodeError 也很重要。文件打不开、编码不匹配或程序自身出错,不应该被一个宽泛的 except Exception 伪装成“数据为空”。错误是否可忽略,必须由明确的数据约定决定。

最后一条,并不总是最新时间

这个实现相信文件追加顺序。如果把多台机器的日志拼在一起,最后出现的记录未必时间最新,此时要按时间戳或递增版本选择。还应先约定时间戳单位:秒和毫秒不能混用,按自然日汇总则应显式选择时区,避免午夜附近的数据被分错日期。

使用边界

逐行遍历避免把整个文件一次性读入内存,但 latest 仍保存每个唯一任务,空间开销随任务数增长。普通日志先用标准库就够;当唯一标识达到无法放进内存的规模,再迁移到 SQLite,利用主键和更新语句维护快照。

本地验证覆盖了重复标识、残缺 JSON、非对象结构、缺失标识、空行和空输入。统计脚本不需要复杂框架,但至少应留下一个能运行的固定样例:先把口径验证正确,再讨论速度。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。