在 2G 大小的文件中,找出高频 top100 的单词

1. 把 2G 的文件进行分割成大小为 512KB 小文件,总共得到 2048 个小文件,避免一
次性读入整个文件造成内存不足。
2. 定义一个长度为 2048 的 hash 表数组,用来统计每个小文件中单词出现的频率。
3. 使用多线程并行遍历 2048 个小文件,针对每个单词进行 hash 取模运算分别存储
到长度为 2048 的 hash 表数组中
inthash=Math.abs(word.hashCode() %hashTableSize);
hashTables[hash].merge(word, 1, Integer::sum);
4. 接着再遍历这 2048 个 hash 表,把频率前 100 的单词存入小顶堆中
5. 最后,小顶堆中最终得到的 100 个单词,就是 top 100 了。
这种解决方案的核心思想是将大文件分割为多个小文件,然后采用分治和堆的算法,来
解决这个问题。
 

以下是一个简化的Java实现,来处理大文件,并找出频率最高的前100个单词。请注意,这个实现假设单词之间由空格分隔,并且使用了Java的ConcurrentHashMap来并行处理哈希表,以及PriorityQueue来实现小顶堆。

 

java复制代码

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TopWordsFinder {
private static final int HASH_TABLE_SIZE = 2048;
private static final int TOP_WORDS_COUNT = 100;
public static void main(String[] args) throws IOException {
String largeFilePath = "path/to/large/file.txt"; // 替换为大文件的路径
String tempDir = "path/to/temp/dir"; // 替换为临时目录的路径
// 1. 分割大文件为512KB的小文件
splitFile(largeFilePath, tempDir, 512 * 1024);
// 2. 初始化哈希表数组
ConcurrentHashMap<Integer, Map<String, Integer>> hashTables = new ConcurrentHashMap<>();
for (int i = 0; i < HASH_TABLE_SIZE; i++) {
hashTables.put(i, new ConcurrentHashMap<>());
}
// 3. 并行遍历小文件,统计单词频率
File[] smallFiles = new File(tempDir).listFiles((dir, name) -> name.endsWith(".txt"));
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
for (File smallFile : smallFiles) {
executor.submit(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(smallFile), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
String[] words = line.split("\\s+");
for (String word : words) {
int hash = Math.abs(word.hashCode() % HASH_TABLE_SIZE);
hashTables.get(hash).merge(word, 1, Integer::sum);
}
}
} catch (IOException e) {
e.printStackTrace();
}
});
}
executor.shutdown();
while (!executor.isTerminated()) {
// 等待所有任务完成
}
// 4. 合并哈希表,并把频率前100的单词存入小顶堆
PriorityQueue<Map.Entry<String, Integer>> minHeap = new PriorityQueue<>(
(o1, o2) -> o1.getValue().compareTo(o2.getValue())
);
hashTables.values().stream().flatMap(Map::entrySet().stream())
.forEach(entry -> minHeap.offer(entry));
// 只保留前TOP_WORDS_COUNT个单词
while (minHeap.size() > TOP_WORDS_COUNT) {
minHeap.poll();
}
// 5. 输出结果
System.out.println("Top " + TOP_WORDS_COUNT + " words:");
minHeap.stream().forEach(entry -> System.out.println(entry.getKey() + ": " + entry.getValue()));
// 清理临时文件
Arrays.stream(smallFiles).forEach(File::delete);
}
private static void splitFile(String largeFilePath, String tempDir, int size) throws IOException {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(largeFilePath))) {
byte[] buffer = new byte[size];
int bytesRead;
int fileCount = 0;
while ((bytesRead = bis.read(buffer)) != -1) {
File smallFile = new File(tempDir, "part-" + fileCount++ + ".txt");
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(smallFile))) {
bos.write(buffer, 0, bytesRead);
}
}
}
}
}

请注意,这个代码示例假设了所有单词都是有效的UTF-8编码,并且单词之间是由空格分隔的。此外,为了简化代码,错误处理被简化了。在生产环境中,您可能需要添加更多的

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从零开始学习人工智能

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值