java(版)数据分析--网站访问日志session数据分析

数据

 

数据中的字段分别为:

访客ip地址

访客访问时间

访客请求的url及协议

网站响应码

网站返回数据量

访客的referral url

访客的客户端操作系统及浏览器信息

 

 

附带数据文件:

 

 

需求:

1) 需要为从访问日志中梳理出每一个session(如果一个用户两次相邻请求之间的时间差<30分钟,则该两次请求都属于同一个session,否则分属不同的session),并为session中的历次请求打上序号,示意如下:

session

ip地址

请求时间

请求url

请求次序

其他字段......

session1

ip1

2017-10-11 08:10:30

/a

1

......

session1

ip1

2017-10-11 08:11:20

/b

2

......

session2

ip1

2017-10-11 09:10:30

/c

1

......

步骤分析:

1 使用正则获取数据文件中的数据

2 对数据ip分组  map<ip,List<Bean>> list并按时间排序照序

3 判断两个相邻的url的时间间隔来判断是否是同一个session,并生成对应的sessionID和序号

4 对结果集处理 获取想要的结果 输出

String ipRegex = "(\\d}+\\.){3}\\d+";

String dateRegex = "\\[.+\\d\\]";

String urlRegex = "(GET|POST){1}\\s(\\S)*\\s";

new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss", Locale.US);

技术分析:

时间格式转换,时间间隔,LIst集合和Map集合,集合的排序,正则表达式

 

2) 将每次session进行汇总,得出用户每次session的浏览起、止页面,每次session会话总时长等,示意如下:

session

ip地址

起始请求时间

结束请求时间

起始页面

跳出页面

访问时长

session1

ip1

2017-10-11 08:10:30

2017-10-11 08:11:20

/a

/b

50

session2

ip1

2017-10-11 09:10:30

2017-10-11 09:10:30

/c

/c

默认值

session3

ip2

2017-10-11 07:15:10

2017-10-11 07:30:10

/h

/x

750

步骤分析:

根据第一步的基础上获取同一个sessionID对应的第一个编号的URL和最后一个编号的URL

计算两个url的时间间隔

1)代码实现

  1 读取文件数据,使用正则获取匹配的字符串

/*

 * 由于读取的数据是不完全规则的数据,使用正则表达式去匹配更为简单

 */

String ipRegex = "(\\d+\\.){3}\\d+";

String dateRegex = "\\[.+\\d\\]";

String urlRegex = "(GET|POST){1}\\s(\\S)*\\s";

while ((line = reader.readLine()) != null) {

//调用正则匹配数据的方法来获取 指定的IP URL DATE

String ip = findSubStrngByRegex(ipRegex, line);

String dateStr = findSubStrngByRegex(dateRegex, line);

String url = findSubStrngByRegex(urlRegex, line);

获取匹配子串的方法

/**

 * 使用正则表达式获取匹配的子串

 * @param rex

 * @param line

 * @return

 */

private static String findSubStrngByRegex(String rex, String line) {

String res = null;

Pattern pattern = Pattern.compile(rex);

Matcher matcher = pattern.matcher(line);

while (matcher.find()) {

res = matcher.group();

}

return res;

}

2将获取的数据封装到SessionBean中 ,需要将字符串转换成时间对象

字符串转时间的方法

/**

 * 将字符串转换成时间

 * @param dateStr

 * @return

 */

private static Date parseDate(String dateStr) {

Date date = null;

try {

String newStr = dateStr.substring(1, dateStr.length() - 1);

SimpleDateFormat format = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss", Locale.US);

date = format.parse(newStr);

} catch (ParseException e) {

e.printStackTrace();

}

return date;

}

if (ip != null && dateStr != null && url != null) {

Date date = parseDate(dateStr);

// System.out.println(url);

SessionBean bean = new SessionBean();

bean.setIp(ip);

bean.setDate(date);

//去除url中的请求方式

bean.setUrl(url.replace("GET ", "").replace("POST ", ""));

3将数据封装在map中  ip作为keyList<SessionBean>作为value

list中的数据需要按照时间排序,两种方式解决,

第一种: 可以在放入map之前对List排序

第二种: 可以多mapvalue指定字段排序进行排序 √

//根据ip获取数据 getOrDefault()方法会有默认值不需要判断

List<SessionBean> default1 = map.getOrDefault(ip, new ArrayList<>());

default1.add(bean);

map.put(ip, default1);

4 对结果集的mapvalue按照时间排序

/**

 * map数据按时间排序

 * @param map

 */

private static void sortMapByDate(Map<String, List<SessionBean>> map) {

Set<Entry<String, List<SessionBean>>> entrySet = map.entrySet();

for (Entry<String, List<SessionBean>> entry : entrySet) {

List<SessionBean> list = entry.getValue();

Collections.sort(list, new Comparator<SessionBean>() {

@Override

public int compare(SessionBean o1, SessionBean o2) {

// TODO Auto-generated method stub

return o1.getDate().compareTo(o2.getDate());

}

});

map.put(entry.getKey(), list);

}

}

5 结果集生成sessionID和序号

主要是对结果集map中的list数据操作

 1 如果一个ip对应的list中只有一个SessionBean说明只有一个请求,那么这个ip只有一个URL对应的一个session和序号为1

2 如果一个ip对应的list中的长度大于1,则要判断两个相邻的url的事件差值是否在30分钟内,如果在30分钟内说明是一个session,响应的Order序号加1

         如果不在30分钟内,说明是两个不同的session

private static void mkSessionId(Map<String, List<SessionBean>> map) {

Set<Entry<String, List<SessionBean>>> entrySet = map.entrySet();

for (Entry<String, List<SessionBean>> entry : entrySet) {

List<SessionBean> list = entry.getValue();

if (list.size() == 1) {//只有一个数据,说明只有一个sessionID

SessionBean bean = list.get(0);

bean.setSessionID(getSesionId(bean.getIp()));

bean.setOrder(1);

}

如果list中有多个数据

for (int i = 0; i < list.size() - 1; i++) {

if (list.size() > 1) {// 两个url

                         //根据时间判断是否是一个sessionID

if (isSameSesison(list.get(i), list.get(i + 1))) {// 同一个sesison

if (list.get(i).getSessionID() != null) {

list.get(i + 1).setSessionID(list.get(i).getSessionID());

} else {

list.get(i).setSessionID(getSesionId(list.get(i).getIp()));

list.get(i + 1).setSessionID(list.get(i).getSessionID());

}

if (list.get(i).getOrder() != null) {

list.get(i + 1).setOrder(list.get(i).getOrder() + 1);

} else {

list.get(i).setOrder(1);

list.get(i + 1).setOrder(list.get(i).getOrder() + 1);

}

 

} else {// 两个相邻的url不是同一个session

if (list.get(i).getSessionID() == null) {

list.get(i).setSessionID(getSesionId(list.get(i).getIp()));

}

list.get(i + 1).setSessionID(getSesionId(list.get(i + 1).getIp()));

if (list.get(i).getOrder() == null) {

list.get(i).setOrder(1);

}

list.get(i + 1).setOrder(1);

}

}

}

map.put(entry.getKey(), list);

}

}

生成sessionId的方法

public static String getSesionId(String ip) {

long l = IpUtil.ipStrToLongIp(ip);

return l + ":" + System.nanoTime();

 

}

判断是否是同一个session的方法

private static boolean isSameSesison(SessionBean s1, SessionBean s2) {

boolean flag = false;

long l1 = s1.getDate().getTime();

long l2 = s2.getDate().getTime();

long l3 = l2 - l1;

if (l3 >= 0 && l3 <= (1000 * 30 * 60)) {

flag = true;

}

return flag;

}

处理结果集  打印或者输出结果

java(版)数据分析--网站访问日志session数据分析

更多内容 qq:598196583  附带视频

java(版)数据分析--网站访问日志session数据分析