转载

使用 R 和 InfoSphere Streams 预测用户对 Web 内容的请求

简介

Web 服务器日志可以用来研究用户的浏览习惯。例如,在 根据日志数据预测 Web 用户的下次访问 中,Rituparna Sen 和 Mark Hansen 就使用了混合的一阶 Markov 模型,找出网站上经常被访问的 Web 页面。他们利用这些模型预测用户下次最有可能请求哪些页面。他们建议在用户实际发出请求之前用这些信息预先提取某个资源。本文介绍了如何结合 IBM InfoSphere Streams 与 R 进行类似的 Web 服务器日志分析。

此解决方案采用了 可扩展 Markov 模型 (EMM) ,该模型最早由 Margaret Dunham、Yu Meng 和 Jie Huang 于 2004 年引入,EMM 将流集群算法与 Markov 链结合使用。 Markov 链 是一种数学系统,它经历了不同状态之间的转换,下一个状态只取决于当前状态,而不取决于在此之前的事件顺序。

Markov 链的状态就是流集群算法所定义的集群。EMM 在遇到新状态时会添加新的状态,并随时间修改现有状态或使现有状态退出 Markov 链。因此,该模型可以随时间适应新的变化。这种能力对于拥有动态使用模式的系统尤为重要,动态使用模式则意味着短期时间内会发生变化。例如,一个网站可能会在一段时间内表现出动态使用模式,以及结构化变化。

本文演示了如何使用 EMM 预测用户对网站内容的请求,还介绍了如何使用服务器日志训练和测试模型,如何使用模型预测浏览行为,以及如何使用 InfoSphere Streams 和 R 根据模型发出预测。InfoSphere Streams 提供了执行框架,而 R 提供了建模和预测。EMM 模型基于 Michael Hahsler 和 Dunham 创建的 rEMM 库 。

回页首

使用 R-project Toolkit 集成 InfoSphere Streams 和 R 的优势

InfoSphere Streams 的 R-project Toolkit

InfoSphere Streams 是一个高级计算平台,允许利用用户开发的应用程序快速提取、分析和关联从数千个实时来源提供的信息,因而可以处理非常高的数据吞吐率 — 每秒多达数百万个时间或消息。它包括一个 R-project Toolkit,支持您应用复杂数据挖掘算法来检测数据流中的有趣模式。了解更多的信息 并进行试用。

大多数用于预测的机器学习模型会在脱机模式下用海量训练数据进行训练。当模型完成训练后,通常可以实时进行预测。该方法适合用来解决各种类型的问题,但是,如果要进行预测的模式频繁发生变化,那么这种方法生成的模型就会落后于它们要预测的系统。由于 EMM 可以进行动态训练,所以它适用于网络流量、交通流量等建模系统,或其他集群模式会随时间变化的系统。Web 服务器流量就属于这一类型。服务器日志提供了丰富的流数据来训练模型,而系统也提供了预测功能。

回页首

根据 Web 服务器日志来预测内容请求

Web 服务器维护了一个资源请求日志。每个日志条目都会保护请求者的 IP 地址、请求时间戳和所请求内容的位置。表 1 展示了 Web 服务器日志中的三个样例条目。这三个条目都来自相同 IP 地址,分别请求三项不同的内容(两个图片和一个 HTML 文档)。这三个条目表示对某个网站的一次访问(或访问的一部分)。

表 1. Web 服务器日志的样例条目

IP 地址 用户名等 时间戳 访问请求 结果状态代码 已传输的字节数
123.123.123.123 - - [26/Apr/2000:00:23:45 -0400] "GET /pics/wpaper.gif HTTP/1.0" 200 6248
123.123.123.123 - - [26/Apr/2000:00:23:48 -0400] "GET /index.html HTTP/1.0" 200 8130
123.123.123.123 - - [26/Apr/2000:00:23:50 -0400] "GET /pics/5star2000.gif HTTP/1.0" 200 4005

回页首

解决方案的详细信息

这个项目的目标是对用户浏览网站的方式进行建模。对于这个简化的模型,每个请求的内容项在 EMM 中都表示一种状态。比较复杂的模型可能会将不同的内容组聚集在一起。通过观察在请求 Page A 后再请求 Page B 的用户的数量,可以确定发生状态转换的概率。除了每个内容项外,模型还包含一种表示 “off-site(脱机)” 的状态。在脱机状态下执行转换意味着用户正在开始一次新的访问(也就是说,这是用户向网站请求的第一个资源)。从其他状态转换到脱机状态意味着用户正在结束一个访问(用户停止向该网站请求资源)。

通过 streamsdev 直通 InfoSphere Streams 开发团队

extended Streams 开发团队为您提供了 streamsdev,您可以从中找到有关 InfoSphere Streams 开发的所有资源,文档、产品下载、SPL 代码示例、帮助、活动、专家博客 — 一应俱全。您可以直接与开发人员进行交流。 立即访问 。

清单 1是应用程序的主要 Streams Processing Language (SPL) 代码。该应用程序包含五个操作符,下面按照在管道中出现的顺序列出了这些操作符:

  • FileSource 操作符 :读取输入服务器日志,每次读取一行,以元组形式返回,每个包含一项内容。每行内容都使用 RScript 操作符进行解析。
  • 第一个 RScript operator :调用 R 脚本。R 脚本将会分析出请求方的 IP 地址和所请求的内容。该脚本还将分析日志条目,判断是否存在关联性(如前所述,根据条件进行判断)。
  • Filter 操作符 :对 R 解析程序标记的所有元组进行过滤。未过滤掉的元组被传递给第二个 RScript 操作符。
  • 第二个 RScript 操作符 :将所请求内容的路径传递给 R 脚本,后者使用该路径生成一个预测,包括 20 项最有可能被再次请求的内容。生成的预测被封装到一个元组中,同时被封装的还有请求方 IP 地址和所请求的内容项。
  • FileSink 操作符 :将新来的元组写入到一个输出文件。

清单 1. 定义应用程序图形的 SPL 代码

composite Main {   graph     // read entries from the log file     stream<rstring line>      inStream = FileSource() {       param  file : "../data/first-100-test-log.txt";     }        // parse the line using an R script     stream<rstring origin, rstring path>      parsedStream = RScript(inStream) {       param         initializationScriptFileName : "../rsrc/parse-functions.R";         rScriptFileName : "../rsrc/parse.R";         streamAttributes : line;         rObjects : "log.entry";         output         parsedStream: origin = fromR("origin"),                       path = fromR("path");     }      // filter out invalid tuples:     stream<rstring origin, rstring path>     filteredStream = Filter(parsedStream) {       param filter : origin != "filter me";     }      // call the r script that will create the prediction     stream<rstring origin, rstring path, list<rstring> prediction>      analyzedStream = RScript(filteredStream) {       param         initializationScriptFileName : "../rsrc/init_predict.R";         rScriptFileName : "../rsrc/predict.R";         streamAttributes : path;         rObjects : "path";                  output         analyzedStream:           prediction = fromR("prediction");     }      // send the results to a file     () as dbg = FileSink(analyzedStream) {       param         format : csv;         file   : "result.txt" ;        } }

清单 2 包含解析日志条目使用的 R 函数。此外,脚本还会识别对 HTML、PDF 或 PS 文档以外的内容的请求,并对返回的元组进行标记,以便进行过滤。

应用程序还维护了一个已知的 bot IP 地址列表。该列表用于标记与 bot 有关联的条目,以便进行过滤。

清单 2. 解析日志条目使用的 R 函数

# This script contains functions used to parse a line from # a web server log.  if (file.exists("../data/bot-list.RData")) {   load("../data/bot-list.RData")   } else {   bot.list <- c("") }  origin.pattern <- "^//S+(//.//S+)*//.//S+" path.pattern <- "GET//s+[///w]+.//w+"  get.code <- function(log.entry) {   # Returns the return code of a web server log entry.   tokens = unlist(strsplit(x=log.entry, split="//s+", perl=TRUE))   code = tokens[length(tokens)-1]      return(code) }  get.path <- function(log.entry) {   # Returns the path of the requested resource of a web server log entry.   path <- regmatches(x=log.entry, m=regexpr(pattern=path.pattern,                                                 text=log.entry,                                                 perl=TRUE))   path <- unlist(strsplit(x=path, split="//s+", perl=TRUE))[2]      return(path) }  get.origin <- function(log.entry) {   # Returns the originating ip or domain from a web server log entry.   return(regmatches(x=log.entry, m=regexpr(pattern=origin.pattern,                                             text=log.entry,                                             perl=TRUE))) }  get.tuple <- function(log.entry) {   # Returns a two-item list containing the modified origin of the    # request and the path to the requested item.   # The origin will be set to "filter me" if:   #   -- The return code is not 200   #   -- The requested file is not HTML, PDF, or PS   #   -- The origin is determined to be a bot   origin <- get.origin(log.entry)   path <- get.path(log.entry)   code <- get.code(log.entry)      if (code != "200") {     origin <- "filter me"   } else if(is.null(path)) {     origin <- "filter me"   } else if(path == FALSE) {     origin <- "filter me"   } else if (! grepl(pattern="//S+//.(htm|html|pdf|ps)$", x=path, perl=TRUE)) {     origin <- "filter me"   } else if (origin %in% bot.list) {     origin <- "filter me"   }    return(list(origin, path)) }

清单 3包含用于解析日志条目的 R 脚本。该脚本使用了清单 2 中的函数。

清单 3. 用于解析日志条目元组的 R 脚本

# This script parses log entries transforming them into tuples # It parses out the origin of the request and the requested path. #  # inputs:  log.entry -- A single line from a web server log. # outputs: origin -- The origin of the request received by web  #                    server. #          path -- The path to the requested item. # # The origin will be set to "filter me" if: #   -- The return code is not 200 #   -- The requested file is not HTML, PDF, or PS #   -- The origin is determined to be a bot  tuple <- unlist(get.tuple(log.entry)) origin <- tuple[1] path <- tuple[2]

如清单 4所示,R 脚本使用训练后的 EMM 预测下一次最有可能被请求的页面或内容项。在本例中,EMM 中的每个状态都代表网站上的一项内容(例如,HTML、PDF 或 PS 文档)。要预测下一次可能请求的内容,脚本会查找与之前请求的内容相关的状态。然后,使用 EMM 返回一个从当前状态转换到所有其他已观察到的状态的概率列表。要获得前 20 项最有可能再次请求的内容,应用程序只需要按照降序对列表进行排序并检索概率最高的状态。在最后一步中,它将预测的状态转换为相应的内容项。

清单 4. 使用 EMM 进行预测的 R 脚本

# inputs:  path — The path of the last requested item. # outputs: prediction — A list of the twenty most likely next paths to be  #                        requested.  prediction <- vector() last.request <- page.hash[[path]] if (! is.null(last.request)) {   likelihoods <- predict(emm, current_state=last.request,                             probabilities=TRUE)   top.twenty <- names(sort(x=likelihoods, decreasing=TRUE)[1:20])   for (i in 1:20) {     prediction[[i]] <- toString(page.list[as.numeric(top.twenty[i])])   }  }

回页首

结果

应用程序处理输出元组,其中包括始发 IP 地址、请求的路径、前 20 个用户最有可能再次请求的内容项列表。清单 5是一个样例输出元组,展示了 Web 服务器日志中的示例条目。

清单 5. 样例输出元组

"123.123.123.123", "/pub/atomicbk/catalog/sleazbk.html",                             ["/atomicbk/new/new.html", "/atomicbk/images/gallery.html",                             "/atomicbk/shocked.html", ...]

回页首

结束语

本文演示了通过结合使用 InfoSphere Stream 和 R,如何从 Web 服务器利用该服务器的日志来预测用户对内容的请求。文中的建模和预测是利用 R 版本的 EMM 实现 完成的。

本文描述的内容属于概念证明,需要执行进一步的操作来创建一个真正的解决方案。接下来的工作包括通过对 Web 页面进行分组来提高性能,进行渐进式训练,以及使用 InfoSphere Streams 实现多个 R 实例。

正文到此结束
Loading...