在巨大的 .ndjson 文件上验证(并报告错误!)的最快方法是什么?
What is the fastest way to validate (and report errors!) on a huge .ndjson file?
我有一个 42 GB 的文件,其中每一行都应该是一个 JSON 对象。我有理由相信这个文件中的某处存在语法错误。
找到有错误的行的最快方法是什么?
一些约束:
- 该行大约有 21 000 行,因此其中一些非常(!!!)长
- 我不想只找到第一个错误;我想找到 所有 有错误的行
- 我希望输出至少向我显示违规行的行号(或行内容)
- 我正在 Windows 或(最好)Ubuntu(通过 WSL2)
此脚本的前 1000 行 (1.2 GB) 花费了大约 1 分钟,目前 运行 在完整文件中:
#!/bin/bash
i=$((0))
time (
while read line; do
i=$((i + 1))
echo "$line" | jq > /dev/null || echo error on line $i &
done < blob_cache_update-20200812T034630.ndjson
wait
echo processed $i rows
)
我该怎么做才能让它更快?
(是的,尝试使用其他语言是一种选择,假设安装所需的工具和实施检查器都足够简单,不会完全掩盖 运行 检查器。)
显然,要做的第一件事是切换到 Python。
这种(single-threaded!)方法在同一个文件上花费了 5 分钟:
#!/bin/env python
import json
import time
# FILE = 'blob_cache_update-sample.ndjson'
FILE = 'blob_cache_update-20200812T034630.ndjson'
start = time.perf_counter()
with open(FILE, 'r') as f:
for i, line in enumerate(f):
if i % 1000 == 0:
print(f'{i}: {time.perf_counter() - start} s')
try:
parsed = json.loads(line)
assert "blob" in parsed
assert "sha" in parsed
assert "size" in parsed
except:
print(f'error on line {i}')
end = time.perf_counter()
print(f"it took {end-start} s")
我有一个 42 GB 的文件,其中每一行都应该是一个 JSON 对象。我有理由相信这个文件中的某处存在语法错误。
找到有错误的行的最快方法是什么?
一些约束:
- 该行大约有 21 000 行,因此其中一些非常(!!!)长
- 我不想只找到第一个错误;我想找到 所有 有错误的行
- 我希望输出至少向我显示违规行的行号(或行内容)
- 我正在 Windows 或(最好)Ubuntu(通过 WSL2)
此脚本的前 1000 行 (1.2 GB) 花费了大约 1 分钟,目前 运行 在完整文件中:
#!/bin/bash
i=$((0))
time (
while read line; do
i=$((i + 1))
echo "$line" | jq > /dev/null || echo error on line $i &
done < blob_cache_update-20200812T034630.ndjson
wait
echo processed $i rows
)
我该怎么做才能让它更快?
(是的,尝试使用其他语言是一种选择,假设安装所需的工具和实施检查器都足够简单,不会完全掩盖 运行 检查器。)
显然,要做的第一件事是切换到 Python。
这种(single-threaded!)方法在同一个文件上花费了 5 分钟:
#!/bin/env python
import json
import time
# FILE = 'blob_cache_update-sample.ndjson'
FILE = 'blob_cache_update-20200812T034630.ndjson'
start = time.perf_counter()
with open(FILE, 'r') as f:
for i, line in enumerate(f):
if i % 1000 == 0:
print(f'{i}: {time.perf_counter() - start} s')
try:
parsed = json.loads(line)
assert "blob" in parsed
assert "sha" in parsed
assert "size" in parsed
except:
print(f'error on line {i}')
end = time.perf_counter()
print(f"it took {end-start} s")