背景:
文本文件a.txt,里面每行存放了一个URL。
需求:
计算出出现频率最多的TOP100个URL。
NOTE:简单写了个demo ,处理逻辑 1、先把大数据文件按行数分割为多个小文件 2、每个文件启动一个线程分析文件内容
HELP:100W条数据以下效率1分钟以内,200W以上数据效率很慢,多线程读取文件时出现内存溢出
package test; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Scanner; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class SortURL { public static String FilePath = "a.txt"; public static int rows = 10000*10; public static List<String> fileList = null; public static ConcurrentHashMap<String, Integer> urlMap = new ConcurrentHashMap<>(); public static void main(String[] args) { //拆分文件 cutFile(FilePath,rows); //多线程处理文件,排序文件内容 threadFile(); } /** * 排序文件内容 */ public static void sortMap() { // 频率排序 List<Map.Entry<String, Integer>> sortList = new ArrayList<>(urlMap.entrySet()); Collections.sort(sortList, new Comparator<Map.Entry<String, Integer>>() { @Override public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) { // TODO Auto-generated method stub return o2.getValue().compareTo(o1.getValue()); } }); //取前100 最多频率 // List<String> url = new ArrayList<>(); for(int i=0;i<sortList.size();i++) { if (i > 100) { break; } System.out.println("URL:"+sortList.get(i).getKey() +" ---- 出现频率:"+sortList.get(i).getValue()); } } /** * 创建线程池 ,启动线程处理文件 */ public static void threadFile() { System.out.println("多线程分析文件...."); long begin = System.currentTimeMillis(); //线程数 最好依据cpu 分配 ExecutorService es = Executors.newCachedThreadPool(); SortURL su = new SortURL(); for (int i=0 ; i< fileList.size();i++) { File file = new File(fileList.get(i)); if (file.isFile()) { es.execute(su.new readFile(file)); } else { System.out.println("未找到文件"); } } es.shutdown(); while(true) { if (es.isTerminated()) { long end = System.currentTimeMillis(); System.out.println("解析 "+fileList.size()+" 个文件 耗时:"+(end-begin)+" 毫秒"); sortMap(); break; } } } /** * 线程 解析文件汇总url * @author ThinkPad * */ private class readFile implements Runnable { File tFile = null; public readFile(File f) { // TODO Auto-generated constructor stub this.tFile = f; } @Override public void run() { resolverFile(); } /** * 解析文件 */ private void resolverFile() { FileInputStream fis = null; Scanner sc = null; Map<String, Integer> map = new HashMap<>(); try { fis = new FileInputStream(tFile); sc = new Scanner(fis); while(sc.hasNextLine()) { String len = sc.nextLine().trim(); if (map.containsKey(len)) { int mValue = map.get(len); map.put(len, mValue+1); }else { map.put(len, 1); } } sc.close(); //合并总得urlMap ConcurrentHashMap 线程安全 if(urlMap.size() == 0) { urlMap.putAll(map); } else { for (String key : map.keySet()) { if (urlMap.containsKey(key)) { int mValue = urlMap.get(key) + map.get(key); urlMap.put(key, mValue); }else { urlMap.put(key, 1); } } } // //清空临时map内存 // map.clear(); System.out.println(tFile.getName()+" mapsize:"+map.size() + " urlmapSize:"+urlMap.size()); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 大文件切割 * @param sourceFile * @param curRows */ public static void cutFile(String sourceFile,int curRows) { System.out.println("开始拆每 "+curRows+" 行,拆分文件"); FileInputStream inputstream = null; Scanner sc = null; StringBuilder sbu = null; BufferedWriter bw = null; // try { inputstream = new FileInputStream(sourceFile); sbu = new StringBuilder(); fileList = new ArrayList<>(); long begin = System.currentTimeMillis(); // Scanner 方法消耗内存低 sc = new Scanner(inputstream); int i = 1; while(sc.hasNextLine()) { sbu.append(sc.nextLine()).append("\r\n"); if ((i % curRows) == 0) { bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(sourceFile+i+".txt")),"UTF-8")); bw.write(sbu.toString()); fileList.add(sourceFile+i+".txt"); bw.close(); sbu.setLength(0); } i++; } // 余下行数生成文件 if(((i-1) % curRows) != 0 ) { bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File(sourceFile+i+".txt")),"UTF-8")); bw.write(sbu.toString()); fileList.add(sourceFile+i+".txt"); bw.close(); sbu.setLength(0); } long end = System.currentTimeMillis(); System.out.println("切割文件耗时: "+(end - begin)+" 毫秒"); inputstream.close(); sc.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { } } }
相关推荐
- **String(字符串)**:最简单的一种数据类型,可以存储二进制数据或者文本数据。 - **Hash(哈希)**:用于存储字段和值的映射关系,类似于Java中的Map。 - **List(列表)**:链表结构,适合做消息队列等场景,...
在上述问题中,涉及到的算法主要包括字符串处理(如分割和匹配)、排序(找出最常见的单词)和哈希映射(用于快速查找和计数)。此外,数据结构如堆(heap)在找出最高频率的元素时非常有用,因为它可以保证在常数...
这个过程可能涉及到字符串处理、集合操作以及数据结构,如哈希表或树,以便高效地存储和查询单词的频率。 接下来是View层。View层主要负责显示结果,它接收来自Controller的指令,并根据这些指令更新用户界面。在...
在编程领域,尤其是在处理字符串数据时,经常需要找出一个字符串中出现次数最多的字符。这个问题有多种解决方案,可以使用不同的编程技巧和数据结构。下面将详细解释三种常见的方法,以中文来阐述,帮助你理解这些...
4. 排序与评分:根据相关性对搜索结果进行排序,常见的评分算法有TF-IDF(词频-逆文档频率)、BM25等。 二、Java全文检索库 1. Lucene:Apache Lucene是Java最知名的全文检索库,提供了完整的搜索引擎功能,包括...
12. **Analysis**: 分析,对数据进行深入研究的过程。 13. **Relation**: 关系,数据库中的表之间存在的关联。 14. **Schema**: 模式,数据库的结构设计。 15. **Query**: 查询,从数据库中检索数据的命令。 16. **...
7. **文件I/O操作**:读取和写入数据文件是必不可少的,这可能涉及到使用编程语言中的文件流或者特定的大数据处理工具如HDFS。 8. **算法设计**:为了有效地处理IP数据,可能需要设计特定的算法,比如哈希函数进行...
在MapReduce操作实例中,TopN问题通常是指找出数据集中出现频率最高的N个元素。在这个实例中,我们看到如何利用Hadoop的MapReduce框架来解决此类问题。以下是具体步骤和涉及的知识点: 1. **Mapper类**:在`...
在Java中实现这个UDF,需要继承Pig的AbstractFunction类,并重写eval方法,确保它接受字符串作为输入,返回分词结果的数组。完成编码后,编译这个Java项目并生成jar包。 然后,在Pig Latin脚本(如`f.pig`)中,...
2. **创建Action类**: 在这里,我们可以编写代码来处理用户的查询请求,如从表单中获取查询字符串,使用Lucene进行查询,并返回结果。 3. **展示结果**: 结果可以通过JSP页面展示,Struts会自动将Action的返回值...
3. **查询解析**:用户输入的查询字符串被解析成一系列的查询项,Lucene提供多种查询语法,如布尔运算符(AND, OR, NOT)、短语查询、范围查询等。 4. **评分机制**:Lucene使用TF-IDF(Term Frequency-Inverse ...
2. **搜索(Searching)**: 用户输入查询后,查询分析器对查询字符串进行同样的分析过程,生成查询关键字。然后,Lucene会比较这些关键字与索引中的记录,找到匹配的文档,并根据相关性得分排序。 3. **结果排序...
- **编写代码**:使用Sphinx API进行搜索操作,如构建查询字符串、设置搜索条件等。 - **结果展示**:将搜索结果展示给用户,例如以列表形式呈现。 #### 七、案例分析与实践 - **博客搜索**:为博客网站实现快速...
7. **QueryParser**:解析用户输入的查询字符串,生成Query对象。 三、Lucene查询与评分 1. **Query**:表示用户的搜索请求,包括TermQuery、PhraseQuery、BooleanQuery等多种类型。 2. **评分机制**:Lucene使用TF...
22. **Geohash**:一种地理编码技术,将地理位置转化为字符串,便于存储和查询。 23. **Geohash距离计算**:通过比较两个Geohash的前缀长度计算大致距离。 24. **找出几百亿数字的中位数**:使用外部排序或者...