海量日志数据,找出出现次数最多的IP地址。

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 问题描述有一个12G的文本文件,每行记录的是一个IP地址,现要找出这个文件中出现次数最多的那个ip。代码实现import java.

问题描述

有一个12G的文本文件,每行记录的是一个IP地址,现要找出这个文件中出现次数最多的那个ip。

代码实现

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

class IP implements Serializable {

	private static final long serialVersionUID = -8903000680469719698L;
	private String ip = "";
	private int count;

	public IP(String ip2, Integer integer) {
		this.ip = ip2;
		this.count = integer;
	}

	public int getCount() {
		return count;
	}

	public String getIp() {
		return ip;
	}

	public void setCount(int count) {
		this.count = count;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

}

/**
 * 1、海量日志数据,提取出某日访问百度次数最多的那个IP。
 * 
 * 首先是这一天,并且是访问百度的日志中的IP取出来,逐个写入到一个大文件中。注意到IP是32位的,最多有个2^32个IP。同样可以采用映射的方法,
 * 比如模1000
 * ,把整个大文件映射为1000个小文件,再找出每个小文中出现频率最大的IP(可以采用hash_map进行频率统计,然后再找出频率最大的几个)及相应的频率
 * 。然后再在这1000个最大的IP中,找出那个频率最大的IP
 * 
 * 
 */
public class No2 {
	static String fileLoc = "D:\\bigdata_ip.txt";

	public static void findIp() throws IOException, ClassNotFoundException {
		long start = System.currentTimeMillis();
		hashToSmallFiles();
		long end1 = System.currentTimeMillis();
		System.out.println("将大文件映射成小文件,用时:" + (end1 - start) + "毫秒");

		System.out.println("映射到小文件完成,开始统计每个小文件中出现频率最高的ip");
		long start1 = System.currentTimeMillis();
		List<IP> list = countEverySmallFile();
		long end2 = System.currentTimeMillis();
		System.out.println("统计所有文件共用时:" + (end2 - start1) + " 毫秒");

		System.out.println("统计完成,开始计算所有ip中出现频率最高的ip");
		IP ip = calculateResult(list);
		System.out.println("访问次数最多的ip是:" + ip.getIp() + ":" + ip.getCount());
		long end = System.currentTimeMillis();
		System.out.println("公用时:" + (end - start) + "毫秒");
	}

	/**
	 * 从每个文件出现频率最高ip中,计算出所有文件中出现频率最高ip。
	 * 
	 * @param list
	 */
	private static IP calculateResult(List<IP> list) {
		IP[] ips = new IP[list.size()];
		ips = list.toArray(ips);
		int max = 0;
		for (int j = 1; j < ips.length; j++) {
			if (ips[j].getCount() > ips[max].getCount()) {
				max = j;
			}
		}
		return ips[max];
	}

	/**
	 * 统计生成的每一个小文件,返回一个List,这个List的每一项就是每个小文件的统计结果,即每个小文件中出现频率最高的ip和出现次数
	 * 
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private static List<IP> countEverySmallFile() throws FileNotFoundException, IOException {
		List<IP> list = new ArrayList<IP>();
		for (int i = 0; i < 1024; i++) {
			File file = new File(fileLoc + i + ".txt");
			if (file.exists()) {
				long startTime = System.currentTimeMillis();
				BufferedReader br1 = new BufferedReader(new FileReader(file));
				String ip1 = "";
				HashMap<String, Integer> hm = new HashMap<String, Integer>();
				while ((ip1 = br1.readLine()) != null) {
					if (!hm.containsKey(ip1)) {
						hm.put(ip1, 1);
					} else {
						hm.put(ip1, hm.get(ip1) + 1);
					}
				}

				IP[] ips = new IP[hm.size()];
				int index = 0;
				for (String temp : hm.keySet()) {
					ips[index] = new IP(temp, hm.get(temp));
					index++;
				}
				int max = 0;
				for (int j = 1; j < ips.length; j++) {
					if (ips[j].getCount() > ips[max].getCount()) {
						max = j;
					}
				}
				list.add(ips[max]);
				long endTime = System.currentTimeMillis();
				System.out.println("已经统计文件:" + fileLoc + i + ".txt,用时:" + (endTime - startTime) + " 毫秒");
			}
		}
		return list;
	}

	/**
	 * 将打文件hash成1024个小文件
	 * 
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	private static void hashToSmallFiles() throws FileNotFoundException, IOException {
		BufferedReader br = new BufferedReader(new FileReader(fileLoc));
		String ip = "";
		HashMap<String, FileWriter> fileWriters = new HashMap<String, FileWriter>();
		while ((ip = br.readLine()) != null) {
			int tmp = Math.abs(ip.hashCode() % 1024);
			String fileName = fileLoc + tmp + ".txt";
			FileWriter fw = null;
			if (fileWriters.containsKey(fileName)) {
				fw = fileWriters.get(fileName);
			} else {
				fw = new FileWriter(fileName, true);
				fileWriters.put(fileName, fw);
			}
			fw.write(ip + "\n");
		}
		br.close();
		for (FileWriter ff : fileWriters.values()) {
			ff.close();
		}
	}

	/**
	 * 随机生成ip地址,生成大文本文件
	 * 
	 * @throws IOException
	 */
	private static void generateFile() throws IOException {
		FileWriter fw = new FileWriter(fileLoc, true);
		for (int i = 0; i < 100000000; i++) {
			for (int j = 0; j < 100000000; j++) {
				fw.write(generateIp() + "\n");
			}
		}
		fw.close();
		System.out.println("done");
	}

	/**
	 * 随机生成ip地址
	 * 
	 * @return
	 */
	private static String generateIp() {
		String ip = "";
		for (int i = 0; i < 4; i++) {
			int temp = (int) (Math.random() * 255);
			ip += temp + ".";
		}
		return ip.substring(0, ip.length() - 1);
	}

	public static void main(String[] args) {
		try {
			findIp();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

运行部分结果









性能优化

上述代码没有充分利用可用内存,程序运行时大概记得总共用了150M内存。而我的机子共4G内存,如果充分利用内存,找出出现次数最多的IP用时肯定能降到5分钟内。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
2月前
|
存储 消息中间件 人工智能
AI大模型独角兽 MiniMax 基于阿里云数据库 SelectDB 版内核 Apache Doris 升级日志系统,PB 数据秒级查询响应
早期 MiniMax 基于 Grafana Loki 构建了日志系统,在资源消耗、写入性能及系统稳定性上都面临巨大的挑战。为此 MiniMax 开始寻找全新的日志系统方案,并基于阿里云数据库 SelectDB 版内核 Apache Doris 升级了日志系统,新系统已接入 MiniMax 内部所有业务线日志数据,数据规模为 PB 级, 整体可用性达到 99.9% 以上,10 亿级日志数据的检索速度可实现秒级响应。
AI大模型独角兽 MiniMax 基于阿里云数据库 SelectDB 版内核 Apache Doris 升级日志系统,PB 数据秒级查询响应
|
2月前
|
缓存 NoSQL Linux
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
【Azure Redis 缓存】Windows和Linux系统本地安装Redis, 加载dump.rdb中数据以及通过AOF日志文件追加数据
|
1月前
|
SQL 人工智能 运维
在阿里云日志服务轻松落地您的AI模型服务——让您的数据更容易产生洞见和实现价值
您有大量的数据,数据的存储和管理消耗您大量的成本,您知道这些数据隐藏着巨大的价值,但是您总觉得还没有把数据的价值变现出来,对吗?来吧,我们用一系列的案例帮您轻松落地AI模型服务,实现数据价值的变现......
139 3
|
2月前
|
存储 监控 网络协议
在Linux中,如何使用 tcpdump 监听主机为 192.168.1.1,tcp 端⼝为 80 的数据,并将将输出结果保存输出到tcpdump.log?
在Linux中,如何使用 tcpdump 监听主机为 192.168.1.1,tcp 端⼝为 80 的数据,并将将输出结果保存输出到tcpdump.log?
|
2月前
|
应用服务中间件 Linux nginx
在Linux中,如何统计ip访问情况?分析 nginx 访问日志?如何找出访问页面数量在前十位的ip?
在Linux中,如何统计ip访问情况?分析 nginx 访问日志?如何找出访问页面数量在前十位的ip?
|
2月前
|
数据库 Java 监控
Struts 2 日志管理化身神秘魔法师,洞察应用运行乾坤,演绎奇幻篇章!
【8月更文挑战第31天】在软件开发中,了解应用运行状况至关重要。日志管理作为 Struts 2 应用的关键组件,记录着每个动作和决策,如同监控摄像头,帮助我们迅速定位问题、分析性能和使用情况,为优化提供依据。Struts 2 支持多种日志框架(如 Log4j、Logback),便于配置日志级别、格式和输出位置。通过在 Action 类中添加日志记录,我们能在开发过程中获取详细信息,及时发现并解决问题。合理配置日志不仅有助于调试,还能分析用户行为,提升应用性能和稳定性。
40 0
|
2月前
|
开发者 前端开发 编解码
Vaadin解锁移动适配新境界:一招制胜,让你的应用征服所有屏幕!
【8月更文挑战第31天】在移动互联网时代,跨平台应用开发备受青睐。作为一款基于Java的Web应用框架,Vaadin凭借其组件化设计和强大的服务器端渲染能力,助力开发者轻松构建多设备适应的Web应用。本文探讨Vaadin与移动设备的适配策略,包括响应式布局、CSS媒体查询、TouchKit插件及服务器端优化,帮助开发者打造美观且实用的移动端体验。通过这些工具和策略的应用,可有效应对屏幕尺寸、分辨率及操作系统的多样性挑战,满足广大移动用户的使用需求。
39 0
|
2月前
|
存储 运维 监控
Entity Framework Core 实现审计日志记录超棒!多种方法助你跟踪数据变化、监控操作,超实用!
【8月更文挑战第31天】在软件开发中,审计日志记录对于跟踪数据变化、监控用户操作及故障排查至关重要。Entity Framework Core (EF Core) 作为强大的对象关系映射框架,提供了多种实现审计日志记录的方法。例如,可以使用 EF Core 的拦截器在数据库操作前后执行自定义逻辑,记录操作类型、时间和执行用户等信息。此外,也可通过在实体类中添加审计属性(如 `CreatedBy`、`CreatedDate` 等),并在保存实体时更新这些属性来记录审计信息。这两种方法都能有效帮助我们追踪数据变更并满足合规性和安全性需求。
27 0
|
2月前
|
SQL 安全 测试技术
【数据守护者必备】SQL数据备份与恢复策略全解析:从全量到日志备份,手把手教你确保企业信息万无一失的实战技巧!
【8月更文挑战第31天】数据库是企业核心业务数据的基石,为防止硬件故障、软件错误或人为失误导致的数据丢失,制定可靠的备份与恢复策略至关重要。本文通过一个在线购物平台的案例,详细介绍了使用 SQL Server 进行全量备份、差异备份及事务日志备份的方法,并演示了如何利用 SQL Server Agent 实现自动化备份任务。此外,还提供了数据恢复的具体步骤和测试建议,确保数据安全与业务连续性。
65 0
|
2月前
|
网络安全
【Azure Service Bus】启用诊断日志来获取客户端访问Azure Service Bus的IP地址 [2024-03-26 实验结果失败]
【Azure Service Bus】启用诊断日志来获取客户端访问Azure Service Bus的IP地址 [2024-03-26 实验结果失败]