1、创建Maven项目

创建的过程参考:

2、准备日志文件

url.log的内容类似:

spark 文本检索_html

20160321101954  http://java.toto.cn/java/course/javaeeadvanced.shtml
20160321101954  http://java.toto.cn/java/course/javaee.shtml
20160321101954  http://java.toto.cn/java/course/android.shtml
20160321101954  http://java.toto.cn/java/video.shtml
20160321101954  http://java.toto.cn/java/teacher.shtml
20160321101954  http://java.toto.cn/java/course/android.shtml
20160321101954  http://php.toto.cn/php/teacher.shtml
20160321101954  http://net.toto.cn/net/teacher.shtml
20160321101954  http://java.toto.cn/java/course/hadoop.shtml
20160321101954  http://java.toto.cn/java/course/base.shtml
20160321101954  http://net.toto.cn/net/course.shtml
20160321101954  http://php.toto.cn/php/teacher.shtml
20160321101954  http://net.toto.cn/net/video.shtml
20160321101954  http://java.toto.cn/java/course/base.shtml
20160321101954  http://net.toto.cn/net/teacher.shtml
20160321101954  http://java.toto.cn/java/video.shtml
20160321101954  http://java.toto.cn/java/video.shtml

3、编写UrlCount1,代码如下:

通过scala的方式获取日志文件中每类次主机名出现的前3名

package cn.toto.spark

import java.net.URL

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

/**
  * 获取到每类host出现的次数的前三名,下面通过sacle的方式实现
  * Created by toto on 2017/7/8.
  */
object UrlCount1 {

  def main(args: Array[String]): Unit = {
    //使用local就是启动一个线程,local[2]表示启动2个线程,Local[*]表示根据机器来自动分配
    val conf = new SparkConf().setAppName("UrlCount1").setMaster("local[2]")
    val sc = new SparkContext(conf)
    val lines:RDD[String] = sc.textFile(args(0))
    //split
    val urlAndOne = lines.map(line =>{
      val fields = line.split("\t")
      val url = fields(1)
      //封装成url,次数
      (url,1)
    })
    //聚合,计算某个url出现了多少次,所以要聚合一下,这里做了Cache,问题是当数据量很大的时候,可能出现内存溢出
    val summedUrl = urlAndOne.reduceByKey(_+_).cache()
    println(summedUrl)

    //返回的是[(host,url,次数)]这样的元组
    //groupBy(_._1)    表示按照host进行分组
    val grouped = summedUrl.map(t => {
      val host = new URL(t._1).getHost
      //主机名,url,次数
      (host,t._1,t._2)
    }).groupBy(_._1)
    println(grouped)

    //_                  :表示上面的集合
    //toList             :表示它转化为集合
    //sortBy             :这里是scala的集合
    //_._3               :表示按照次数进行排序
    //.reverse.take(3)   :表示取前3名
    val result = grouped.mapValues(_.toList.sortBy(_._3).reverse.take(3))
    println(result.collect().toBuffer)

    sc.stop()
  }
}

运行参数配置:

spark 文本检索_html_02


运行结果:

spark 文本检索_spark_03


4、通过Spark的方式计算URL出现的前3名

代码如下:

package cn.toto.spark

import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

/**
  * 使用SparkRDD的方式取出每个子Host的出现的次数的前3名,并循环打印出来。
  * Created by toto on 2017/7/8.
  */
object UrlCount2 {

  /**
    * 使用了Spark的RDD缓存机制,这样再进行排序时不会出现内存溢出
    * @param args
    */
  def main(args: Array[String]): Unit = {
    //后续这些Url就从数据库中获取到
    val urls = Array("http://java.toto.cn","http://php.toto.cn","http://net.toto.cn")

    val conf = new SparkConf().setAppName("UrlCount1").setMaster("local[2]")
    val sc = new SparkContext(conf)
    val lines:RDD[String] = sc.textFile(args(0))
    //split
    val urlAndOne = lines.map(line => {
      val fields = line.split("\t")
      val url = fields(1)
      //(url,次数)
      (url,1)
    })
    //聚合
    val summedUrl = urlAndOne.reduceByKey(_+_)

    //循环过滤
    for(u <- urls) {
      //过滤(值过滤出urls这些的内容)
      val insRdd = summedUrl.filter(t => {
        val url = t._1
        url.startsWith(u)
      })
      val result = insRdd.sortBy(_._2, false).take(3)
      println(result.toBuffer)
    }

    sc.stop()
  }
}

运行参数配置:

spark 文本检索_java_04


运行结果:

spark 文本检索_java_05


5、将url进行筛选,分类,并通过自定义分区将数据存储到不同的文件中

package cn.toto.spark

import java.net.URL

import org.apache.spark.rdd.RDD
import org.apache.spark.{Partitioner, SparkConf, SparkContext}

import scala.collection.mutable

/**
  * 自定义Partitioner,按照不同的子主机名存储到不同的分区文件中
  * Created by toto on 2017/7/8.
  */
object UrlCount3 {
  /**
    * 如果把每个学员单独产生的内容都写入到磁盘文件中
    * @param args
    */
  def main(args: Array[String]): Unit = {
    val conf = new SparkConf().setAppName("UrlCount1").setMaster("local[2]")
    val sc = new SparkContext(conf)
    val lines : RDD[String] = sc.textFile("E:\\workspace\\url.log")
    //split
    val urlAndOne = lines.map(line => {
      val fields = line.split("\t")
      val url = fields(1)
      (url,1)
    })
    //聚合
    val summedUrl = urlAndOne.reduceByKey(_+_).cache()

    val rdd1 = summedUrl.map(t => {
      val host = new URL(t._1).getHost
      //(host,(url,出现次数))
      (host,(t._1,t._2))
    })

    val urls = rdd1.map(_._1).distinct().collect()

    val partitioner = new HostPartitioner(urls)
    //安装自定义的分区器重新分区
    val partitionedRdd = rdd1.partitionBy(partitioner)

    val result = partitionedRdd.mapPartitions(it => {
      it.toList.sortBy(_._2._2).reverse.take(3).iterator
    })

    result.saveAsTextFile("E:\\workspace\\out")
    sc.stop()
  }
}

class HostPartitioner(urls: Array[String]) extends Partitioner {
  val rules = new mutable.HashMap[String,Int]()
  var index = 0
  for(url <- urls){
    rules.put(url,index)
    index += 1
  }

  override def getPartition(key: Any): Int = {
    val url = key.toString
    //如果取到了值就返回url,否则返回0
    rules.getOrElse(url,0)
  }

  //分区数量
  override def numPartitions: Int = urls.length
}

最终的输出内容是:

spark 文本检索_spark_06

spark 文本检索_scala_07

spark 文本检索_html_08

spark 文本检索_java_09