如何在Ruby中从文件行提取数据?处理千万行数据遇问题
解决1000万行MongoDB导出数据的id提取问题
看起来你遇到的是MongoDB导出的非标准JSON格式问题——因为ObjectId不是合法的JSON类型,所以直接用JSON.parse会报错。针对1000万行的大数据量,我给你两个实用的解决方案,兼顾性能和稳健性:
方案一:精准正则匹配(性能最优)
因为你的每行格式非常固定,"id"后面跟着的是整数,我们可以用专门匹配数字的正则直接提取,完全避免JSON解析的开销:
# 提前编译正则并冻结,提升循环内的匹配速度 ID_PATTERN = /"id" : (\d+)/.freeze # 用File.foreach逐行读取,避免一次性加载大文件到内存 File.foreach('your_large_file.txt').with_index do |line, idx| # 跳过空行,减少无效处理 next if line.strip.empty? if match_result = ID_PATTERN.match(line) listing_id = match_result[1].to_i # 这里写你的id处理逻辑 else # 记录异常行,方便后续排查 puts "Warning: Invalid line format at index #{idx}: #{line.strip}" end end
这个方法的核心是用(\d+)精准匹配"id" :后面的所有数字,不会把末尾的 }包含进来,而且逐行读取的方式内存占用极低,适合处理千万级别的大文件。
方案二:修复JSON格式后解析(稳健性更强)
如果你之后可能需要提取其他字段,或者担心格式有微小变动,我们可以先把非标准的ObjectId替换成合法JSON字符串,再用JSON.parse解析:
require 'json' # 替换ObjectId为JSON合法字符串的正则 FIX_JSON_PATTERN = /ObjectId\("([^"]+)"\)/.freeze File.foreach('your_large_file.txt').with_index do |line, idx| next if line.strip.empty? begin # 把ObjectId("xxx")替换成"xxx",让整行变成合法JSON fixed_line = line.gsub(FIX_JSON_PATTERN, '"\1"') data = JSON.parse(fixed_line) listing_id = data.fetch("id") # 处理逻辑 rescue JSON::ParserError => e puts "Error parsing line #{idx}: #{e.message} | Line content: #{line.strip}" end end
这个方法的优势是能完整解析整行数据,后续要提取其他字段(比如_id的字符串值)也很方便,唯一的小缺点是比纯正则多了字符串替换和JSON解析的步骤,性能稍逊,但对于千万级别数据来说依然足够高效。
额外优化建议
- 尽量避免用
File.readlines一次性读取整个文件,会占用大量内存;File.foreach是逐行读取,内存友好。 - 正则表达式提前编译并冻结(
.freeze),可以避免循环内重复编译正则的开销。 - 加上空行判断和异常捕获,能让程序在遇到格式异常的行时不会崩溃,还能记录问题方便排查。
内容的提问来源于stack exchange,提问作者toHo
相关产品推荐
相关产品推荐

