上篇文章简单的统计了一些信息,下一步希望找到404对应的url。
思路:
1.获取request字段
2.过滤不需要字符
3.实现获取url,并打印输出
1.创建getRequest函数获取request字段
// get the `request` field from an access log record def getRequest(rawAccessLogString: String): Option[String] = { val accessLogRecordOption = p.parseRecord(rawAccessLogString) accessLogRecordOption match { case Some(rec) => Some(rec.request) case None => None } }
2.创建extractUriFromRequest函数
// val request = "GET /foo HTTP/1.0" def extractUriFromRequest(requestField: String) = requestField.split(" ")(1)
这个目的大家可以猜猜它的作用
获取404页面,并且打印出请求的URL.
val distinctRecs = log.filter(line => getStatusCode(p.parseRecord(line)) == "404") .map(getRequest(_)) .collect { case Some(requestField) => requestField } .map(extractUriFromRequest(_)) .distinct
distinctRecs.count
distinctRecs.collect().foreach(println(_))
3.获取url
val distinctRecs = log.filter(line => getStatusCode(p.parseRecord(line)) == "404") .map(getRequest(_)) .collect { case Some(requestField) => requestField } .map(extractUriFromRequest(_)) .distinct
通过上面看,其实挺简单。Scala本身是非常简洁的。
相关说明:
上面看似简单,其实有很多需要说明的
val recs = log.filter(line => getStatusCode(p.parseRecord(line)) == "404").map(getRequest(_))
上面得出404对应的url.getRequest是上面我们定义的函数
val distinctRecs = log.filter(line => getStatusCode(p.parseRecord(line)) == "404").map(getRequest(_)).distinct
这里多了distinct是为了去重,下面是直接打印。
distinctRecs.collect().foreach(println(_))。
对于extractUriFromRequest,这个主要为过滤我们不想要的内容。如下面,GET 和HTTP/1.1都不是我们想要的。所以我们取第二个元素即可。
GET /foo HTTP/1.0 GET /foo HTTP/1.1
知识补充:
对于collect() 函数,是比较常见的,但是对于下面内容,是什么意思。
collect { case Some(requestField) => requestField }这个作用,类似map。
##################
更多信息:
在Scala中,当我需要对集合的元素进行转换时,自然而然会使用到map方法。而当我们在对tuple类型的集合或者针对Map进行map操作时,通常更倾向于在map方法中使用case语句,这比直接使用_1与_2更加可读。例如:
val languageToCount = Map("Scala" -> 10, "Java" -> 20, "Ruby" -> 5) languageToCount map { case (_, count) => count + 1 }
然而对于上述场景,其实我们也可以使用collect方法:
languageToCount collect { case (_, count) => count + 1 }