spark实战之:分析维基百科网站统计数据(java版)

news/2024/5/18 7:48:44/文章来源:https://xinchen.blog.csdn.net/article/details/87241814

在《寻找海量数据集用于大数据开发实战(维基百科网站统计数据)》一文中,我们获取到维基百科网站的网页点击统计数据,也介绍了数据的格式和内容,今天就用这些数据来练习基本的spark开发,开发语言是Java

实战环境信息

为了快速搭建spark集群环境,我是在docker下搭建的,您也可以选择用传统的方式来搭建,以下是参考文章:

  1. 如果您也打算用docker来搭建,请参考《docker下,极速搭建spark集群(含hdfs集群)》,本次实战用到的docker-compose.yml内容如下:
version: "2.2"
services:namenode:image: bde2020/hadoop-namenode:1.1.0-hadoop2.7.1-java8container_name: namenodevolumes:- ./hadoop/namenode:/hadoop/dfs/name- ./input_files:/input_filesenvironment:- CLUSTER_NAME=testenv_file:- ./hadoop.envports:- 50070:50070resourcemanager:image: bde2020/hadoop-resourcemanager:1.1.0-hadoop2.7.1-java8container_name: resourcemanagerdepends_on:- namenode- datanode1- datanode2env_file:- ./hadoop.envhistoryserver:image: bde2020/hadoop-historyserver:1.1.0-hadoop2.7.1-java8container_name: historyserverdepends_on:- namenode- datanode1- datanode2volumes:- ./hadoop/historyserver:/hadoop/yarn/timelineenv_file:- ./hadoop.envnodemanager1:image: bde2020/hadoop-nodemanager:1.1.0-hadoop2.7.1-java8container_name: nodemanager1depends_on:- namenode- datanode1- datanode2env_file:- ./hadoop.envdatanode1:image: bde2020/hadoop-datanode:1.1.0-hadoop2.7.1-java8container_name: datanode1depends_on:- namenodevolumes:- ./hadoop/datanode1:/hadoop/dfs/dataenv_file:- ./hadoop.envdatanode2:image: bde2020/hadoop-datanode:1.1.0-hadoop2.7.1-java8container_name: datanode2depends_on:- namenodevolumes:- ./hadoop/datanode2:/hadoop/dfs/dataenv_file:- ./hadoop.envdatanode3:image: bde2020/hadoop-datanode:1.1.0-hadoop2.7.1-java8container_name: datanode3depends_on:- namenodevolumes:- ./hadoop/datanode3:/hadoop/dfs/dataenv_file:- ./hadoop.envmaster:image: gettyimages/spark:2.3.0-hadoop-2.8container_name: mastercommand: bin/spark-class org.apache.spark.deploy.master.Master -h masterhostname: masterenvironment:MASTER: spark://master:7077SPARK_CONF_DIR: /confSPARK_PUBLIC_DNS: localhostlinks:- namenodeexpose:- 7001- 7002- 7003- 7004- 7005- 7077- 6066ports:- 4040:4040- 6066:6066- 7077:7077- 8080:8080volumes:- ./conf/master:/conf- ./data:/tmp/data- ./jars:/root/jarsworker1:image: gettyimages/spark:2.3.0-hadoop-2.8container_name: worker1command: bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077hostname: worker1environment:SPARK_CONF_DIR: /confSPARK_WORKER_CORES: 2SPARK_WORKER_MEMORY: 2gSPARK_WORKER_PORT: 8881SPARK_WORKER_WEBUI_PORT: 8081SPARK_PUBLIC_DNS: localhostlinks:- masterexpose:- 7012- 7013- 7014- 7015- 8881volumes:- ./conf/worker1:/conf- ./data/worker1:/tmp/dataworker2:image: gettyimages/spark:2.3.0-hadoop-2.8container_name: worker2command: bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077hostname: worker2environment:SPARK_CONF_DIR: /confSPARK_WORKER_CORES: 2SPARK_WORKER_MEMORY: 2gSPARK_WORKER_PORT: 8881SPARK_WORKER_WEBUI_PORT: 8081SPARK_PUBLIC_DNS: localhostlinks:- masterexpose:- 7012- 7013- 7014- 7015- 8881volumes:- ./conf/worker2:/conf- ./data/worker2:/tmp/data     worker3:image: gettyimages/spark:2.3.0-hadoop-2.8container_name: worker3command: bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077hostname: worker3environment:SPARK_CONF_DIR: /confSPARK_WORKER_CORES: 2SPARK_WORKER_MEMORY: 2gSPARK_WORKER_PORT: 8881SPARK_WORKER_WEBUI_PORT: 8081SPARK_PUBLIC_DNS: localhostlinks:- masterexpose:- 7012- 7013- 7014- 7015- 8881volumes:- ./conf/worker3:/conf- ./data/worker3:/tmp/dataworker4:image: gettyimages/spark:2.3.0-hadoop-2.8container_name: worker4command: bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077hostname: worker4environment:SPARK_CONF_DIR: /confSPARK_WORKER_CORES: 2SPARK_WORKER_MEMORY: 2gSPARK_WORKER_PORT: 8881SPARK_WORKER_WEBUI_PORT: 8081SPARK_PUBLIC_DNS: localhostlinks:- masterexpose:- 7012- 7013- 7014- 7015- 8881volumes:- ./conf/worker4:/conf- ./data/worker4:/tmp/dataworker5:image: gettyimages/spark:2.3.0-hadoop-2.8container_name: worker5command: bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077hostname: worker5environment:SPARK_CONF_DIR: /confSPARK_WORKER_CORES: 2SPARK_WORKER_MEMORY: 2gSPARK_WORKER_PORT: 8881SPARK_WORKER_WEBUI_PORT: 8081SPARK_PUBLIC_DNS: localhostlinks:- masterexpose:- 7012- 7013- 7014- 7015- 8881volumes:- ./conf/worker5:/conf- ./data/worker5:/tmp/dataworker6:image: gettyimages/spark:2.3.0-hadoop-2.8container_name: worker6command: bin/spark-class org.apache.spark.deploy.worker.Worker spark://master:7077hostname: worker6environment:SPARK_CONF_DIR: /confSPARK_WORKER_CORES: 2SPARK_WORKER_MEMORY: 2gSPARK_WORKER_PORT: 8881SPARK_WORKER_WEBUI_PORT: 8081SPARK_PUBLIC_DNS: localhostlinks:- masterexpose:- 7012- 7013- 7014- 7015- 8881volumes:- ./conf/worker6:/conf- ./data/worker6:/tmp/data
  1. 如果您打算基于传统方式搭建,请参考《部署spark2.2集群(standalone模式)》;

sprak环境的基本情况如下所示:
在这里插入图片描述

以下是本次实战涉及的版本号:

  1. 操作系统:CentOS7
  2. hadoop:2.8
  3. spark:2.3
  4. docker:17.03.2-ce
  5. docker-compose:1.23.2

维基百科网站统计数据简介

先回顾一下维基百科网站统计数据的内容和格式,一行数据的内容如下所示:

aa.b User_talk:Sevela.p 1 5786

这一行由空格字符分割成了四个字段:

内容意义
aa.b项目名称,".b"表示wikibooks
User_talk:Sevela.p网页的三级目录
1一小时内的访问次数
5786一小时内被请求的字节总数

上述内容可以还原为一个网址,如下图所示,对应的URL为:https://aa.wikibooks.org/wiki/User_talk:Sevela.p
在这里插入图片描述

实战功能简介

本次实战开发的spark应用的功能,是对网站统计数据进行排名,找出访问量最高的前100地址,在控制台打印出来并保存到hdsf;

源码下载

接下来详细讲述应用的编码过程,如果您不想自己写代码,也可以在GitHub下载完整的应用源码,地址和链接信息如下表所示:

名称链接备注
项目主页https://github.com/zq2599/blog_demos该项目在GitHub上的主页
git仓库地址(https)https://github.com/zq2599/blog_demos.git该项目源码的仓库地址,https协议
git仓库地址(ssh)git@github.com:zq2599/blog_demos.git该项目源码的仓库地址,ssh协议

这个git项目中有多个文件夹,本章源码在sparkdemo这个文件夹下,如下图红框所示:
在这里插入图片描述

详细开发

  1. 基于maven创建工程,pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.bolingcavalry</groupId><artifactId>sparkdemo</artifactId><version>1.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.apache.spark</groupId><artifactId>spark-core_2.11</artifactId><version>2.3.2</version></dependency></dependencies><build><sourceDirectory>src/main/java</sourceDirectory><testSourceDirectory>src/test/java</testSourceDirectory><plugins><plugin><artifactId>maven-assembly-plugin</artifactId><configuration><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><archive><manifest><mainClass></mainClass></manifest></archive></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin><plugin><groupId>org.codehaus.mojo</groupId><artifactId>exec-maven-plugin</artifactId><version>1.2.1</version><executions><execution><goals><goal>exec</goal></goals></execution></executions><configuration><executable>java</executable><includeProjectDependencies>false</includeProjectDependencies><includePluginDependencies>false</includePluginDependencies><classpathScope>compile</classpathScope><mainClass>com.bolingcavalry.sparkdemo.app.WikiRank</mainClass></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></build>
</project>
  1. 创建一个数据结构类PageInfo,在运行过程中会用到,里面记录了业务所需的字段:
package com.bolingcavalry.sparkdemo.bean;import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;/*** @Description: 数据结构类* @author: willzhao E-mail: zq2599@gmail.com* @date: 2019/2/10 15:33*/
public class PageInfo implements Serializable {/*** 还原的url地址*/private String url;/*** urldecode之后的三级域名*/private String name;/*** 该三级域名的请求次数*/private int requestTimes;/*** 该地址被请求的字节总数*/private long requestLength;/*** 对应的原始字段*/private List<String> raws = new LinkedList<>();public String getName() {return name;}public void setName(String name) {this.name = name;}public int getRequestTimes() {return requestTimes;}public void setRequestTimes(int requestTimes) {this.requestTimes = requestTimes;}public long getRequestLength() {return requestLength;}public void setRequestLength(long requestLength) {this.requestLength = requestLength;}public List<String> getRaws() {return raws;}public void setRaws(List<String> raws) {this.raws = raws;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}
}
  1. 对于前面提到的例子,“aa.b User_talk:Sevela.p 1 5786"对应的网址是"https://aa.wikibooks.org/wiki/User_talk:Sevela.p”,这个转换逻辑被做成了一个静态方法,这样就能把每一行记录对应的地址还原出来了,如下所示:
package com.bolingcavalry.sparkdemo.util;import org.apache.commons.lang3.StringUtils;/*** @Description: 常用的静态工具放置在此* @author: willzhao E-mail: zq2599@gmail.com* @date: 2019/2/16 9:01*/
public class Tools {/*** 域名的格式化模板*/private static final String URL_TEMPALTE = "https://%s/wiki/%s";/*** 根据项目名称和三级域名还原完整url,* 还原逻辑来自:https://wikitech.wikimedia.org/wiki/Analytics/Archive/Data/Pagecounts-raw* @param project* @param thirdLvPath* @return*/public static String getUrl(String project, String thirdLvPath){//如果入参不合法,就返回固定格式的错误提示if(StringUtils.isBlank(project) || StringUtils.isBlank(thirdLvPath)){return "1. invalid param (" + project + ")(" + thirdLvPath + ")";}//检查project中是否有"."int dotOffset = project.indexOf('.');//如果没有".",就用project+".wikipedia.org"作为一级域名if(dotOffset<0){return String.format(URL_TEMPALTE,project + ".wikipedia.org",thirdLvPath);}//如果有".",就用"."之后的字符串按照不同的逻辑转换String code = project.substring(dotOffset);//".mw"属于移动端网页,统计的逻辑略微复杂,详情参考网页链接,这里不作处理直接返回固定信息if(".mw".equals(code)){return "mw page (" + project + ")(" + thirdLvPath + ")";}String firstLvPath = null;//就用"."之后的字符串按照不同的逻辑转换switch(code){case ".b":firstLvPath = ".wikibooks.org";break;case ".d":firstLvPath = ".wiktionary.org";break;case ".f":firstLvPath = ".wikimediafoundation.org";break;case ".m":firstLvPath = ".wikimedia.org";break;case ".n":firstLvPath = ".wikinews.org";break;case ".q":firstLvPath = ".wikiquote.org";break;case ".s":firstLvPath = ".wikisource.org";break;case ".v":firstLvPath = ".wikiversity.org";break;case ".voy":firstLvPath = ".wikivoyage.org";break;case ".w":firstLvPath = ".mediawiki.org";break;case ".wd":firstLvPath = ".wikidata.org";break;}if(null==firstLvPath){return "2. invalid param (" + project + ")(" + thirdLvPath + ")";}//还原地址return String.format(URL_TEMPALTE,project.substring(0, dotOffset) + firstLvPath,thirdLvPath);}public static void main(String[] args){String str = "abc.123456";System.out.println(str.substring(str.indexOf('.')));}
}
  1. 接下来是spark应用的源码,主要是创建PageInfo对象,以及map、reduce、排序等逻辑,代码中已有注释说明,就不再赘述:
package com.bolingcavalry.sparkdemo.app;import com.bolingcavalry.sparkdemo.bean.PageInfo;
import com.bolingcavalry.sparkdemo.util.Tools;
import org.apache.commons.lang3.StringUtils;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.Function2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import scala.Tuple2;import java.net.URLDecoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;/*** @Description: 根据wiki的统计来查找最高访问量的文章* @author: willzhao E-mail: zq2599@gmail.com* @date: 2019/2/8 17:21*/
public class WikiRank {private static final Logger logger = LoggerFactory.getLogger(WikiRank.class);private static final int TOP = 100;public static void main(String[] args) {if(null==args|| args.length<2|| StringUtils.isEmpty(args[0])|| StringUtils.isEmpty(args[1])) {logger.error("invalid params!");}String hdfsHost = args[0];String hdfsPort = args[1];SparkConf sparkConf = new SparkConf().setAppName("Spark WordCount Application (java)");JavaSparkContext javaSparkContext = new JavaSparkContext(sparkConf);String hdfsBasePath = "hdfs://" + hdfsHost + ":" + hdfsPort;//文本文件的hdfs路径String inputPath = hdfsBasePath + "/input/*";//输出结果文件的hdfs路径String outputPath = hdfsBasePath + "/output/"+ new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());logger.info("input path : {}", inputPath);logger.info("output path : {}", outputPath);logger.info("import text");//导入文件JavaRDD<String> textFile = javaSparkContext.textFile(inputPath);logger.info("do map operation");JavaPairRDD<String, PageInfo> counts = textFile//过滤掉无效的数据.filter((Function<String, Boolean>) v1 -> {if(StringUtils.isBlank(v1)){return false;}//分割为数组String[] array = v1.split(" ");/*** 以下情况都要过滤掉* 1. 名称无效(array[1])* 2. 请求次数无效(array[2)* 3. 请求总字节数无效(array[3)*/if(null==array|| array.length<4|| StringUtils.isBlank(array[1])|| !StringUtils.isNumeric(array[2])|| !StringUtils.isNumeric(array[3])){logger.error("find invalid data [{}]", v1);return false;}return true;})//将每一行转成一个PageInfo对象.map((Function<String, PageInfo>) v1 -> {String[] array = v1.split(" ");PageInfo pageInfo = new PageInfo();try {pageInfo.setName(URLDecoder.decode(array[1], "UTF-8"));}catch (Exception e){//有的字符串没有做过urlencode,此时做urldecode可能抛出异常(例如abc%),此时用原来的内容作为name即可pageInfo.setName(array[1]);}pageInfo.setUrl(Tools.getUrl(array[0], array[1]));pageInfo.setRequestTimes(Integer.valueOf(array[2]));pageInfo.setRequestLength(Long.valueOf(array[3]));pageInfo.getRaws().add(v1);return pageInfo;})//转成键值对,键是url,值是PageInfo对象.mapToPair(pageInfo -> new Tuple2<>(pageInfo.getUrl(), pageInfo))//按照url做reduce,将请求次数累加.reduceByKey((Function2<PageInfo, PageInfo, PageInfo>) (v1, v2) -> {v2.setRequestTimes(v2.getRequestTimes() + v1.getRequestTimes());v2.getRaws().addAll(v1.getRaws());return v2;});logger.info("do convert");//先将key和value倒过来,再按照key排序JavaPairRDD<Integer, PageInfo> sorts = counts//key和value颠倒,生成新的map.mapToPair(tuple2 -> new Tuple2<>(tuple2._2().getRequestTimes(), tuple2._2()))//按照key倒排序.sortByKey(false);logger.info("take top " + TOP);//取前10个List<Tuple2<Integer, PageInfo>> top = sorts.take(TOP);StringBuilder sbud = new StringBuilder("top "+ top + " word :\n");//打印出来for(Tuple2<Integer, PageInfo> tuple2 : top){sbud.append(tuple2._2().getName()).append("\t").append(tuple2._1()).append("\n");}logger.info(sbud.toString());logger.info("merge and save as file");//分区合并成一个,再导出为一个txt保存在hdfsjavaSparkContext.parallelize(top).coalesce(1).map(tuple2 -> new Tuple2<>(tuple2._2().getRequestTimes(), tuple2._2().getName() + " ### " + tuple2._2().getUrl() +" ### " + tuple2._2().getRaws().toString())).saveAsTextFile(outputPath);logger.info("close context");//关闭contextjavaSparkContext.close();}
}
  1. 编码完成后,在pom.xml所在目录下编译构建jar包:
mvn clean package -Dmaven.test.skip=true
  1. 编译成功后,target目录下的sparkdemo-1.0-SNAPSHOT.jar就是应用jar包;
  2. 将sparkdemo-1.0-SNAPSHOT.jar提交到spark服务器上,我这里用的是docker环境,通过文件夹映射将容器的目录和宿主机目录对应起来,只要将文件放入宿主机的jars目录即可,您需要按照自己的实际情况上传;

提交任务

  1. 当前电脑上,维基百科网站的统计数据文件保存在目录/input_files/input
  2. 将维基百科网站的统计数据文件提交到hdfs,我这边用的是docker环境,提交命令如下:
docker exec namenode hdfs dfs -put /input_files/input /
  1. 提交成功后,在hdfs的web页面可见/input目录下的数据,如下:
    在这里插入图片描述
  2. 将jar文件上传到spark服务再提交任务,我用的是docker环境,命令如下:
docker exec -it master spark-submit \
--class com.bolingcavalry.sparkdemo.app.WikiRank \
--executor-memory 1g \
--total-executor-cores 12 \
/root/jars/sparkdemo-1.0-SNAPSHOT.jar \
namenode \
8020

上述命令调动了12个executor,每个内存为1G,请您按照自己环境的实际情况来配置;
5. 由于本次要处理的文件较多(24个128兆的文件),因此耗时较长,需要耐心等待,您也可以减少上传文件数量来缩减处理时间,以下是web页面显示的处理情况:
在这里插入图片描述
6. 处理完成后,在控制台会打印简单的排名信息:

en	111840450
Main_Page	61148163
ja	20336203
es	18133852
Заглавная_страница	16997475
de	12537288
ru	10127971
fr	9296777
it	9011481
pt	5904807
id	3472100
tr	3089611
pl	3051718
ar	3023412
nl	2372696
zh	1987233
sv	1845525
fa	1687804
ko	1511408
commons	1138613
fi	1123291
th	1012375
vi	1007987
he	822433
Wikipedia:Hauptseite	767106
cs	750085
hu	687040
Wikipédia:Accueil_principal	597885
da	512714
no	507885
Special:Search	493995
ro	488945
uk	419609
Special:NewItem	414436
hi	399883
Antoninus_Pius	345542
el	342715
Hoofdpagina	287517
tl	274145
bg	252691
Wikipedia:Portada	250932
Liste_des_automobiles_Ferrari	237985
hr	228896
メインページ	227591
Начална_страница	220605
Okto	211002
Proyecto_40	207534
  1. 也可以去hdfs查看更详细的输出内容,先查找到输出文件所在目录:
root@willzhao-deepin:~# docker exec namenode hdfs dfs -ls /output/
Found 3 items
drwxr-xr-x   - root supergroup          0 2019-02-16 00:53 /output/20190216005136
drwxr-xr-x   - root supergroup          0 2019-02-16 01:50 /output/20190216014759
drwxr-xr-x   - root supergroup          0 2019-02-16 02:41 /output/20190216021144
root@willzhao-deepin:~# docker exec namenode hdfs dfs -ls /output/20190216021144
Found 2 items
-rw-r--r--   3 root supergroup          0 2019-02-16 02:41 /output/20190216021144/_SUCCESS
-rw-r--r--   3 root supergroup     105181 2019-02-16 02:41 /output/20190216021144/part-00000

可见输出文件为/output/20190216021144/part-00000
8. 用cat命令查看输出文件内容,以下是部分内容:

(63364,2016_Summer_Olympics ### https://en.wikipedia.org/wiki/2016_Summer_Olympics ### [en 2016_Summer_Olympics 3396 274589952, en 2016_Summer_Olympics 3015 252640325, en 2016_Summer_Olympics 3136 260875102, en 2016_Summer_Olympics 3094 257683527, en 2016_Summer_Olympics 2302 189633601, en 2016_Summer_Olympics 2532 211137547, en 2016_Summer_Olympics 2073 174153850, en 2016_Summer_Olympics 2425 201808231, en 2016_Summer_Olympics 2869 244961273, en 2016_Summer_Olympics 2647 227408637, en 2016_Summer_Olympics 3173 276779678, en 2016_Summer_Olympics 3242 261206575, en 2016_Summer_Olympics 1871 168316209, en 2016_Summer_Olympics 2234 204588727, en 2016_Summer_Olympics 2857 239335148, en 2016_Summer_Olympics 2345 197360752, en 2016_Summer_Olympics 2949 248777317, en 2016_Summer_Olympics 2040 171690687, en 2016_Summer_Olympics 4006 332402716, en 2016_Summer_Olympics 3137 274672915, en 2016_Summer_Olympics 1895 156985346, en 2016_Summer_Olympics 2089 180840058, en 2016_Summer_Olympics 2062 177089806, en 2016_Summer_Olympics 1975 169774986])
(62904,index.html ### https://de.wikipedia.org/wiki/index.html ### [de index.html 1325 16171364, de index.html 2680 30968912, de index.html 2458 27982474, de index.html 2703 30869488, de index.html 2829 32784835, de index.html 2674 30702050, de index.html 2346 26947956, de index.html 2573 29374195, de index.html 2610 30237824, de index.html 2689 32111034, de index.html 2748 31632152, de index.html 2659 30566670, de index.html 2657 30411903, de index.html 2765 32298328, de index.html 2982 34626678, de index.html 2953 33925805, de index.html 2543 29180781, de index.html 2722 31230645, de index.html 2810 32517269, de index.html 2307 26760806, de index.html 2847 33270784, de index.html 2776 32310052, de index.html 2544 29206518, de index.html 2704 31382398])

上述第一个网站全天的访问量为63364,如下图,地址是:https://en.wikipedia.org/wiki/2016_Summer_Olympic
在这里插入图片描述

至此,对维基百科网站统计数据的处理实战就完成了,希望此实战能够给您的大数据分析提供一些参考;

欢迎关注我的公众号:程序员欣宸

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_736892.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站建设中标签的使用:Tag优化标准文档

Tag 中文译作标签、书签。在很多网站中&#xff0c;由于导航无法承载更多的信息分类&#xff0c;而内容量又过大的时候&#xff0c;使用TAG来更加有效地组织网站结构和内容。 一、Tag来源 是代表某些内容&#xff08;文字、图片、音频、视频&#xff09;的关键词或词组&#xf…

bluePen – 使用在线 CSS 编辑器美化你的网站

BluePen 是一款非常强大的样式编辑工具&#xff0c;甚至可以轻松地安装在一个动态的网站中。一旦你已经安装了它&#xff0c;你就可以在任何时间&#xff0c;任何地方修改样式表&#xff0c;一切修改将实时更新到您的浏览器&#xff08;但不是线上网站&#xff09;&#xff0c;…

5个基于Linux命令行的文件下载和网站浏览工具

命令行是GNU/Linux中最神奇迷人的部分&#xff0c;它是非常强大的工具;命令行本身功能多样&#xff0c;多种内建或者第三方的命令行应用使得Linux变得更加健壮和强大。Linux Shell支持多种不同类型的网络应用&#xff0c;无论是BT下载软件&#xff0c;专用下载器或者互联网冲浪…

采用建站cms制作企业网站的好处

随着网络的发展和普及&#xff0c;现在各行各业开展业务都离不开网络推广&#xff0c;而网络营销推广的标配就是企业必须有一个企业网站&#xff0c;目前做企业网站制作主要有两个方法&#xff0c;一种找网络公司开发&#xff0c;一种利用cms来制作网站&#xff0c;那么建站cms…

中国.net域名网站的“前世今生”,那些年的光辉

1987年9月的一天&#xff0c;中国的第一封电子邮件成功发出&#xff0c;邮件的内容大致是“跨越长城&#xff0c;走向世界”&#xff0c;在当时&#xff0c;没有人会想到十年后中国的互联网开始萌芽&#xff0c;并发展成今天的繁荣。1994年&#xff0c;“巴黎统筹委员会”的解散…

大型网站技术架构(1)

为什么80%的码农都做不了架构师&#xff1f;>>> 网站都是从小网站一步一步发展为大型网站的&#xff0c;而这之中的挑战主要来自于庞大的用户、安全环境恶劣、高并发的访问和海量的数据&#xff0c;任何简单的业务处理&#xff0c;一旦需要处理数以 P 计的数据和面…

超详细新手建站指南

概述 对于一个建站新手来讲&#xff0c;最重要的莫过于2件事 时间效率性价比换句话讲&#xff0c;对于非专业选手&#xff0c;在整个建站过程&#xff0c;如何省时省力&#xff0c;用相对简单的方式&#xff0c;花更少的钱建好网站是关键。 基于上述&#xff0c;给大家带来一版…

大型网站压力测试及优化方案

木桶理论应用在系统优化中 木桶理论又称短板理论&#xff0c;其核心思想是一只木桶盛水多少&#xff0c;并不取决于最高的木板&#xff0c;而取决于最短的那块木板。木桶原理应用在系统分析中&#xff0c;即系统的最终性能取决于系统中性能表现最差的组件&#xff0c;为了提升系…

从入侵到变现——“黑洞”下的黑帽SEO分析

概述 由于互联网入口流量主要被搜索引擎占据&#xff0c;网站在搜索引擎中的排名直接影响到市场营销效果&#xff0c;因此SEO服务应运而生。SEO(Search Engine Optimization)全称为搜索引擎优化&#xff0c;是指利用搜索引擎的规则提高网站在相关搜索引擎内的自然排名。SEO服务…

Linux学习网站

2019独角兽企业重金招聘Python工程师标准>>> 分享一个Linux学习网站 http://www.linuxprobe.com/ 转载于:https://my.oschina.net/bob1900/blog/847041

安全篇 Web网站类 CC防护

大家好&#xff0c;云吞铺子又和大家见面了&#xff1b;我叫枫凡&#xff0c;是技术服务中心的工程师&#xff1b;借这个机会主要和大家分享一下&#xff0c;Web网站应用在受到CC攻击的情况分析以及防护的一些心得。 一键防护 当网站受到CC攻击时&#xff0c;第一优先级为想办法…

服务器搭建网站完整教程

服务器最大的用途&#xff0c;就是可以搭建网站&#xff0c;许多人都认为搭建网站是一件很难的事情&#xff0c;因为包含许多的比较专业东西&#xff0c;比如服务器、编程之类的&#xff0c;确实&#xff0c;在几年前是这样的&#xff0c;普通人想要自己做一个网站太难了 但是随…

《Axure RP7网站和APP原型制作从入门到精通(60小时案例版)》一1.4 交互基础...

本节书摘来自异步社区《Axure RP7网站和APP原型制作从入门到精通&#xff08;60小时案例版&#xff09;》一书中的第1章&#xff0c;第1.4节&#xff0c;作者 金乌&#xff0c;更多章节内容可以访问云栖社区“异步社区”公众号查看 1.4 交互基础 该部分内容可参考视频教程基础…

2017-11-28 在线编程网站对中文代码的支持

参考哪些比较好的在线编程网站&#xff1f;, 测试各个网站对中文命名的代码的支持, 包括调试信息等(见向LeetCode报告编译信息中Unicode显示问题). 有趣的是, 在范围有限的评测中, 国产的在线编程网站似乎对中文命名的代码普遍支持更好. 不知开发者是否对这个功能有特别的关注,…

文章被爬取到几十个网站?居然还出现了伪简书站点

不要笑&#xff0c;也许你的文章也已经被爬取... 微信截图_20190527162755.png上面的图片&#xff0c;第一眼&#xff0c;你肯定认为是简书站点吧&#xff1f;其实你错了&#xff0c;这只是一个伪站点而已... 今天一看&#xff0c;我的文章居然被几十个网站爬取&#xff0c;被爬…

09、搭建门户网站子模块、运营商广告列表的实现、广告CRUD、广告状态修改、门户网站轮播图广告、实现广告排序,状态等条件的设定、Linux安装redis、广告列表保存到redis、广告数据同步问题

搭建门户网站子模块 在父工程下新建门户子模块protal—web 注意springmvc.xml文件中需要对dubbo进行设置导入静态原型&#xff0c;controller实现类等文件。 搭建广告service模块 1、在父工程下引入两个子模块&#xff0c;分别是广告content的service接口&#xff0c;一个是…

实现基于LNMP的电子商务网站的搭建

一 环境准备&#xff1a;centos系统 yum源&#xff08;安装mysql&#xff0c;nginx,和php-fpm)二&#xff1a;安装步骤&#xff1a;用yum的方式安装mariadb,mariadb-server,php-mysql,php-fpm,nginx下载需要搭建网站的源码&#xff0c;我搭建的是基于小米网站的搭建&#xff0…

如何从word中复制内容到网站后台编辑器中

很多时候我们用一些管理系统的时候&#xff0c;发布新闻、公告等文字类信息时&#xff0c;希望能很快的将word里面的内容直接粘贴到富文本编辑器里面&#xff0c;然后发布出来。减少排版复杂的工作量。 下面是借用百度doc 来快速实现这个word 粘贴到 富文本编辑器里面 方法一&…

16个时髦的扁平化设计的 HTML5 CSS3 网站模板

创建网站最好办法之一是使用现成的网站模板或使用开源 CMS 应用程序。所以&#xff0c;今天这篇文章给大家带来的是16款基于 HTML5 & CSS3 的精美的扁平风格网站模板&#xff0c;大家可以借助这些优秀的网站模板创建自己的优秀网站。这些网站模板虽然是收费&#xff0c;但是…

多域名同一个IP在IIS环境下架设多个网站 主机头

由于各种原因&#xff0c;我们有时候需要在一个IP地址上建立多个web站点&#xff0c;在IIS5中&#xff0c;我们可能通过简单的设置达到这个目标。在IIS中&#xff0c;每个 Web 站点都具有唯一的、由三个部分组成的标识&#xff0c;用来接收和响应请求:(1) IP地址(2) 端口号(3) …