You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:使用JavaScript对2800万条字符串去重的可行方案

大体积JSON字符串去重与统计解决方案

JavaScript(Node.js)可行方案

流式读取+Set结构

针对大文件无法一次性加载的问题,采用流式解析结合Set(比普通对象更高效的唯一值存储结构),避免内存溢出:

场景1:JSON为每行一条字符串格式

const fs = require('fs');
const readline = require('readline');

const uniqueSet = new Set();
const outputStream = fs.createWriteStream('unique_output.json');
outputStream.write('[');
let isFirst = true;

// 创建逐行读取接口
const rl = readline.createInterface({
  input: fs.createReadStream('input.json'),
  crlfDelay: Infinity
});

rl.on('line', (line) => {
  // 清理行内的引号、逗号等格式符号
  const str = line.trim().replace(/^"|"|,$/g, '');
  if (!uniqueSet.has(str)) {
    uniqueSet.add(str);
    // 写入输出文件,处理逗号分隔
    if (!isFirst) outputStream.write(',');
    outputStream.write(`"${str}"`);
    isFirst = false;
  }
});

rl.on('close', () => {
  outputStream.write(']');
  outputStream.end();
  console.log(`唯一字符串数量:${uniqueSet.size}`);
});

场景2:JSON为大数组格式(如["a","b",...])

使用JSONStream库流式解析数组元素,避免一次性加载整个数组:

const fs = require('fs');
const JSONStream = require('JSONStream');

const uniqueSet = new Set();
const outputStream = fs.createWriteStream('unique_output.json');
outputStream.write('[');
let isFirst = true;

fs.createReadStream('input.json')
  .pipe(JSONStream.parse('*')) // 解析数组中的每个元素
  .on('data', (str) => {
    if (!uniqueSet.has(str)) {
      uniqueSet.add(str);
      if (!isFirst) outputStream.write(',');
      outputStream.write(JSON.stringify(str));
      isFirst = false;
    }
  })
  .on('end', () => {
    outputStream.write(']');
    outputStream.end();
    console.log(`唯一字符串数量:${uniqueSet.size}`);
  });

安装依赖:npm install jsonstream

注意:若预估2.4亿条唯一值超出内存(单条100字符约占24GB内存),JavaScript方案会受限,需转向磁盘分桶或其他语言方案。

其他语言高效方案

Python 哈希分桶方案(内存不足时首选)

当内存无法容纳所有唯一值时,通过哈希分桶将数据拆分到多个临时文件,再逐个去重合并,分摊内存压力:

import json
import hashlib
import os
import ijson

# 分桶数量,根据内存调整(示例设为100)
BUCKET_NUM = 100
temp_files = {}

# 第一步:流式读取并分桶
for i in range(BUCKET_NUM):
    temp_files[i] = open(f"temp_{i}.txt", "w", encoding="utf-8")

with open("input.json", "r", encoding="utf-8") as f:
    # 流式解析JSON数组中的每个元素
    for str_item in ijson.items(f, "item"):
        # 计算哈希值取模,分配到对应桶
        hash_digest = hashlib.md5(str_item.encode()).hexdigest()
        bucket_idx = int(hash_digest, 16) % BUCKET_NUM
        temp_files[bucket_idx].write(f"{str_item}\n")

# 关闭临时文件
for f in temp_files.values():
    f.close()

# 第二步:逐个桶去重并合并结果
unique_count = 0
with open("unique_output.json", "w", encoding="utf-8") as out_f:
    out_f.write("[")
    is_first = True
    for i in range(BUCKET_NUM):
        temp_path = f"temp_{i}.txt"
        if not os.path.exists(temp_path):
            continue
        unique_in_bucket = set()
        with open(temp_path, "r", encoding="utf-8") as temp_f:
            for line in temp_f:
                s = line.strip()
                if s not in unique_in_bucket:
                    unique_in_bucket.add(s)
                    if not is_first:
                        out_f.write(",")
                    out_f.write(json.dumps(s))
                    is_first = False
                    unique_count += 1
        os.remove(temp_path)
    out_f.write("]")

print(f"唯一字符串数量:{unique_count}")

安装依赖:pip install ijson

Go 高性能流式方案(内存充足时首选)

Go的内存效率和并发特性适合处理超大规模数据,用map[string]struct{}作为轻量去重结构:

package main

import (
	"bufio"
	"encoding/json"
	"fmt"
	"os"
	"strings"
)

func main() {
	inputFile, err := os.Open("input.json")
	if err != nil {
		panic(err)
	}
	defer inputFile.Close()

	outputFile, err := os.Create("unique_output.json")
	if err != nil {
		panic(err)
	}
	defer outputFile.Close()

	writer := bufio.NewWriter(outputFile)
	writer.WriteString("[")
	defer writer.WriteString("]")
	defer writer.Flush()

	uniqueMap := make(map[string]struct{})
	scanner := bufio.NewScanner(inputFile)
	isFirst := true

	// 跳过JSON数组开头的[
	if scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line != "[" {
			panic("输入JSON不是标准数组格式")
		}
	}

	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		// 清理行尾的逗号或]
		line = strings.TrimSuffix(line, ",")
		line = strings.TrimSuffix(line, "]")
		if line == "" {
			continue
		}
		var str string
		if err := json.Unmarshal([]byte(line), &str); err != nil {
			continue
		}
		if _, exists := uniqueMap[str]; !exists {
			uniqueMap[str] = struct{}{}
			if !isFirst {
				writer.WriteString(",")
			}
			jsonStr, _ := json.Marshal(str)
			writer.Write(jsonStr)
			isFirst = false
		}
	}

	if err := scanner.Err(); err != nil {
		panic(err)
	}

	fmt.Printf("唯一字符串数量:%d\n", len(uniqueMap))
}

方案选择建议

  • 内存充足(32GB+):优先选Go方案,其次是Node.js流式+Set方案,性能最优。
  • 内存不足(<32GB):选Python哈希分桶方案,通过磁盘分摊内存压力。

内容的提问来源于stack exchange,提问作者Kirk Ouimet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 14:05:38